From 8f66bf11a1b68ec42af55782dfb3f9370f76dfbe Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 08:14:21 +0100 Subject: [PATCH 01/13] Add context calls for EVM block creation --- src/rust/crates/ain-evm-ffi/src/lib.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index ba5b3b2e550..6eed0828d79 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -11,6 +11,10 @@ mod ffi { fn evm_sub_balance(address: &str, amount: i64) -> Result<()>; fn evm_validate_raw_tx(tx: &str) -> Result; + fn evm_get_context() -> u64; + fn evm_execute_tx(context: u64) -> Result; + fn evm_finalise(context: u64) -> Result>; + fn init_runtime(); fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; fn stop_runtime(); @@ -42,3 +46,18 @@ pub fn evm_validate_raw_tx(tx: &str) -> Result> { Err(_) => Ok(false), } } + +pub fn evm_get_context() -> u64 { + // TODO Generate unique contexts. + 1 +} + +fn evm_execute_tx(context: u64) -> Result> { + Ok(true) +} + +fn evm_finalise(context: u64) -> Result, Box> { + let block_and_failed_txs: Vec = Vec::new(); + Ok(block_and_failed_txs) +} + From a03f55c8d9098b9185dba3f965800070b09456bb Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 08:20:55 +0100 Subject: [PATCH 02/13] Add update_state bool --- src/rust/crates/ain-evm-ffi/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 6eed0828d79..3fb963f50a7 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -13,7 +13,7 @@ mod ffi { fn evm_get_context() -> u64; fn evm_execute_tx(context: u64) -> Result; - fn evm_finalise(context: u64) -> Result>; + fn evm_finalise(context: u64, update_state: bool) -> Result>; fn init_runtime(); fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; @@ -56,7 +56,7 @@ fn evm_execute_tx(context: u64) -> Result> { Ok(true) } -fn evm_finalise(context: u64) -> Result, Box> { +fn evm_finalise(context: u64, update_state: bool) -> Result, Box> { let block_and_failed_txs: Vec = Vec::new(); Ok(block_and_failed_txs) } From e996d70591d80cca4c65a87d35723b88879a404f Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 09:24:59 +0100 Subject: [PATCH 03/13] Add context discard --- src/rust/crates/ain-evm-ffi/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 3fb963f50a7..3d7ab3ef742 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -12,7 +12,8 @@ mod ffi { fn evm_validate_raw_tx(tx: &str) -> Result; fn evm_get_context() -> u64; - fn evm_execute_tx(context: u64) -> Result; + fn evm_discard_context(context: u64); + fn evm_queue_tx(context: u64) -> Result; fn evm_finalise(context: u64, update_state: bool) -> Result>; fn init_runtime(); @@ -52,7 +53,11 @@ pub fn evm_get_context() -> u64 { 1 } -fn evm_execute_tx(context: u64) -> Result> { +fn evm_discard_context(context: u64) { + // TODO discard +} + +fn evm_queue_tx(context: u64) -> Result> { Ok(true) } From 768ba25d5f7f7857c7425d0d9a85a9573f6e428f Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 09:39:01 +0100 Subject: [PATCH 04/13] Return vector of vectors --- src/rust/crates/ain-evm-ffi/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 3d7ab3ef742..4d83d5abb1d 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -14,7 +14,7 @@ mod ffi { fn evm_get_context() -> u64; fn evm_discard_context(context: u64); fn evm_queue_tx(context: u64) -> Result; - fn evm_finalise(context: u64, update_state: bool) -> Result>; + fn evm_finalise(context: u64, update_state: bool) -> Result>>; fn init_runtime(); fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; @@ -61,8 +61,8 @@ fn evm_queue_tx(context: u64) -> Result> { Ok(true) } -fn evm_finalise(context: u64, update_state: bool) -> Result, Box> { - let block_and_failed_txs: Vec = Vec::new(); +fn evm_finalise(context: u64, update_state: bool) -> Result>, Box> { + let block_and_failed_txs: Vec> = Vec::new(); Ok(block_and_failed_txs) } From a5eccd6164262b14289feea686cd44a90ca3a5d0 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 09:51:00 +0100 Subject: [PATCH 05/13] Vector of vectors unsupported --- src/rust/crates/ain-evm-ffi/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 4d83d5abb1d..3d7ab3ef742 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -14,7 +14,7 @@ mod ffi { fn evm_get_context() -> u64; fn evm_discard_context(context: u64); fn evm_queue_tx(context: u64) -> Result; - fn evm_finalise(context: u64, update_state: bool) -> Result>>; + fn evm_finalise(context: u64, update_state: bool) -> Result>; fn init_runtime(); fn start_servers(json_addr: &str, grpc_addr: &str) -> Result<()>; @@ -61,8 +61,8 @@ fn evm_queue_tx(context: u64) -> Result> { Ok(true) } -fn evm_finalise(context: u64, update_state: bool) -> Result>, Box> { - let block_and_failed_txs: Vec> = Vec::new(); +fn evm_finalise(context: u64, update_state: bool) -> Result, Box> { + let block_and_failed_txs: Vec = Vec::new(); Ok(block_and_failed_txs) } From bd217608cd87a5b351aa2313c0d7437079c4cffe Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 10:26:13 +0100 Subject: [PATCH 06/13] Add EVM context to ConnectBlock --- src/masternodes/mn_checks.cpp | 19 +++++++++++++------ src/masternodes/mn_checks.h | 6 ++++-- src/validation.cpp | 11 ++++++++--- src/validation.h | 2 +- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 936dca7c04d..95f7066484b 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -771,6 +771,7 @@ Res CCustomTxVisitor::IsOnChainGovernanceEnabled() const { class CCustomTxApplyVisitor : public CCustomTxVisitor { uint64_t time; uint32_t txn; + uint64_t evmContext; public: CCustomTxApplyVisitor(const CTransaction &tx, @@ -779,11 +780,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CCustomCSView &mnview, const Consensus::Params &consensus, uint64_t time, - uint32_t txn) + uint32_t txn, + const uint64_t evmContext) : CCustomTxVisitor(tx, height, coins, mnview, consensus), time(time), - txn(txn) {} + txn(txn), + evmContext(evmContext) {} Res operator()(const CCreateMasterNodeMessage &obj) const { Require(CheckMasternodeCreationTx()); @@ -3862,7 +3865,9 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { return Res::Err("evm tx failed to validate"); } - // TODO Execute TX + if (!evm_queue_tx(evmContext)) { + return Res::Err("evm tx failed to queue"); + } return Res::Ok(); } @@ -3945,12 +3950,13 @@ Res CustomTxVisit(CCustomCSView &mnview, const Consensus::Params &consensus, const CCustomTxMessage &txMessage, uint64_t time, - uint32_t txn) { + uint32_t txn, + const uint64_t evmContext) { if (IsDisabledTx(height, tx, consensus)) { return Res::ErrCode(CustomTxErrCodes::Fatal, "Disabled custom transaction"); } try { - return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn), txMessage); + return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, evmContext), txMessage); } catch (const std::bad_variant_access &e) { return Res::Err(e.what()); } catch (...) { @@ -4035,7 +4041,8 @@ Res ApplyCustomTx(CCustomCSView &mnview, uint32_t height, uint64_t time, uint256 *canSpend, - uint32_t txn) { + uint32_t txn, + const uint64_t evmContext) { auto res = Res::Ok(); if (tx.IsCoinBase() && height > 0) { // genesis contains custom coinbase txs return res; diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index be1d6446154..2d93bfecfe3 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -466,7 +466,8 @@ Res ApplyCustomTx(CCustomCSView &mnview, uint32_t height, uint64_t time = 0, uint256 *canSpend = nullptr, - uint32_t txn = 0); + uint32_t txn = 0, + const int64_t evmContext = 0); Res CustomTxVisit(CCustomCSView &mnview, const CCoinsViewCache &coins, const CTransaction &tx, @@ -474,7 +475,8 @@ Res CustomTxVisit(CCustomCSView &mnview, const Consensus::Params &consensus, const CCustomTxMessage &txMessage, uint64_t time, - uint32_t txn = 0); + uint32_t txn = 0, + const uint64_t evmContext = 0); ResVal ApplyAnchorRewardTx(CCustomCSView &mnview, const CTransaction &tx, int height, diff --git a/src/validation.cpp b/src/validation.cpp index 2f72c313cda..80001c5f680 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -2289,7 +2290,7 @@ static void LogApplyCustomTx(const CTransaction &tx, const int64_t start) { * Validity checks that depend on the UTXO set are also done; ConnectBlock () * can fail if those validity checks fail (among other reasons). */ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, - CCoinsViewCache& view, CCustomCSView& mnview, const CChainParams& chainparams, bool & rewardedAnchors, bool fJustCheck) + CCoinsViewCache& view, CCustomCSView& mnview, const CChainParams& chainparams, bool & rewardedAnchors, bool fJustCheck, const int64_t evmContext) { AssertLockHeld(cs_main); assert(pindex); @@ -2633,7 +2634,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } const auto applyCustomTxTime = GetTimeMicros(); - const auto res = ApplyCustomTx(accountsView, view, tx, chainparams.GetConsensus(), pindex->nHeight, pindex->GetBlockTime(), nullptr, i); + const auto res = ApplyCustomTx(accountsView, view, tx, chainparams.GetConsensus(), pindex->nHeight, pindex->GetBlockTime(), nullptr, i, evmContext); LogApplyCustomTx(tx, applyCustomTxTime); if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) { if (pindex->nHeight >= chainparams.GetConsensus().EunosHeight) { @@ -2833,6 +2834,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } mnview.SetLastHeight(pindex->nHeight); + evm_finalise(evmContext, true); + auto &checkpoints = chainparams.Checkpoints().mapCheckpoints; auto it = checkpoints.lower_bound(pindex->nHeight); if (it != checkpoints.begin()) { @@ -3275,9 +3278,11 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp CCoinsViewCache view(&CoinsTip()); CCustomCSView mnview(*pcustomcsview, paccountHistoryDB.get(), pburnHistoryDB.get(), pvaultHistoryDB.get()); bool rewardedAnchors{}; - bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors); + const auto evmContext = evm_get_context(); + bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, false, evmContext); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { + evm_discard_context(evmContext); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } diff --git a/src/validation.h b/src/validation.h index 750ea2f3fe6..2cefd2bd2d1 100644 --- a/src/validation.h +++ b/src/validation.h @@ -734,7 +734,7 @@ class CChainState { // Block (dis)connection on a given view: DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view, CCustomCSView& cache, std::vector & disconnectedAnchorConfirms); bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, - CCoinsViewCache& view, CCustomCSView& cache, const CChainParams& chainparams, bool & rewardedAnchors, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + CCoinsViewCache& view, CCustomCSView& cache, const CChainParams& chainparams, bool & rewardedAnchors, bool fJustCheck = false, const int64_t evmContext = 0) EXCLUSIVE_LOCKS_REQUIRED(cs_main); // Apply the effects of a block disconnection on the UTXO set. bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs); From 2d6e89479190daeeb8c9e318cc3fe838d67350e4 Mon Sep 17 00:00:00 2001 From: jouzo Date: Tue, 4 Apr 2023 09:37:53 +0100 Subject: [PATCH 07/13] Add TransactionQueueMap and rough finalize_block --- src/defid.cpp | 2 +- src/masternodes/mn_checks.cpp | 2 +- src/masternodes/rpc_evm.cpp | 6 +- src/rpc/client.cpp | 4 + src/rust/Cargo.lock | 2 + src/rust/crates/ain-evm-ffi/src/lib.rs | 26 +- src/rust/crates/ain-evm-state/Cargo.toml | 1 + src/rust/crates/ain-evm-state/src/handler.rs | 277 +++++++++++++----- src/rust/crates/ain-evm-state/src/lib.rs | 7 +- src/rust/crates/ain-evm-state/src/tx_queue.rs | 92 ++++++ src/rust/crates/ain-evm/Cargo.toml | 1 + src/rust/crates/ain-evm/src/block.rs | 69 +++++ src/rust/crates/ain-evm/src/executor.rs | 92 ++++++ src/rust/crates/ain-evm/src/lib.rs | 3 + src/rust/crates/ain-evm/src/traits.rs | 22 ++ src/rust/crates/ain-evm/src/transaction.rs | 29 +- src/rust/crates/ain-utils/src/lib.rs | 7 +- 17 files changed, 536 insertions(+), 106 deletions(-) create mode 100644 src/rust/crates/ain-evm-state/src/tx_queue.rs create mode 100644 src/rust/crates/ain-evm/src/block.rs create mode 100644 src/rust/crates/ain-evm/src/executor.rs create mode 100644 src/rust/crates/ain-evm/src/traits.rs diff --git a/src/defid.cpp b/src/defid.cpp index e7ee7a87a59..a4ef266ed98 100644 --- a/src/defid.cpp +++ b/src/defid.cpp @@ -68,7 +68,7 @@ static bool AppInit(int argc, char* argv[]) util::ThreadRename("init"); init_runtime(); // Test linking to dummy address - evm_add_balance("0xf3088943Fa15Ff33D5C3Af9845dc65073Ae2bAc8", 100); + evm_add_balance("0xf3088943Fa15Ff33D5C3Af9845dc65073Ae2bAc8", ArithToUint256(100).ToArrayReversed()); // // Parameters diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 95f7066484b..f682f0a3151 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3865,7 +3865,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { return Res::Err("evm tx failed to validate"); } - if (!evm_queue_tx(evmContext)) { + if (!evm_queue_tx(evmContext, HexStr(obj.evmTx))) { return Res::Err("evm tx failed to queue"); } diff --git a/src/masternodes/rpc_evm.cpp b/src/masternodes/rpc_evm.cpp index 31acd1568c3..1bdd020873a 100644 --- a/src/masternodes/rpc_evm.cpp +++ b/src/masternodes/rpc_evm.cpp @@ -57,7 +57,7 @@ UniValue evmtx(const JSONRPCRequest& request) { const uint64_t chainID{1}; const arith_uint256 nonceParam = request.params[1].get_int64(); - const auto nonce = ArithToUint256(nonceParam).ToArray(); + const auto nonce = ArithToUint256(nonceParam); arith_uint256 gasPriceArith = request.params[2].get_int64(); // Price as GWei gasPriceArith *= WEI_IN_GWEI; // Convert to Wei @@ -79,7 +79,7 @@ UniValue evmtx(const JSONRPCRequest& request) { } const arith_uint256 valueParam = AmountFromValue(request.params[5]); - const auto value = ArithToUint256(valueParam * CAMOUNT_TO_WEI * WEI_IN_GWEI).ToArray(); + const auto value = ArithToUint256(valueParam * CAMOUNT_TO_WEI * WEI_IN_GWEI); rust::Vec input{}; if (!request.params[6].isNull()) { @@ -96,7 +96,7 @@ UniValue evmtx(const JSONRPCRequest& request) { std::array privKey{}; std::copy(key.begin(), key.end(), privKey.begin()); - const auto signedTx = create_and_sign_tx(chainID, nonce, gasPrice.ToArrayReversed(), gasLimit.ToArrayReversed(), to, value, input, privKey); + const auto signedTx = create_and_sign_tx(chainID, nonce.ToArrayReversed(), gasPrice.ToArrayReversed(), gasLimit.ToArrayReversed(), to, value.ToArrayReversed(), input, privKey); std::vector evmTx(signedTx.size()); std::copy(signedTx.begin(), signedTx.end(), evmTx.begin()); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index e83b5cf7e4e..ff354c6303c 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -361,6 +361,10 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listgovproposalvotes", 3, "pagination" }, { "listgovproposals", 2, "cycle" }, { "listgovproposals", 3, "pagination" }, + { "evmtx", 1, "nonce" }, + { "evmtx", 2, "gasPrice" }, + { "evmtx", 3, "gasLimit" }, + { "evmtx", 5, "value" }, }; // clang-format on diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b8f1f39455b..405a803229c 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,6 +16,7 @@ name = "ain-evm" version = "0.1.0" dependencies = [ "ain-utils", + "anyhow", "ethereum", "evm", "hex", @@ -67,6 +68,7 @@ dependencies = [ "evm", "hex", "primitive-types", + "rand", ] [[package]] diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 3d7ab3ef742..20efd2d4d3c 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -7,13 +7,13 @@ use std::error::Error; #[cxx::bridge] mod ffi { extern "Rust" { - fn evm_add_balance(address: &str, amount: i64) -> Result<()>; - fn evm_sub_balance(address: &str, amount: i64) -> Result<()>; + fn evm_add_balance(address: &str, amount: [u8; 32]) -> Result<()>; + fn evm_sub_balance(address: &str, amount: [u8; 32]) -> Result<()>; fn evm_validate_raw_tx(tx: &str) -> Result; fn evm_get_context() -> u64; fn evm_discard_context(context: u64); - fn evm_queue_tx(context: u64) -> Result; + fn evm_queue_tx(context: u64, raw_tx: &str) -> Result; fn evm_finalise(context: u64, update_state: bool) -> Result>; fn init_runtime(); @@ -33,12 +33,12 @@ mod ffi { } } -pub fn evm_add_balance(address: &str, amount: i64) -> Result<(), Box> { - RUNTIME.evm.add_balance(address, amount) +pub fn evm_add_balance(address: &str, amount: [u8; 32]) -> Result<(), Box> { + RUNTIME.evm.add_balance(address, amount.into()) } -pub fn evm_sub_balance(address: &str, amount: i64) -> Result<(), Box> { - RUNTIME.evm.sub_balance(address, amount) +pub fn evm_sub_balance(address: &str, amount: [u8; 32]) -> Result<(), Box> { + RUNTIME.evm.sub_balance(address, amount.into()) } pub fn evm_validate_raw_tx(tx: &str) -> Result> { @@ -49,20 +49,22 @@ pub fn evm_validate_raw_tx(tx: &str) -> Result> { } pub fn evm_get_context() -> u64 { - // TODO Generate unique contexts. - 1 + RUNTIME.evm.get_context() } fn evm_discard_context(context: u64) { // TODO discard + RUNTIME.evm.discard_context(context) } -fn evm_queue_tx(context: u64) -> Result> { - Ok(true) +fn evm_queue_tx(context: u64, raw_tx: &str) -> Result> { + match RUNTIME.evm.queue_tx(context, raw_tx) { + Ok(_) => Ok(true), + Err(_) => Ok(false), + } } fn evm_finalise(context: u64, update_state: bool) -> Result, Box> { let block_and_failed_txs: Vec = Vec::new(); Ok(block_and_failed_txs) } - diff --git a/src/rust/crates/ain-evm-state/Cargo.toml b/src/rust/crates/ain-evm-state/Cargo.toml index 3617ec8126a..e3a1f1883de 100644 --- a/src/rust/crates/ain-evm-state/Cargo.toml +++ b/src/rust/crates/ain-evm-state/Cargo.toml @@ -10,5 +10,6 @@ bincode = "1.3.3" ethereum = "0.14.0" hex = "0.4.3" anyhow = "1.0" +rand = "0.8.5" ain-evm = { path = "../ain-evm" } diff --git a/src/rust/crates/ain-evm-state/src/handler.rs b/src/rust/crates/ain-evm-state/src/handler.rs index 646fe76ae8e..3de2959ff8c 100644 --- a/src/rust/crates/ain-evm-state/src/handler.rs +++ b/src/rust/crates/ain-evm-state/src/handler.rs @@ -1,33 +1,29 @@ -use ain_evm::transaction::SignedTx; +use ain_evm::{block::Block, executor::AinExecutor, traits::Executor, transaction::SignedTx}; use anyhow::anyhow; -use ethereum::{AccessList, TransactionAction, TransactionV2}; +use ethereum::{AccessList, TransactionV2}; use evm::{ - backend::{Basic, MemoryAccount, MemoryBackend, MemoryVicinity}, - executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata}, - ExitReason, Memory, + backend::{MemoryBackend, MemoryVicinity}, + ExitReason, }; use hex::FromHex; use primitive_types::{H160, H256, U256}; use std::error::Error; use std::sync::{Arc, RwLock}; -use std::{collections::BTreeMap, sync::Mutex}; -use crate::traits::PersistentState; -use crate::{EVMState, CONFIG, EVM_STATE_PATH, GAS_LIMIT}; +use crate::tx_queue::TransactionQueueMap; +use crate::EVMState; #[derive(Clone, Debug)] pub struct EVMHandler { pub state: Arc>, - pub tx_queue: Arc>>, + pub tx_queues: Arc, } impl EVMHandler { pub fn new() -> Self { Self { - state: Arc::new(RwLock::new( - EVMState::load_from_disk(EVM_STATE_PATH).unwrap(), - )), - tx_queue: Arc::new(Mutex::new(Vec::new())), + state: Arc::new(RwLock::new(EVMState::new())), + tx_queues: Arc::new(TransactionQueueMap::new()), } } @@ -41,50 +37,15 @@ impl EVMHandler { access_list: AccessList, ) -> (ExitReason, Vec) { // TODO Add actual gas, chain_id, block_number from header - let vicinity = MemoryVicinity { - gas_price: U256::zero(), - origin: caller.unwrap_or_default(), - block_hashes: Vec::new(), - block_number: Default::default(), - block_coinbase: Default::default(), - block_timestamp: Default::default(), - block_difficulty: Default::default(), - block_gas_limit: Default::default(), - chain_id: U256::one(), - block_base_fee_per_gas: U256::zero(), - }; + let vicinity = get_vicinity(caller, None); + let state = self.state.read().unwrap().clone(); let backend = MemoryBackend::new(&vicinity, state); - - let metadata = StackSubstateMetadata::new(GAS_LIMIT, &CONFIG); - let state = MemoryStackState::new(metadata, &backend); - let precompiles = BTreeMap::new(); // TODO Add precompile crate - let mut executor = StackExecutor::new_with_precompiles(state, &CONFIG, &precompiles); - let access_list = access_list - .into_iter() - .map(|x| (x.address, x.storage_keys)) - .collect::>(); - match to { - Some(address) => executor.transact_call( - caller.unwrap_or_default(), - address, - value, - data.to_vec(), - gas_limit, - access_list.into(), - ), - None => executor.transact_create( - caller.unwrap_or_default(), - value, - data.to_vec(), - gas_limit, - access_list, - ), - } + AinExecutor::new(backend).call(caller, to, value, data, gas_limit, access_list, false) } // TODO wrap in EVM transaction and dryrun with evm_call - pub fn add_balance(&self, address: &str, value: i64) -> Result<(), Box> { + pub fn add_balance(&self, address: &str, value: U256) -> Result<(), Box> { let to = address.parse()?; let mut state = self.state.write().unwrap(); let mut account = state.entry(to).or_default(); @@ -92,42 +53,28 @@ impl EVMHandler { Ok(()) } - pub fn sub_balance(&self, address: &str, value: i64) -> Result<(), Box> { + pub fn sub_balance(&self, address: &str, value: U256) -> Result<(), Box> { let address = address.parse()?; let mut state = self.state.write().unwrap(); let mut account = state.get_mut(&address).unwrap(); - if account.balance > value.into() { + if account.balance > value { account.balance = account.balance - value; } Ok(()) } - fn get_account(&self, address: &H160) -> MemoryAccount { - self.state - .read() - .unwrap() - .get(&address) - .map(|account| account.clone()) - .unwrap_or_else(|| MemoryAccount { - nonce: U256::default(), - balance: U256::default(), - storage: BTreeMap::new(), - code: Vec::new(), - }) - } - - pub fn validate_raw_tx(&self, tx: &str) -> Result<(), Box> { + pub fn validate_raw_tx(&self, tx: &str) -> Result> { let buffer = >::from_hex(tx)?; let tx: TransactionV2 = ethereum::EnvelopedDecodable::decode(&buffer) .map_err(|_| anyhow!("Error: decoding raw tx to TransactionV2"))?; // TODO Validate gas limit and chain_id - let sign_tx: SignedTx = tx.try_into()?; + let signed_tx: SignedTx = tx.try_into()?; // TODO validate account nonce and balance to pay gas - // let account = self.get_account(&sign_tx.sender); - // if account.nonce >= sign_tx.nonce() { + // let account = self.get_account(&signed_tx.sender); + // if account.nonce >= signed_tx.nonce() { // return Err(anyhow!("Invalid nonce").into()); // } // if account.balance < MIN_GAS { @@ -135,15 +82,187 @@ impl EVMHandler { // } match self.call( - Some(sign_tx.sender), - sign_tx.to(), - sign_tx.value(), - sign_tx.data(), - sign_tx.gas_limit().as_u64(), - sign_tx.access_list(), + Some(signed_tx.sender), + signed_tx.to(), + signed_tx.value(), + signed_tx.data(), + signed_tx.gas_limit().as_u64(), + signed_tx.access_list(), ) { - (exit_reason, _) if exit_reason.is_succeed() => Ok(()), + (exit_reason, _) if exit_reason.is_succeed() => Ok(signed_tx), _ => Err(anyhow!("Error calling EVM").into()), } } + + pub fn get_context(&self) -> u64 { + self.tx_queues.get_context() + } + + pub fn discard_context(&self, context: u64) { + self.tx_queues.clear(context) + } + + pub fn queue_tx(&self, context: u64, raw_tx: &str) -> Result<(), Box> { + let signed_tx = self.validate_raw_tx(raw_tx)?; + self.tx_queues.add_signed_tx(context, signed_tx); + Ok(()) + } + + pub fn finalize_block( + &self, + context: u64, + update_state: bool, + ) -> Result<(Block, Vec), Box> { + let mut tx_hashes = Vec::with_capacity(self.tx_queues.len(context)); + let mut failed_tx_hashes = Vec::with_capacity(self.tx_queues.len(context)); + + let vicinity = get_vicinity(None, None); + let state = self.state.read().unwrap().clone(); + let backend = MemoryBackend::new(&vicinity, state); + let mut executor = AinExecutor::new(backend); + + for signed_tx in self.tx_queues.drain_all(context) { + let (exit_reason, _) = executor.exec(&signed_tx); + + if exit_reason.is_succeed() { + tx_hashes.push(signed_tx.transaction.hash()); + } else { + failed_tx_hashes.push(signed_tx.transaction.hash()) + } + } + + if update_state { + let mut state = self.state.write().unwrap(); + *state = executor.backend().state().clone(); + } + + let block = Block::new(tx_hashes); + Ok((block, failed_tx_hashes)) + } +} + +// TBD refine what vicinity we need. gas_price and origin only ? +fn get_vicinity(origin: Option, gas_price: Option) -> MemoryVicinity { + MemoryVicinity { + gas_price: gas_price.unwrap_or_else(|| U256::MAX), + origin: origin.unwrap_or_default(), + block_hashes: Vec::new(), + block_number: Default::default(), + block_coinbase: Default::default(), + block_timestamp: Default::default(), + block_difficulty: Default::default(), + block_gas_limit: U256::MAX, + chain_id: U256::one(), + block_base_fee_per_gas: U256::MAX, + } +} + +mod tests { + use ain_evm::transaction::SignedTx; + use evm::backend::MemoryAccount; + use primitive_types::{H160, H256, U256}; + + use super::EVMHandler; + + #[test] + fn test_finalize_block_and_update_test() { + let handler = EVMHandler::new(); + handler + .add_balance( + "0x4a1080c5533cb89edc4b65013f08f78868e382de", + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ) + .unwrap(); + let context = handler.get_context(); + + let tx1: SignedTx = "f86b0285174876e8006494a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + handler.tx_queues.add_signed_tx(context, tx1.clone()); + + handler + .add_balance( + "0x47e0d33aeaaaba1a0367ee9adbf87c828f05ce3d", + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ) + .unwrap(); + let tx2: SignedTx = "f86b0285174876e8006494a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a01465e2d999c34b22bf4b8b5c9439918e46341f4f0da1b00a6b0479c541161d4aa074abe79c51bf57086e1e84b57ee483cbb2ecf30e8222bc0472436fabfc57dda8".try_into().unwrap(); + handler.tx_queues.add_signed_tx(context, tx2.clone()); + + let tx3: SignedTx = "f86b0285174876e8006494a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a070b21a24cec13c0569099ee2f8221268103fd609646b73f7c9e85efeb7af5c8ea03d5de75bc12ce28a80f7c0401df6021cc82a334cb1c802c8b9d46223c5c8eb40".try_into().unwrap(); + handler.tx_queues.add_signed_tx(context, tx3.clone()); + + assert_eq!(handler.tx_queues.len(context), 3); + assert_eq!(handler.tx_queues.len(handler.get_context()), 0); + + let (block, failed_txs) = handler.finalize_block(context, true).unwrap(); + assert_eq!( + block.txs, + vec![tx1, tx2] + .into_iter() + .map(|t| t.transaction.hash()) + .collect::>() + ); + assert_eq!( + failed_txs, + vec![tx3] + .into_iter() + .map(|t| t.transaction.hash()) + .collect::>() + ); + + let state = handler.state.read().unwrap(); + assert_eq!( + state + .get( + &"0xa8f7c4c78c36e54c3950ad58dad24ca5e0191b29" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("200000000000000000000", 10).unwrap() + ); + assert_eq!( + state + .get( + &"0x4a1080c5533cb89edc4b65013f08f78868e382de" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("0", 10).unwrap() + ); + assert_eq!( + state + .get( + &"0x47e0d33aeaaaba1a0367ee9adbf87c828f05ce3d" + .parse() + .unwrap() + ) + .unwrap() + .balance, + U256::from_str_radix("0", 10).unwrap() + ) + } + + #[test] + fn test_finalize_block_and_do_not_update_test() { + let handler = EVMHandler::new(); + handler + .add_balance( + "0x4a1080c5533cb89edc4b65013f08f78868e382de", + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ) + .unwrap(); + let context = handler.get_context(); + + let tx1: SignedTx = "f86b0285174876e8006494a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); + handler.tx_queues.add_signed_tx(context, tx1.clone()); + + let old_state = handler.state.read().unwrap(); + let _ = handler.finalize_block(context, false).unwrap(); + + let new_state = handler.state.read().unwrap(); + assert_eq!(*new_state, *old_state); + } } diff --git a/src/rust/crates/ain-evm-state/src/lib.rs b/src/rust/crates/ain-evm-state/src/lib.rs index 2ca20350151..c3908a5d1af 100644 --- a/src/rust/crates/ain-evm-state/src/lib.rs +++ b/src/rust/crates/ain-evm-state/src/lib.rs @@ -1,18 +1,17 @@ pub mod handler; pub mod traits; +pub mod tx_queue; use std::collections::BTreeMap; use crate::traits::PersistentState; pub use evm::backend::Backend; use evm::backend::MemoryAccount; -use evm::Config; use primitive_types::H160; use std::fs::File; use std::io::{Read, Write}; use std::path::Path; -pub static CONFIG: Config = Config::london(); pub static GAS_LIMIT: u64 = u64::MAX; pub static EVM_STATE_PATH: &str = "evm_state.bin"; @@ -60,8 +59,8 @@ mod tests { #[test] fn test_load_non_existent_file() { - let state = EVMState::load_from_disk("non_existent_file.bin"); - assert!(state.is_err()); + let state = EVMState::load_from_disk("non_existent_file.bin").unwrap(); + assert_eq!(state, EVMState::default()); } #[test] diff --git a/src/rust/crates/ain-evm-state/src/tx_queue.rs b/src/rust/crates/ain-evm-state/src/tx_queue.rs new file mode 100644 index 00000000000..5d1c262c568 --- /dev/null +++ b/src/rust/crates/ain-evm-state/src/tx_queue.rs @@ -0,0 +1,92 @@ +use rand::Rng; +use std::{ + collections::HashMap, + sync::{Mutex, RwLock}, +}; + +use ain_evm::transaction::SignedTx; + +#[derive(Debug)] +pub struct TransactionQueueMap { + queues: RwLock>, +} + +impl TransactionQueueMap { + pub fn new() -> Self { + TransactionQueueMap { + queues: RwLock::new(HashMap::new()), + } + } + + pub fn get_context(&self) -> u64 { + let mut rng = rand::thread_rng(); + loop { + let context = rng.gen(); + let mut write_guard = self.queues.write().unwrap(); + + if !write_guard.contains_key(&context) { + write_guard.insert(context, TransactionQueue::new()); + return context; + } + } + } + + pub fn clear(&self, index: u64) { + if let Some(queue) = self.queues.read().unwrap().get(&index) { + queue.clear() + } + } + + pub fn add_signed_tx(&self, index: u64, signed_tx: SignedTx) { + if let Some(queue) = self.queues.read().unwrap().get(&index) { + queue.add_signed_tx(signed_tx) + } + } + + pub fn drain_all(&self, index: u64) -> Vec { + match self.queues.read().unwrap().get(&index) { + Some(queue) => queue.drain_all(), + None => Vec::new(), + } + } + + pub fn len(&self, index: u64) -> usize { + match self.queues.read().unwrap().get(&index) { + Some(queue) => queue.len(), + None => 0, + } + } +} + +#[derive(Debug)] +pub struct TransactionQueue { + txs: Mutex>, +} + +impl TransactionQueue { + pub fn new() -> Self { + Self { + txs: Mutex::new(Vec::new()), + } + } + + pub fn clear(&self) { + self.txs.lock().unwrap().clear() + } + + pub fn drain_all(&self) -> Vec { + self.txs + .lock() + .unwrap() + .drain(..) + .collect::>() + } + + pub fn add_signed_tx(&self, signed_tx: SignedTx) { + self.txs.lock().unwrap().push(signed_tx) + } + + pub fn len(&self) -> usize { + self.txs.lock().unwrap().len() + } +} diff --git a/src/rust/crates/ain-evm/Cargo.toml b/src/rust/crates/ain-evm/Cargo.toml index cac6bc185ae..30606f0cc43 100644 --- a/src/rust/crates/ain-evm/Cargo.toml +++ b/src/rust/crates/ain-evm/Cargo.toml @@ -12,5 +12,6 @@ libsecp256k1 = "0.7.1" ethereum = "0.14.0" sha3 = "0.10.6" hex = "0.4.3" +anyhow = "1.0" ain-utils = { path = "../ain-utils" } diff --git a/src/rust/crates/ain-evm/src/block.rs b/src/rust/crates/ain-evm/src/block.rs new file mode 100644 index 00000000000..2268adcbefd --- /dev/null +++ b/src/rust/crates/ain-evm/src/block.rs @@ -0,0 +1,69 @@ +use primitive_types::H256; + +// go-ethereum Header: +// TBD -- Fields to support + +// Header represents a block header in the Ethereum blockchain. +// type Header struct { +// ParentHash common.Hash `json:"parentHash" gencodec:"required"` +// UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` +// Coinbase common.Address `json:"miner"` +// Root common.Hash `json:"stateRoot" gencodec:"required"` +// TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` +// ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` +// Bloom Bloom `json:"logsBloom" gencodec:"required"` +// Difficulty *big.Int `json:"difficulty" gencodec:"required"` +// Number *big.Int `json:"number" gencodec:"required"` +// GasLimit uint64 `json:"gasLimit" gencodec:"required"` +// GasUsed uint64 `json:"gasUsed" gencodec:"required"` +// Time uint64 `json:"timestamp" gencodec:"required"` +// Extra []byte `json:"extraData" gencodec:"required"` +// MixDigest common.Hash `json:"mixHash"` +// Nonce BlockNonce `json:"nonce"` + +// // BaseFee was added by EIP-1559 and is ignored in legacy headers. +// BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + +// // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. +// WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` + +// /* +// TODO (MariusVanDerWijden) Add this field once needed +// // Random was added during the merge and contains the BeaconState randomness +// Random common.Hash `json:"random" rlp:"optional"` +// */ +// } + +type MerkleRoot = H256; + +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct Header { + pub hash: H256, + pub parent_hash: H256, + pub state_root: MerkleRoot, + pub nonce: u64, + pub timestamp: u64, + pub block_number: u64, +} + +impl Header { + pub fn new() -> Self { + Header { + ..Default::default() + } + } +} + +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct Block { + pub header: Header, + pub txs: Vec, +} + +impl Block { + pub fn new(txs: Vec) -> Self { + let header = Header::new(); + + Block { header, txs } + } +} diff --git a/src/rust/crates/ain-evm/src/executor.rs b/src/rust/crates/ain-evm/src/executor.rs new file mode 100644 index 00000000000..5e73b07b151 --- /dev/null +++ b/src/rust/crates/ain-evm/src/executor.rs @@ -0,0 +1,92 @@ +use std::collections::BTreeMap; + +use crate::{traits::Executor, transaction::SignedTx}; +use evm::{ + backend::{ApplyBackend, Backend, MemoryAccount}, + executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata}, + Config, ExitReason, +}; + +use ethereum::AccessList; + +use primitive_types::{H160, U256}; + +pub struct AinExecutor { + backend: B, +} + +impl AinExecutor +where + B: Backend + ApplyBackend, +{ + pub fn new(backend: B) -> Self { + Self { backend } + } + + pub fn backend(&self) -> &B { + &self.backend + } +} + +impl Executor for AinExecutor +where + B: Backend + ApplyBackend, +{ + const CONFIG: Config = Config::london(); + + fn call( + &mut self, + caller: Option, + to: Option, + value: U256, + data: &[u8], + gas_limit: u64, + access_list: AccessList, + apply: bool, + ) -> (ExitReason, Vec) { + // let metadata = StackSubstateMetadata::new(gas_limit, &Self::CONFIG); + let metadata = StackSubstateMetadata::new(100000, &Self::CONFIG); + let state = MemoryStackState::new(metadata, &self.backend); + let precompiles = BTreeMap::new(); // TODO Add precompile crate + let mut executor = StackExecutor::new_with_precompiles(state, &Self::CONFIG, &precompiles); + let access_list = access_list + .into_iter() + .map(|x| (x.address, x.storage_keys)) + .collect::>(); + let (exit_reason, data) = match to { + Some(address) => executor.transact_call( + caller.unwrap_or_default(), + address, + value, + data.to_vec(), + gas_limit, + access_list.into(), + ), + None => executor.transact_create( + caller.unwrap_or_default(), + value, + data.to_vec(), + gas_limit, + access_list, + ), + }; + if apply && exit_reason.is_succeed() { + let (values, logs) = executor.into_state().deconstruct(); + self.backend.apply(values, logs, true); + } + (exit_reason, data) + } + + fn exec(&mut self, signed_tx: &SignedTx) -> (ExitReason, Vec) { + let apply = true; + self.call( + Some(signed_tx.sender), + signed_tx.to(), + signed_tx.value(), + signed_tx.data(), + signed_tx.gas_limit().as_u64(), + signed_tx.access_list(), + apply, + ) + } +} diff --git a/src/rust/crates/ain-evm/src/lib.rs b/src/rust/crates/ain-evm/src/lib.rs index 5866856b58e..acbfbc8e07e 100644 --- a/src/rust/crates/ain-evm/src/lib.rs +++ b/src/rust/crates/ain-evm/src/lib.rs @@ -1,3 +1,6 @@ +pub mod block; +pub mod executor; +pub mod traits; pub mod transaction; use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature}; diff --git a/src/rust/crates/ain-evm/src/traits.rs b/src/rust/crates/ain-evm/src/traits.rs new file mode 100644 index 00000000000..3bdf923f87f --- /dev/null +++ b/src/rust/crates/ain-evm/src/traits.rs @@ -0,0 +1,22 @@ +use ethereum::AccessList; +use evm::{backend::MemoryAccount, Config, ExitReason}; +use primitive_types::{H160, U256}; + +use crate::transaction::SignedTx; + +pub trait Executor { + const CONFIG: Config = Config::london(); + + fn call( + &mut self, + caller: Option, + to: Option, + value: U256, + data: &[u8], + gas_limit: u64, + access_list: AccessList, + apply: bool, + ) -> (ExitReason, Vec); + + fn exec(&mut self, tx: &SignedTx) -> (ExitReason, Vec); +} diff --git a/src/rust/crates/ain-evm/src/transaction.rs b/src/rust/crates/ain-evm/src/transaction.rs index d11c7fddb1c..363e26edbaa 100644 --- a/src/rust/crates/ain-evm/src/transaction.rs +++ b/src/rust/crates/ain-evm/src/transaction.rs @@ -123,6 +123,21 @@ impl TryFrom for SignedTx { } } +use anyhow::anyhow; +use hex::FromHex; + +impl TryFrom<&str> for SignedTx { + type Error = Box; + + fn try_from(src: &str) -> Result { + let buffer = >::from_hex(src)?; + let tx: TransactionV2 = ethereum::EnvelopedDecodable::decode(&buffer) + .map_err(|_| anyhow!("Error: decoding raw tx to TransactionV2"))?; + + tx.try_into().map_err(|e: libsecp256k1::Error| e.into()) + } +} + impl SignedTx { pub fn nonce(&self) -> U256 { match &self.transaction { @@ -133,11 +148,7 @@ impl SignedTx { } pub fn to(&self) -> Option { - let action = match &self.transaction { - TransactionV2::Legacy(t) => t.action, - TransactionV2::EIP2930(t) => t.action, - TransactionV2::EIP1559(t) => t.action, - }; + let action = self.action(); match action { TransactionAction::Call(to) => Some(to), TransactionAction::Create => None, @@ -176,6 +187,14 @@ impl SignedTx { } } + pub fn gas_price(&self) -> U256 { + match &self.transaction { + TransactionV2::Legacy(tx) => tx.gas_price, + TransactionV2::EIP2930(tx) => tx.gas_price, + TransactionV2::EIP1559(tx) => tx.max_fee_per_gas.min(tx.max_priority_fee_per_gas), // TODO verify calculation + } + } + pub fn data(&self) -> &[u8] { match &self.transaction { TransactionV2::Legacy(tx) => tx.input.as_ref(), diff --git a/src/rust/crates/ain-utils/src/lib.rs b/src/rust/crates/ain-utils/src/lib.rs index 7f31f9d4562..334064ac6eb 100644 --- a/src/rust/crates/ain-utils/src/lib.rs +++ b/src/rust/crates/ain-utils/src/lib.rs @@ -10,7 +10,12 @@ pub fn recover_public_key( recovery_id: u8, ) -> Result { let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes()); - let signature = Signature::parse_standard_slice(&[r.as_bytes(), &s.as_bytes()].concat())?; + + let mut standard_slice = [0u8; 64]; + standard_slice[..32].copy_from_slice(r.as_fixed_bytes()); + standard_slice[32..].copy_from_slice(s.as_fixed_bytes()); + let signature = Signature::parse_standard_slice(&standard_slice)?; + let recovery_id = RecoveryId::parse(recovery_id)?; libsecp256k1::recover(&msg, &signature, &recovery_id) } From c8ebbbac0b5a8b7fc7c6202119c3a92467af5de2 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 11:30:56 +0100 Subject: [PATCH 08/13] Add EVM header to coinbase --- src/masternodes/mn_checks.h | 2 +- src/miner.cpp | 27 +++++++++++++++++++++++---- src/miner.h | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index 2d93bfecfe3..c89542e928c 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -467,7 +467,7 @@ Res ApplyCustomTx(CCustomCSView &mnview, uint64_t time = 0, uint256 *canSpend = nullptr, uint32_t txn = 0, - const int64_t evmContext = 0); + const uint64_t evmContext = 0); Res CustomTxVisit(CCustomCSView &mnview, const CCoinsViewCache &coins, const CTransaction &tx, diff --git a/src/miner.cpp b/src/miner.cpp index 0ceef2d3d2e..ab7a85cc7f6 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -234,12 +235,20 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc timeOrdering = false; } + const auto evmContext = evm_get_context(); + if (timeOrdering) { - addPackageTxs(nPackagesSelected, nDescendantsUpdated, nHeight, mnview); + addPackageTxs(nPackagesSelected, nDescendantsUpdated, nHeight, mnview, evmContext); } else { - addPackageTxs(nPackagesSelected, nDescendantsUpdated, nHeight, mnview); + addPackageTxs(nPackagesSelected, nDescendantsUpdated, nHeight, mnview, evmContext); } + // TODO Get failed TXs and try to restore to mempool + const auto rustHeader = evm_finalise(evmContext, false); + + std::vector evmHeader{}; + evmHeader.resize(rustHeader.size()); + std::copy(rustHeader.begin(), rustHeader.end(), evmHeader.begin()); // TXs for the creationTx field in new tokens created via token split if (nHeight >= chainparams.GetConsensus().FortCanningCrunchHeight) { @@ -315,6 +324,16 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].nValue = CalculateCoinbaseReward(blockReward, consensus.dist.masternode); } + if (nHeight >= consensus.NextNetworkUpgradeHeight && !evmHeader.empty()) { + const auto headerIndex = coinbaseTx.vout.size(); + coinbaseTx.vout.resize(headerIndex + 1); + coinbaseTx.vout[headerIndex].nValue = 0; + + CScript script; + script << OP_RETURN << evmHeader; + coinbaseTx.vout[headerIndex].scriptPubKey = script; + } + LogPrint(BCLog::STAKING, "%s: post Eunos logic. Block reward %d Miner share %d foundation share %d\n", __func__, blockReward, coinbaseTx.vout[0].nValue, foundationValue); } @@ -507,7 +526,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve // mapModifiedTxs with the next transaction in the mempool to decide what // transaction package to work on next. template -void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int nHeight, CCustomCSView &view) +void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int nHeight, CCustomCSView &view, const uint64_t evmContext) { // mapModifiedTx will store sorted packages after they are modified // because some of their txs are already in the block @@ -655,7 +674,7 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda // Only check custom TXs if (txType != CustomTxType::None) { - auto res = ApplyCustomTx(view, coins, tx, chainparams.GetConsensus(), nHeight, pblock->nTime); + const auto res = ApplyCustomTx(view, coins, tx, chainparams.GetConsensus(), nHeight, pblock->nTime, nullptr, 0, evmContext); // Not okay invalidate, undo and skip if (!res.ok) { diff --git a/src/miner.h b/src/miner.h index 2a9a29c5d39..a00b2784c1f 100644 --- a/src/miner.h +++ b/src/miner.h @@ -193,7 +193,7 @@ class BlockAssembler * Increments nPackagesSelected / nDescendantsUpdated with corresponding * statistics from the package selection (for logging statistics). */ template - void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int nHeight, CCustomCSView &view) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); + void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, int nHeight, CCustomCSView &view, const uint64_t evmContext) EXCLUSIVE_LOCKS_REQUIRED(mempool.cs); // helper functions for addPackageTxs() /** Remove confirmed (inBlock) entries from given set */ From bbefa87705a42a808e195ebd7279789af3293793 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Tue, 4 Apr 2023 12:59:47 +0100 Subject: [PATCH 09/13] Add call to get key from wallets --- src/wallet/wallet.cpp | 17 +++++++++++++++++ src/wallet/wallet.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f32293dbf43..67a80432a75 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -156,6 +156,23 @@ std::shared_ptr LoadWallet(interfaces::Chain& chain, const WalletLocati return wallet; } +std::array GetKeyFromWallets(rust::Vec input) { + CKey key; + CKeyID keyID; + std::copy(input.begin(), input.end(), keyID.begin()); + + for (const auto &wallet : GetWallets()) { + if (wallet->GetKey(keyID, key)) { + break; + } + } + + std::array result{}; + std::copy(key.begin(), key.end(), result.begin()); + + return result; +} + std::shared_ptr LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning) { return LoadWallet(chain, WalletLocation(name), error, warning); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 14e93839c06..d976bded457 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include