From 393e55aa81a51213d4e70a95dcbc7ea1b2f16fd0 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Thu, 6 Apr 2023 14:07:28 +0800 Subject: [PATCH] Revert "EVM in/out refinements (#1865)" This reverts commit 35c85d4938d6cd1170ed7f90ce82b4dbeaf5c49b. --- src/amount.h | 2 - src/masternodes/mn_checks.cpp | 52 ++---- src/masternodes/rpc_evm.cpp | 3 + src/rust/crates/ain-evm-ffi/src/lib.rs | 25 +-- src/rust/crates/ain-evm-state/src/handler.rs | 153 +----------------- src/rust/crates/ain-evm-state/src/tx_queue.rs | 108 ++----------- src/rust/crates/ain-evm-state/tests/block.rs | 110 ------------- src/wallet/wallet.cpp | 4 +- src/wallet/wallet.h | 3 +- 9 files changed, 43 insertions(+), 417 deletions(-) delete mode 100644 src/rust/crates/ain-evm-state/tests/block.rs diff --git a/src/amount.h b/src/amount.h index 67db644848..dd26bdc686 100644 --- a/src/amount.h +++ b/src/amount.h @@ -77,8 +77,6 @@ struct DCT_ID { static constexpr CAmount COIN = 100000000; static constexpr CAmount CENT = 1000000; -static constexpr int64_t WEI_IN_GWEI = 1000000000; -static constexpr int64_t CAMOUNT_TO_WEI = 10; //Converts the given value to decimal format string with COIN precision. inline std::string GetDecimalString(CAmount nValue) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 960f04fb70..7afd8c7faa 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3834,6 +3834,12 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { const auto sumFrom = SumAllTransfers(obj.from); const auto sumTo = SumAllTransfers(obj.to); + if (obj.type == CTransferBalanceType::EvmIn || obj.type == CTransferBalanceType::EvmOut) { + for (const auto& [id, _] : sumFrom.balances) + if (id != DCT_ID{0}) + return Res::Err("For EVM in/out transfers only DFI token is currently supported"); + } + if (sumFrom != sumTo) return Res::Err("sum of inputs (from) != sum of outputs (to)"); @@ -3845,54 +3851,18 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { if (!res) return res; } else if (obj.type == CTransferBalanceType::EvmIn) { - res = SubBalancesDelShares(obj.from); - if (!res) - return res; - - for (const auto& [addr, balances] : obj.to) { + for (const auto& [addr, _] : obj.to) { CTxDestination dest; if (ExtractDestination(addr, dest)) { if (dest.index() != WitV16KeyEthHashType) { return Res::Err("To address must be an ETH address in case of \"evmin\" transfertype"); } } - - const auto toAddress = std::get(dest); - - for (const auto& [id, amount] : balances.balances) { - if (id != DCT_ID{0}) { - return Res::Err("For EVM out transfers, only DFI token is currently supported"); - } - - arith_uint256 balanceIn = amount; - balanceIn *= CAMOUNT_TO_WEI * WEI_IN_GWEI; - evm_add_balance(evmContext, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).ToArrayReversed()); - } } + res = SubBalancesDelShares(obj.from); + if (!res) + return res; } else if (obj.type == CTransferBalanceType::EvmOut) { - for (const auto& [addr, balances] : obj.from) { - CTxDestination dest; - if (ExtractDestination(addr, dest)) { - if (dest.index() != WitV16KeyEthHashType) { - return Res::Err("Invalid destination"); - } - } - - const auto fromAddress = std::get(dest); - - for (const auto& [id, amount] : balances.balances) { - if (id != DCT_ID{0}) { - return Res::Err("For EVM out transfers, only DFI token is currently supported"); - } - - arith_uint256 balanceIn = amount; - balanceIn *= CAMOUNT_TO_WEI * WEI_IN_GWEI; - if (!evm_sub_balance(evmContext, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).ToArrayReversed())) { - return Res::Err("Not enough balance in %s to cover EVM out", EncodeDestination(dest)); - } - } - } - res = AddBalancesSetShares(obj.to); if (!res) return res; @@ -4115,7 +4085,7 @@ Res ApplyCustomTx(CCustomCSView &mnview, PopulateVaultHistoryData(mnview.GetHistoryWriters(), view, txMessage, txType, height, txn, tx.GetHash()); } - res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, txn, evmContext); + res = CustomTxVisit(view, coins, tx, height, consensus, txMessage, time, txn); if (res) { if (canSpend && txType == CustomTxType::UpdateMasternode) { diff --git a/src/masternodes/rpc_evm.cpp b/src/masternodes/rpc_evm.cpp index fed5bc3c22..1bdd020873 100644 --- a/src/masternodes/rpc_evm.cpp +++ b/src/masternodes/rpc_evm.cpp @@ -3,6 +3,9 @@ #include #include +const int64_t WEI_IN_GWEI = 1000000000; +const int64_t CAMOUNT_TO_WEI = 10; + UniValue evmtx(const JSONRPCRequest& request) { auto pwallet = GetWallet(request); diff --git a/src/rust/crates/ain-evm-ffi/src/lib.rs b/src/rust/crates/ain-evm-ffi/src/lib.rs index 5734f7a409..26ba028c11 100644 --- a/src/rust/crates/ain-evm-ffi/src/lib.rs +++ b/src/rust/crates/ain-evm-ffi/src/lib.rs @@ -7,8 +7,8 @@ use std::error::Error; #[cxx::bridge] mod ffi { extern "Rust" { - fn evm_add_balance(context: u64, address: &str, amount: [u8; 32]) -> Result<()>; - fn evm_sub_balance(context: u64, address: &str, amount: [u8; 32]) -> 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; @@ -33,25 +33,12 @@ mod ffi { } } -pub fn evm_add_balance( - context: u64, - address: &str, - amount: [u8; 32], -) -> Result<(), Box> { - let address = address.parse()?; - Ok(RUNTIME.evm.add_balance(context, address, amount.into())) +pub fn evm_add_balance(address: &str, amount: [u8; 32]) -> Result<(), Box> { + RUNTIME.handlers.evm.add_balance(address, amount.into()) } -pub fn evm_sub_balance( - context: u64, - address: &str, - amount: [u8; 32], -) -> Result> { - let address = address.parse()?; - match RUNTIME.evm.sub_balance(context, address, amount.into()) { - Ok(_) => Ok(true), - Err(_) => Ok(false), - } +pub fn evm_sub_balance(address: &str, amount: [u8; 32]) -> Result<(), Box> { + RUNTIME.handlers.evm.sub_balance(address, amount.into()) } pub fn evm_validate_raw_tx(tx: &str) -> Result> { diff --git a/src/rust/crates/ain-evm-state/src/handler.rs b/src/rust/crates/ain-evm-state/src/handler.rs index a63b09b7d3..14d18e501e 100644 --- a/src/rust/crates/ain-evm-state/src/handler.rs +++ b/src/rust/crates/ain-evm-state/src/handler.rs @@ -9,157 +9,8 @@ pub struct Handlers { impl Handlers { pub fn new() -> Self { Self { - state: Arc::new(RwLock::new(EVMState::new())), - tx_queues: Arc::new(TransactionQueueMap::new()), + evm: EVMHandler::new(), + block: BlockHandler::new(), } } - - pub fn call( - &self, - caller: Option, - to: Option, - value: U256, - data: &[u8], - gas_limit: u64, - access_list: AccessList, - ) -> (ExitReason, Vec) { - // TODO Add actual gas, chain_id, block_number from header - let vicinity = get_vicinity(caller, None); - - let state = self.state.read().unwrap().clone(); - let backend = MemoryBackend::new(&vicinity, state); - let tx_response = - AinExecutor::new(backend).call(caller, to, value, data, gas_limit, access_list, false); - (tx_response.exit_reason, tx_response.data) - } - - // TODO wrap in EVM transaction and dryrun with evm_call - pub fn add_balance(&self, context: u64, address: H160, value: U256) { - self.tx_queues.add_balance(context, address, value) - } - - pub fn sub_balance( - &self, - context: u64, - address: H160, - value: U256, - ) -> Result<(), Box> { - self.tx_queues - .sub_balance(context, address, value) - .map_err(|e| e.into()) - } - - 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 signed_tx: SignedTx = tx.try_into()?; - - // TODO validate account nonce and balance to pay gas - // 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 { - // return Err(anyhow!("Insufficiant balance to pay fees").into()); - // } - - match 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(), - ) { - (exit_reason, _) if exit_reason.is_succeed() => Ok(signed_tx), - _ => Err(anyhow!("Error calling EVM").into()), - } - } - - pub fn get_context(&self) -> u64 { - let state = self.state.read().unwrap().clone(); - self.tx_queues.get_context(state) - } - - 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.tx_queues.state(context).expect("Wrong context"); - let backend = MemoryBackend::new(&vicinity, state); - let mut executor = AinExecutor::new(backend); - - for signed_tx in self.tx_queues.drain_all(context) { - let tx_response = executor.exec(&signed_tx); - println!("tx_response : {:#?}", tx_response); - if tx_response.exit_reason.is_succeed() { - // responses.push() - tx_hashes.push(signed_tx.transaction); - } else { - failed_tx_hashes.push(signed_tx.transaction) - } - } - - self.tx_queues.remove(context); - - if update_state { - let mut state = self.state.write().unwrap(); - *state = executor.backend().state().clone(); - } - - let block = Block::new( - PartialHeader { - parent_hash: Default::default(), - beneficiary: Default::default(), - state_root: Default::default(), - receipts_root: Default::default(), - logs_bloom: Default::default(), - difficulty: Default::default(), - number: Default::default(), - gas_limit: Default::default(), - gas_used: Default::default(), - timestamp: Default::default(), - extra_data: Default::default(), - mix_hash: Default::default(), - nonce: Default::default(), - }, - tx_hashes, - Vec::new(), - ); - 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, - } } diff --git a/src/rust/crates/ain-evm-state/src/tx_queue.rs b/src/rust/crates/ain-evm-state/src/tx_queue.rs index 24a011ba54..5d1c262c56 100644 --- a/src/rust/crates/ain-evm-state/src/tx_queue.rs +++ b/src/rust/crates/ain-evm-state/src/tx_queue.rs @@ -1,4 +1,3 @@ -use primitive_types::{H160, U256}; use rand::Rng; use std::{ collections::HashMap, @@ -7,8 +6,6 @@ use std::{ use ain_evm::transaction::SignedTx; -use crate::EVMState; - #[derive(Debug)] pub struct TransactionQueueMap { queues: RwLock>, @@ -21,97 +18,64 @@ impl TransactionQueueMap { } } - pub fn get_context(&self, state: EVMState) -> u64 { + 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(state)); + write_guard.insert(context, TransactionQueue::new()); return context; } } } - pub fn remove(&self, context_id: u64) -> Option { - self.queues.write().unwrap().remove(&context_id) - } - - pub fn clear(&self, context_id: u64) { - if let Some(queue) = self.queues.read().unwrap().get(&context_id) { + pub fn clear(&self, index: u64) { + if let Some(queue) = self.queues.read().unwrap().get(&index) { queue.clear() } } - pub fn add_signed_tx(&self, context_id: u64, signed_tx: SignedTx) { - if let Some(queue) = self.queues.read().unwrap().get(&context_id) { + 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, context_id: u64) -> Vec { - match self.queues.read().unwrap().get(&context_id) { + 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, context_id: u64) -> usize { - match self.queues.read().unwrap().get(&context_id) { + pub fn len(&self, index: u64) -> usize { + match self.queues.read().unwrap().get(&index) { Some(queue) => queue.len(), None => 0, } } - - pub fn add_balance(&self, context_id: u64, address: H160, value: U256) { - if let Some(queue) = self.queues.read().unwrap().get(&context_id) { - queue.add_balance(address, value) - } - } - - pub fn sub_balance( - &self, - context_id: u64, - address: H160, - value: U256, - ) -> Result<(), QueueError> { - if let Some(queue) = self.queues.read().unwrap().get(&context_id) { - queue.sub_balance(address, value) - } else { - Err(QueueError::NoSuchContext) - } - } - - pub fn state(&self, context_id: u64) -> Option { - if let Some(queue) = self.queues.read().unwrap().get(&context_id) { - Some(queue.state()) - } else { - None - } - } } #[derive(Debug)] pub struct TransactionQueue { - transactions: Mutex>, - state: RwLock, + txs: Mutex>, } impl TransactionQueue { - pub fn new(state: EVMState) -> Self { + pub fn new() -> Self { Self { - transactions: Mutex::new(Vec::new()), - state: RwLock::new(state), + txs: Mutex::new(Vec::new()), } } pub fn clear(&self) { - self.transactions.lock().unwrap().clear() + self.txs.lock().unwrap().clear() } pub fn drain_all(&self) -> Vec { - self.transactions + self.txs .lock() .unwrap() .drain(..) @@ -119,48 +83,10 @@ impl TransactionQueue { } pub fn add_signed_tx(&self, signed_tx: SignedTx) { - self.transactions.lock().unwrap().push(signed_tx) + self.txs.lock().unwrap().push(signed_tx) } pub fn len(&self) -> usize { - self.transactions.lock().unwrap().len() - } - - pub fn state(&self) -> EVMState { - self.state.read().unwrap().clone() - } - - pub fn add_balance(&self, address: H160, value: U256) { - let mut state = self.state.write().unwrap(); - let mut account = state.entry(address).or_default(); - account.balance = account.balance + value; - } - - pub fn sub_balance(&self, address: H160, value: U256) -> Result<(), QueueError> { - let mut state = self.state.write().unwrap(); - let mut account = state.get_mut(&address).unwrap(); - if account.balance > value { - account.balance = account.balance - value; - Ok(()) - } else { - Err(QueueError::InsufficientBalance) - } - } -} - -#[derive(Debug)] -pub enum QueueError { - NoSuchContext, - InsufficientBalance, -} - -impl std::fmt::Display for QueueError { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - QueueError::NoSuchContext => write!(f, "No transaction queue for this context"), - QueueError::InsufficientBalance => write!(f, "Insufficient balance"), - } + self.txs.lock().unwrap().len() } } - -impl std::error::Error for QueueError {} diff --git a/src/rust/crates/ain-evm-state/tests/block.rs b/src/rust/crates/ain-evm-state/tests/block.rs deleted file mode 100644 index e3a96a9e4c..0000000000 --- a/src/rust/crates/ain-evm-state/tests/block.rs +++ /dev/null @@ -1,110 +0,0 @@ -use ain_evm::transaction::SignedTx; -use primitive_types::U256; - -use ain_evm_state::handler::EVMHandler; - -#[test] -fn test_finalize_block_and_do_not_update_state() { - let handler = EVMHandler::new(); - let context = handler.get_context(); - handler.add_balance( - context, - "0x4a1080c5533cb89edc4b65013f08f78868e382de" - .parse() - .unwrap(), - U256::from_str_radix("100000000000000000000", 10).unwrap(), - ); - - let tx1: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); - println!("tx1 : {:#?}", tx1); - 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); -} - -#[test] -fn test_finalize_block_and_update_state() { - let handler = EVMHandler::new(); - let context = handler.get_context(); - handler.add_balance( - context, - "0x6745f998a96050bb9b0449e6bd4358138a519679" - .parse() - .unwrap(), - U256::from_str_radix("100000000000000000000", 10).unwrap(), - ); - - let tx1: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); - handler.tx_queues.add_signed_tx(context, tx1.clone()); - - handler.add_balance( - context, - "0xc0cd829081485e70348975d325fe5275140277bd" - .parse() - .unwrap(), - U256::from_str_radix("100000000000000000000", 10).unwrap(), - ); - let tx2: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a01465e2d999c34b22bf4b8b5c9439918e46341f4f0da1b00a6b0479c541161d4aa074abe79c51bf57086e1e84b57ee483cbb2ecf30e8222bc0472436fabfc57dda8".try_into().unwrap(); - handler.tx_queues.add_signed_tx(context, tx2.clone()); - - let tx3: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a070b21a24cec13c0569099ee2f8221268103fd609646b73f7c9e85efeb7af5c8ea03d5de75bc12ce28a80f7c0401df6021cc82a334cb1c802c8b9d46223c5c8eb40".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.transactions, - vec![tx1, tx2] - .into_iter() - .map(|t| t.transaction) - .collect::>() - ); - assert_eq!( - failed_txs, - vec![tx3] - .into_iter() - .map(|t| t.transaction) - .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( - &"0x6745f998a96050bb9b0449e6bd4358138a519679" - .parse() - .unwrap() - ) - .unwrap() - .balance, - U256::from_str_radix("0", 10).unwrap() - ); - assert_eq!( - state - .get( - &"0xc0cd829081485e70348975d325fe5275140277bd" - .parse() - .unwrap() - ) - .unwrap() - .balance, - U256::from_str_radix("0", 10).unwrap() - ); -} diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 1bb27f4d52..67a80432a7 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -156,7 +156,7 @@ std::shared_ptr LoadWallet(interfaces::Chain& chain, const WalletLocati return wallet; } -std::array GetKeyFromWallets(std::array input) { +std::array GetKeyFromWallets(rust::Vec input) { CKey key; CKeyID keyID; std::copy(input.begin(), input.end(), keyID.begin()); @@ -167,7 +167,7 @@ std::array GetKeyFromWallets(std::array input) { } } - std::array result{}; + std::array result{}; std::copy(key.begin(), key.end(), result.begin()); return result; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 4a297c7689..d976bded45 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include