diff --git a/lib/ain-evm/src/backend.rs b/lib/ain-evm/src/backend.rs index 6aae6816a3c..f829d0c3094 100644 --- a/lib/ain-evm/src/backend.rs +++ b/lib/ain-evm/src/backend.rs @@ -283,9 +283,9 @@ use std::{error::Error, fmt, sync::Arc}; #[derive(Debug)] pub struct InsufficientBalance { - address: H160, - account_balance: U256, - amount: U256, + pub address: H160, + pub account_balance: U256, + pub amount: U256, } #[derive(Debug)] diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index c50c85b50ad..df3e9c68318 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -1,9 +1,9 @@ -use crate::backend::{EVMBackend, EVMBackendError, Vicinity}; +use crate::backend::{EVMBackend, EVMBackendError, InsufficientBalance, Vicinity}; use crate::executor::TxResponse; use crate::storage::traits::{BlockStorage, PersistentState, PersistentStateError}; use crate::storage::Storage; use crate::transaction::bridge::{BalanceUpdate, BridgeTx}; -use crate::tx_queue::{QueueTx, TransactionQueueMap}; +use crate::tx_queue::{QueueError, QueueTx, TransactionQueueMap}; use crate::{ executor::AinExecutor, traits::{Executor, ExecutorContext}, @@ -196,12 +196,7 @@ impl EVMHandler { } impl EVMHandler { - pub fn queue_tx( - &self, - context: u64, - tx: QueueTx, - hash: NativeTxHash, - ) -> Result<(), Box> { + pub fn queue_tx(&self, context: u64, tx: QueueTx, hash: NativeTxHash) -> Result<(), EVMError> { self.tx_queues.queue_tx(context, tx, hash)?; Ok(()) } @@ -211,7 +206,7 @@ impl EVMHandler { address: H160, amount: U256, hash: NativeTxHash, - ) -> Result<(), Box> { + ) -> Result<(), EVMError> { let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount })); self.tx_queues.queue_tx(context, queue_tx, hash)?; Ok(()) @@ -223,17 +218,31 @@ impl EVMHandler { address: H160, amount: U256, hash: NativeTxHash, - ) -> Result<(), Box> { - let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })); - self.tx_queues.queue_tx(context, queue_tx, hash)?; - Ok(()) + ) -> Result<(), EVMError> { + let block_number = self + .storage + .get_latest_block() + .map_or(U256::default(), |block| block.header.number); + let balance = self.get_balance(address, block_number)?; + if balance < amount { + Err(EVMBackendError::InsufficientBalance(InsufficientBalance { + address, + account_balance: balance, + amount, + }) + .into()) + } else { + let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount })); + self.tx_queues.queue_tx(context, queue_tx, hash)?; + Ok(()) + } } pub fn get_context(&self) -> u64 { self.tx_queues.get_context() } - pub fn clear(&self, context: u64) -> Result<(), Box> { + pub fn clear(&self, context: u64) -> Result<(), EVMError> { self.tx_queues.clear(context)?; Ok(()) } @@ -316,6 +325,7 @@ use std::fmt; #[derive(Debug)] pub enum EVMError { BackendError(EVMBackendError), + QueueError(QueueError), NoSuchAccount(H160), TrieError(String), } @@ -324,6 +334,7 @@ impl fmt::Display for EVMError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { EVMError::BackendError(e) => write!(f, "EVMError: Backend error: {e}"), + EVMError::QueueError(e) => write!(f, "EVMError: Queue error: {e}"), EVMError::NoSuchAccount(address) => { write!(f, "EVMError: No such acccount for address {address:#x}") } @@ -340,4 +351,10 @@ impl From for EVMError { } } +impl From for EVMError { + fn from(e: QueueError) -> Self { + EVMError::QueueError(e) + } +} + impl std::error::Error for EVMError {} diff --git a/test/functional/feature_evm.py b/test/functional/feature_evm.py index b75d98477eb..4b77bd547bd 100755 --- a/test/functional/feature_evm.py +++ b/test/functional/feature_evm.py @@ -102,7 +102,7 @@ def run_test(self): assert_raises_rpc_error(-32600, "sum of inputs (from) != sum of outputs (to)", self.nodes[0].transferdomain, 1, {address:["100@BTC"]}, {ethAddress:["100@DFI"]}) assert_raises_rpc_error(-32600, "sum of inputs (from) != sum of outputs (to)", self.nodes[0].transferdomain, 1, {address:["100@DFI"]}, {ethAddress:["100@BTC"]}) assert_raises_rpc_error(-32600, "For \"evmin\" transfers, only DFI token is currently supported", self.nodes[0].transferdomain, 1, {address:["100@BTC"]}, {ethAddress:["100@BTC"]}) - #assert_raises_rpc_error(-32600, "Not enough balance in " + ethAddress + " to cover \"evmout\" transfer", self.nodes[0].transferdomain, 2, {ethAddress:["100@DFI"]}, {address:["100@DFI"]}) + assert_raises_rpc_error(-32600, "Not enough balance in " + ethAddress + " to cover \"evmout\" transfer", self.nodes[0].transferdomain, 2, {ethAddress:["100@DFI"]}, {address:["100@DFI"]}) self.nodes[0].transferdomain(1,{address:["100@DFI"]}, {ethAddress:["100@DFI"]}) self.nodes[0].generate(1)