From b84fc5827dd6d98335c73122d15db62a1c7f67aa Mon Sep 17 00:00:00 2001 From: Niven Date: Fri, 12 Jan 2024 15:11:22 +0800 Subject: [PATCH] EVM: Add pending transactions filter (#2774) * Shift create filters * Better refactor, add method documentations * Fmt rs * Refactor transaction cache out of core service * Fmt rs * Better rename --- lib/ain-cpp-imports/src/bridge.rs | 1 + lib/ain-cpp-imports/src/lib.rs | 1 + lib/ain-evm/src/core.rs | 119 +++--------------- lib/ain-evm/src/evm.rs | 14 ++- lib/ain-evm/src/filters.rs | 182 ++++++++++++++++++++++++--- lib/ain-evm/src/transaction/cache.rs | 116 +++++++++++++++++ lib/ain-evm/src/transaction/mod.rs | 1 + lib/ain-grpc/src/rpc/eth.rs | 14 +-- lib/ain-rs-exports/src/evm.rs | 49 ++------ src/ffi/ffiexports.cpp | 43 ++++--- src/ffi/ffiexports.h | 1 + 11 files changed, 348 insertions(+), 193 deletions(-) create mode 100644 lib/ain-evm/src/transaction/cache.rs diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 53d3662157b..cd614433021 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -20,6 +20,7 @@ pub mod ffi { pub tx_type: u8, pub data: String, pub direction: u8, + pub entry_time: i64, } unsafe extern "C++" { diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index fd008bd4bcd..9c73d704990 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -26,6 +26,7 @@ mod ffi { pub tx_type: u8, pub data: String, pub direction: u8, + pub entry_time: i64, } const UNIMPL_MSG: &str = "This cannot be used on a test path"; diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 530b6cb6441..ce7d8323c59 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -1,6 +1,5 @@ use std::{ collections::{BTreeSet, HashMap}, - num::NonZeroUsize, path::PathBuf, sync::Arc, }; @@ -11,10 +10,7 @@ use ain_contracts::{ FixedContract, }; use anyhow::format_err; -use ethereum::{ - AccessList, Account, Block, EnvelopedEncodable, Log, PartialHeader, TransactionAction, - TransactionV2, -}; +use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionAction, TransactionV2}; use ethereum_types::{Bloom, BloomInput, H160, H256, U256}; use evm::{ executor::stack::{MemoryStackState, StackExecutor, StackSubstateMetadata}, @@ -23,7 +19,6 @@ use evm::{ }; use evm_runtime::tracing::using as runtime_using; use log::{debug, trace}; -use lru::LruCache; use parking_lot::Mutex; use vsdb_core::vsdb_set_base_dir; @@ -37,7 +32,10 @@ use crate::{ precompiles::MetachainPrecompiles, receipt::ReceiptService, storage::{traits::BlockStorage, Storage}, - transaction::SignedTx, + transaction::{ + cache::{TransactionCache, ValidateTxInfo}, + SignedTx, + }, trie::TrieDBStore, weiamount::{try_from_satoshi, WeiAmount}, EVMError, Result, @@ -45,85 +43,6 @@ use crate::{ pub type XHash = String; -pub struct SignedTxCache { - inner: spin::Mutex>, -} - -impl Default for SignedTxCache { - fn default() -> Self { - Self::new(ain_cpp_imports::get_ecc_lru_cache_count()) - } -} - -impl SignedTxCache { - pub fn new(capacity: usize) -> Self { - Self { - inner: spin::Mutex::new(LruCache::new(NonZeroUsize::new(capacity).unwrap())), - } - } - - pub fn try_get_or_create(&self, key: &str) -> Result { - let mut guard = self.inner.lock(); - debug!("[signed-tx-cache]::get: {}", key); - let res = guard.try_get_or_insert(key.to_string(), || { - debug!("[signed-tx-cache]::create {}", key); - SignedTx::try_from(key) - })?; - Ok(res.clone()) - } - - pub fn pre_populate(&self, key: &str, signed_tx: SignedTx) -> Result<()> { - let mut guard = self.inner.lock(); - debug!("[signed-tx-cache]::pre_populate: {}", key); - let _ = guard.get_or_insert(key.to_string(), move || { - debug!("[signed-tx-cache]::pre_populate:: create {}", key); - signed_tx - }); - - Ok(()) - } - - pub fn try_get_or_create_from_tx(&self, tx: &TransactionV2) -> Result { - let data = EnvelopedEncodable::encode(tx); - let key = hex::encode(&data); - let mut guard = self.inner.lock(); - debug!("[signed-tx-cache]::get from tx: {}", &key); - let res = guard.try_get_or_insert(key.clone(), || { - debug!("[signed-tx-cache]::create from tx {}", &key); - SignedTx::try_from(key.as_str()) - })?; - Ok(res.clone()) - } -} - -struct TxValidationCache { - stateless: spin::Mutex>, -} - -impl Default for TxValidationCache { - fn default() -> Self { - Self::new(ain_cpp_imports::get_evmv_lru_cache_count()) - } -} - -impl TxValidationCache { - pub fn new(capacity: usize) -> Self { - Self { - stateless: spin::Mutex::new(LruCache::new(NonZeroUsize::new(capacity).unwrap())), - } - } - - pub fn get_stateless(&self, key: &str) -> Option { - self.stateless.lock().get(key).cloned() - } - - pub fn set_stateless(&self, key: String, value: ValidateTxInfo) -> ValidateTxInfo { - let mut cache = self.stateless.lock(); - cache.put(key, value.clone()); - value - } -} - #[derive(Clone, Debug)] pub struct ExecutionStep { pub pc: usize, @@ -136,10 +55,9 @@ pub struct ExecutionStep { pub struct EVMCoreService { pub trie_store: Arc, - pub signed_tx_cache: SignedTxCache, storage: Arc, + pub tx_cache: Arc, nonce_store: Mutex>>, - tx_validation_cache: TxValidationCache, } pub struct EthCallArgs<'a> { pub caller: H160, @@ -152,12 +70,6 @@ pub struct EthCallArgs<'a> { pub block_number: U256, } -#[derive(Clone, Debug)] -pub struct ValidateTxInfo { - pub signed_tx: SignedTx, - pub max_prepay_fee: U256, -} - pub struct TransferDomainTxInfo { pub from: String, pub to: String, @@ -175,20 +87,20 @@ fn init_vsdb(path: PathBuf) { } impl EVMCoreService { - pub fn restore(storage: Arc, path: PathBuf) -> Self { + pub fn restore(storage: Arc, tx_cache: Arc, path: PathBuf) -> Self { init_vsdb(path); Self { trie_store: Arc::new(TrieDBStore::restore()), - signed_tx_cache: SignedTxCache::default(), storage, + tx_cache, nonce_store: Mutex::new(HashMap::new()), - tx_validation_cache: TxValidationCache::default(), } } pub fn new_from_json( storage: Arc, + tx_cache: Arc, genesis_path: PathBuf, evm_datadir: PathBuf, ) -> Result { @@ -197,10 +109,9 @@ impl EVMCoreService { let handler = Self { trie_store: Arc::new(TrieDBStore::new()), - signed_tx_cache: SignedTxCache::default(), storage: Arc::clone(&storage), + tx_cache: Arc::clone(&tx_cache), nonce_store: Mutex::new(HashMap::new()), - tx_validation_cache: TxValidationCache::default(), }; let (state_root, genesis) = TrieDBStore::genesis_state_root_from_json( &handler.trie_store, @@ -324,11 +235,11 @@ impl EVMCoreService { let ValidateTxInfo { signed_tx, max_prepay_fee, - } = if let Some(validate_info) = self.tx_validation_cache.get_stateless(tx) { + } = if let Some(validate_info) = self.tx_cache.get_stateless(tx) { validate_info } else { let signed_tx = self - .signed_tx_cache + .tx_cache .try_get_or_create(tx) .map_err(|_| format_err!("Error: decoding raw tx to TransactionV2"))?; debug!("[validate_raw_tx] signed_tx : {:#?}", signed_tx); @@ -359,7 +270,7 @@ impl EVMCoreService { let max_prepay_fee = calculate_max_prepay_gas_fee(&signed_tx)?; debug!("[validate_raw_tx] max_prepay_fee : {:x?}", max_prepay_fee); - self.tx_validation_cache.set_stateless( + self.tx_cache.set_stateless( String::from(tx), ValidateTxInfo { signed_tx, @@ -463,11 +374,11 @@ impl EVMCoreService { let ValidateTxInfo { signed_tx, max_prepay_fee, - } = if let Some(validate_info) = self.tx_validation_cache.get_stateless(tx) { + } = if let Some(validate_info) = self.tx_cache.get_stateless(tx) { validate_info } else { let signed_tx = self - .signed_tx_cache + .tx_cache .try_get_or_create(tx) .map_err(|_| format_err!("Error: decoding raw tx to TransactionV2"))?; debug!( diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 3297a552617..981bfa5814f 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -30,7 +30,7 @@ use crate::{ log::{LogService, Notification}, receipt::ReceiptService, storage::{traits::BlockStorage, Storage}, - transaction::SignedTx, + transaction::{cache::TransactionCache, SignedTx}, trie::GENESIS_STATE_ROOT, Result, }; @@ -47,6 +47,7 @@ pub struct EVMServices { pub logs: LogService, pub filters: FilterService, pub storage: Arc, + pub tx_cache: Arc, pub channel: NotificationChannel, } @@ -104,17 +105,20 @@ impl EVMServices { .into()); } let storage = Arc::new(Storage::new(&path)?); + let tx_cache = Arc::new(TransactionCache::new()); Ok(Self { core: EVMCoreService::new_from_json( Arc::clone(&storage), + Arc::clone(&tx_cache), PathBuf::from(state_input_path), path, )?, block: BlockService::new(Arc::clone(&storage))?, receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), - filters: FilterService::new(Arc::clone(&storage)), + filters: FilterService::new(Arc::clone(&storage), Arc::clone(&tx_cache)), storage, + tx_cache, channel: NotificationChannel { sender, receiver: RwLock::new(receiver), @@ -122,13 +126,15 @@ impl EVMServices { }) } else { let storage = Arc::new(Storage::restore(&path)?); + let tx_cache = Arc::new(TransactionCache::new()); Ok(Self { - core: EVMCoreService::restore(Arc::clone(&storage), path), + core: EVMCoreService::restore(Arc::clone(&storage), Arc::clone(&tx_cache), path), block: BlockService::new(Arc::clone(&storage))?, receipt: ReceiptService::new(Arc::clone(&storage)), logs: LogService::new(Arc::clone(&storage)), - filters: FilterService::new(Arc::clone(&storage)), + filters: FilterService::new(Arc::clone(&storage), Arc::clone(&tx_cache)), storage, + tx_cache, channel: NotificationChannel { sender, receiver: RwLock::new(receiver), diff --git a/lib/ain-evm/src/filters.rs b/lib/ain-evm/src/filters.rs index 1e3fcbeda67..0a2705b537f 100644 --- a/lib/ain-evm/src/filters.rs +++ b/lib/ain-evm/src/filters.rs @@ -1,6 +1,5 @@ use std::{ cmp::min, - collections::BTreeSet, num::NonZeroUsize, sync::{Arc, RwLock}, }; @@ -16,6 +15,7 @@ use crate::{ traits::{BlockStorage, LogStorage}, Storage, }, + transaction::cache::TransactionCache, EVMError, Result, }; @@ -46,8 +46,8 @@ pub enum Filter { Logs(LogsFilter), // Blocks filter holds the last block number polled. Blocks(U256), - // Transactions filter holds the last set of tx hashes polled. - Transactions(BTreeSet), + // Transactions filter holds the latest unix time of evm tx hashes polled. + Transactions(Option), } // FilterCriteria encapsulates the arguments to the filter query, containing options @@ -171,8 +171,7 @@ impl FilterSystem { pub fn create_tx_filter(&mut self) -> usize { self.id = self.id.wrapping_add(1); - self.cache - .put(self.id, Filter::Transactions(BTreeSet::new())); + self.cache.put(self.id, Filter::Transactions(None)); self.id } @@ -188,7 +187,8 @@ impl FilterSystem { self.cache.pop(&filter_id).is_some() } - pub fn update_last_block(&mut self, filter_id: usize, last_block: U256) -> Result<()> { + // Update last block information for logs and blocks filter + pub fn update_filter_last_block(&mut self, filter_id: usize, last_block: U256) -> Result<()> { if let Some(entry) = self.cache.get_mut(&filter_id) { match entry { Filter::Logs(f) => f.last_block = Some(last_block), @@ -200,18 +200,39 @@ impl FilterSystem { Err(FilterError::FilterNotFound.into()) } } + + // Update last pending tx entry time for pending txs filter + pub fn update_filter_last_tx_time( + &mut self, + filter_id: usize, + last_entry_time: i64, + ) -> Result<()> { + if let Some(entry) = self.cache.get_mut(&filter_id) { + match entry { + Filter::Transactions(last_time) => { + *last_time = Some(last_entry_time); + Ok(()) + } + _ => Err(FilterError::InvalidFilter.into()), + } + } else { + Err(FilterError::FilterNotFound.into()) + } + } } pub struct FilterService { storage: Arc, + tx_cache: Arc, system: RwLock, } // Filter system methods impl FilterService { - pub fn new(storage: Arc) -> Self { + pub fn new(storage: Arc, tx_cache: Arc) -> Self { Self { storage, + tx_cache, system: RwLock::new(FilterSystem { id: 0, cache: LruCache::new(NonZeroUsize::new(FILTER_LRU_CACHE_DEFAULT_SIZE).unwrap()), @@ -248,8 +269,19 @@ impl FilterService { } } -// Filter methods +// Log filter methods impl FilterService { + /// Get logs from a specified block based on filter criteria. + /// + /// # Arguments + /// + /// * `criteria` - The log filter criteria + /// * `block_number` - The block number of the block to get the transaction logs from. + /// + /// # Returns + /// + /// Returns a vector of transaction logs. + /// pub fn get_block_logs( &self, criteria: &FilterCriteria, @@ -297,6 +329,16 @@ impl FilterService { Ok(logs) } + /// Get all transaction logs from a specified criteria. + /// + /// # Arguments + /// + /// * `criteria` - The log filter criteria + /// + /// # Returns + /// + /// Returns a vector of transaction logs. + /// pub fn get_logs_from_filter(&self, criteria: &FilterCriteria) -> Result> { if let Some(block_hash) = criteria.block_hash { let block_number = if let Some(block) = self.storage.get_block_by_hash(&block_hash)? { @@ -324,7 +366,19 @@ impl FilterService { } } - pub fn get_filter_logs_from_entry( + /// Get all transaction logs from a logs filter entry. + /// + /// # Arguments + /// + /// * `entry` - The log filter entry. + /// * `filter_change` - Flag to specify getting logs based on filter changes or criteria. + /// * `curr_block` - The current latest block number. + /// + /// # Returns + /// + /// Returns a vector of transaction logs. + /// + pub fn get_logs_filter_from_entry( &self, entry: LogsFilter, filter_change: bool, @@ -341,8 +395,22 @@ impl FilterService { } self.get_logs_from_filter(&criteria) } +} - pub fn get_filter_blocks_from_entry( +// Block and pending transactions filter methods +impl FilterService { + /// Get all new block hashes within the target block range of a block filter entry. + /// + /// # Arguments + /// + /// * `last_block` - The last queried block number of the block filter. + /// * `target_block` - The target block number of the block filter. + /// + /// # Returns + /// + /// Returns a vector of new block hash changes. + /// + pub fn get_blocks_filter_from_entry( &self, last_block: U256, target_block: U256, @@ -361,7 +429,67 @@ impl FilterService { Ok(out) } - pub fn get_filter_logs_from_id( + /// Get all new pending transaction hashes of a pending txs filter entry. + /// + /// # Arguments + /// + /// * `last_entry_time` - The last queried pending tx time that entered the tx mempool. + /// + /// # Returns + /// + /// Returns a vector of pending transaction hash changes. + /// + pub fn get_pending_txs_filter_from_entry( + &self, + last_entry_time: Option, + ) -> Result<(Vec, i64)> { + let last_entry_time = last_entry_time.unwrap_or_default(); + let mut pool_txs = ain_cpp_imports::get_pool_transactions() + .map_err(|_| format_err!("Error getting pooled transactions"))?; + + // Discard pending txs that are above last entry time + let mut new_pool_txs = Vec::new(); + if let Some(index) = pool_txs + .iter() + .position(|pool_tx| pool_tx.entry_time > last_entry_time) + { + pool_txs.drain(..index); + new_pool_txs = pool_txs; + } + + // get new latest entry time + let entry_time = if let Some(last_tx) = new_pool_txs.last() { + last_tx.entry_time + } else { + 0 + }; + + let new_tx_hashes = new_pool_txs + .iter() + .flat_map(|pool_tx| { + self.tx_cache + .try_get_or_create(pool_tx.data.as_str()) + .map(|tx| tx.hash()) + }) + .collect(); + Ok((new_tx_hashes, entry_time)) + } +} + +// Filter service methods +impl FilterService { + /// Get the full transaction logs from the filter id. + /// + /// # Arguments + /// + /// * `filter_id` - The filter entry id. + /// * `curr_block` - The current latest block number. + /// + /// # Returns + /// + /// Returns a vector of transaction logs. + /// + pub fn get_logs_from_filter_id( &self, filter_id: usize, curr_block: U256, @@ -369,13 +497,26 @@ impl FilterService { let mut system = self.system.write().unwrap(); let entry = system.get_filter(filter_id)?; if let Filter::Logs(entry) = entry { - self.get_filter_logs_from_entry(entry, false, curr_block) + self.get_logs_filter_from_entry(entry, false, curr_block) } else { Err(FilterError::InvalidFilter.into()) } } - pub fn get_filter_changes_from_id( + /// Get filter changes from the filter id. + /// + /// # Arguments + /// + /// * `filter_id` - The filter entry id. + /// * `curr_block` - The current latest block number. + /// + /// # Returns + /// + /// Returns a vector of transaction logs if logs filter entry. + /// Returns a vector of new block hash changes if blocks filter entry. + /// Returns a vector of transaction logs if pending transactions filter entry. + /// + pub fn get_changes_from_filter_id( &self, filter_id: usize, curr_block: U256, @@ -384,16 +525,21 @@ impl FilterService { let entry = system.get_filter(filter_id)?; match entry { Filter::Logs(entry) => { - let out = self.get_filter_logs_from_entry(entry, true, curr_block)?; - system.update_last_block(filter_id, curr_block)?; + let out = self.get_logs_filter_from_entry(entry, true, curr_block)?; + system.update_filter_last_block(filter_id, curr_block)?; Ok(FilterResults::Logs(out)) } Filter::Blocks(last_block) => { - let out = self.get_filter_blocks_from_entry(last_block, curr_block)?; - system.update_last_block(filter_id, curr_block)?; + let out = self.get_blocks_filter_from_entry(last_block, curr_block)?; + system.update_filter_last_block(filter_id, curr_block)?; Ok(FilterResults::Blocks(out)) } - Filter::Transactions(_) => Ok(FilterResults::Transactions(vec![])), + Filter::Transactions(last_entry_time) => { + let (out, curr_entry_time) = + self.get_pending_txs_filter_from_entry(last_entry_time)?; + system.update_filter_last_tx_time(filter_id, curr_entry_time)?; + Ok(FilterResults::Transactions(out)) + } } } } diff --git a/lib/ain-evm/src/transaction/cache.rs b/lib/ain-evm/src/transaction/cache.rs new file mode 100644 index 00000000000..a26a43bdcda --- /dev/null +++ b/lib/ain-evm/src/transaction/cache.rs @@ -0,0 +1,116 @@ +use std::num::NonZeroUsize; + +use ethereum::{EnvelopedEncodable, TransactionV2}; +use ethereum_types::U256; +use log::debug; +use lru::LruCache; + +use crate::{transaction::SignedTx, Result}; + +#[derive(Debug, Default)] +pub struct TransactionCache { + pub signed_tx_cache: SignedTxCache, + pub tx_validation_cache: TxValidationCache, +} + +impl TransactionCache { + pub fn new() -> Self { + Self { + signed_tx_cache: SignedTxCache::default(), + tx_validation_cache: TxValidationCache::default(), + } + } +} + +/// Signed transactions cache methods +impl TransactionCache { + pub fn try_get_or_create(&self, key: &str) -> Result { + let mut guard = self.signed_tx_cache.inner.lock(); + debug!("[signed-tx-cache]::get: {}", key); + let res = guard.try_get_or_insert(key.to_string(), || { + debug!("[signed-tx-cache]::create {}", key); + SignedTx::try_from(key) + })?; + Ok(res.clone()) + } + + pub fn pre_populate(&self, key: &str, signed_tx: SignedTx) -> Result<()> { + let mut guard = self.signed_tx_cache.inner.lock(); + debug!("[signed-tx-cache]::pre_populate: {}", key); + let _ = guard.get_or_insert(key.to_string(), move || { + debug!("[signed-tx-cache]::pre_populate:: create {}", key); + signed_tx + }); + + Ok(()) + } + + pub fn try_get_or_create_from_tx(&self, tx: &TransactionV2) -> Result { + let data = EnvelopedEncodable::encode(tx); + let key = hex::encode(&data); + let mut guard = self.signed_tx_cache.inner.lock(); + debug!("[signed-tx-cache]::get from tx: {}", &key); + let res = guard.try_get_or_insert(key.clone(), || { + debug!("[signed-tx-cache]::create from tx {}", &key); + SignedTx::try_from(key.as_str()) + })?; + Ok(res.clone()) + } +} + +/// Transaction validation cache methods +impl TransactionCache { + pub fn get_stateless(&self, key: &str) -> Option { + self.tx_validation_cache.stateless.lock().get(key).cloned() + } + + pub fn set_stateless(&self, key: String, value: ValidateTxInfo) -> ValidateTxInfo { + let mut cache = self.tx_validation_cache.stateless.lock(); + cache.put(key, value.clone()); + value + } +} + +#[derive(Debug)] +pub struct SignedTxCache { + inner: spin::Mutex>, +} + +impl Default for SignedTxCache { + fn default() -> Self { + Self::new(ain_cpp_imports::get_ecc_lru_cache_count()) + } +} + +impl SignedTxCache { + pub fn new(capacity: usize) -> Self { + Self { + inner: spin::Mutex::new(LruCache::new(NonZeroUsize::new(capacity).unwrap())), + } + } +} + +#[derive(Clone, Debug)] +pub struct ValidateTxInfo { + pub signed_tx: SignedTx, + pub max_prepay_fee: U256, +} + +#[derive(Debug)] +pub struct TxValidationCache { + stateless: spin::Mutex>, +} + +impl Default for TxValidationCache { + fn default() -> Self { + Self::new(ain_cpp_imports::get_evmv_lru_cache_count()) + } +} + +impl TxValidationCache { + pub fn new(capacity: usize) -> Self { + Self { + stateless: spin::Mutex::new(LruCache::new(NonZeroUsize::new(capacity).unwrap())), + } + } +} diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 4b3f93a0c8b..38093d2bad6 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -1,3 +1,4 @@ +pub mod cache; pub mod system; use anyhow::format_err; diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 2c6b9c4b9f3..79fa3a73f60 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -724,7 +724,7 @@ impl MetachainRPCServer for MetachainRPCModule { let signed_tx: SignedTx = self .handler .core - .signed_tx_cache + .tx_cache .try_get_or_create(raw_tx) .map_err(RPCError::EvmError)?; @@ -1102,13 +1102,17 @@ impl MetachainRPCServer for MetachainRPCModule { .into()) } + fn new_pending_transaction_filter(&self) -> RpcResult { + Ok(self.handler.filters.create_tx_filter().into()) + } + fn get_filter_changes(&self, filter_id: U256) -> RpcResult { let filter_id = usize::try_from(filter_id).map_err(to_custom_err)?; let curr_block = self.get_block(Some(BlockNumber::Latest))?.header.number; let res = self .handler .filters - .get_filter_changes_from_id(filter_id, curr_block) + .get_changes_from_filter_id(filter_id, curr_block) .map_err(RPCError::EvmError)? .into(); Ok(res) @@ -1125,14 +1129,10 @@ impl MetachainRPCServer for MetachainRPCModule { let logs = self .handler .filters - .get_filter_logs_from_id(filter_id, curr_block) + .get_logs_from_filter_id(filter_id, curr_block) .map_err(RPCError::EvmError)?; Ok(logs.into_iter().map(|log| log.into()).collect()) } - - fn new_pending_transaction_filter(&self) -> RpcResult { - Ok(self.handler.filters.create_tx_filter().into()) - } } fn sign(address: H160, message: TransactionMessage) -> RpcResult { diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index cf44382ffa2..0f2c470e1b1 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -281,11 +281,7 @@ fn evm_try_unsafe_add_balance_in_template( raw_tx: &str, native_hash: &str, ) -> Result<()> { - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; let native_hash = XHash::from(native_hash); let exec_tx = ExecuteTx::SystemTx(SystemTx::TransferDomain(TransferDomainData { @@ -312,11 +308,7 @@ fn evm_try_unsafe_sub_balance_in_template( raw_tx: &str, native_hash: &str, ) -> Result { - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; let native_hash = XHash::from(native_hash); let exec_tx = ExecuteTx::SystemTx(SystemTx::TransferDomain(TransferDomainData { @@ -511,11 +503,7 @@ fn evm_try_unsafe_push_tx_in_template( let native_hash = native_hash.to_string(); unsafe { - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; let tx_hash = signed_tx.hash(); SERVICES.evm.push_tx_in_block_template( @@ -671,11 +659,7 @@ fn evm_try_get_tx_by_hash(tx_hash: &str) -> Result { .get_transaction_by_hash(&tx_hash)? .ok_or("Unable to get evm tx from tx hash")?; - let tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create_from_tx(&tx)?; + let tx = SERVICES.evm.core.tx_cache.try_get_or_create_from_tx(&tx)?; let nonce = u64::try_from(tx.nonce())?; let gas_limit = u64::try_from(tx.gas_limit())?; @@ -756,11 +740,7 @@ fn evm_try_unsafe_bridge_dst20( ) -> Result<()> { let native_hash = XHash::from(native_hash); let contract_address = ain_contracts::dst20_address_from_token_id(token_id)?; - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; let system_tx = ExecuteTx::SystemTx(SystemTx::DST20Bridge(DST20Data { signed_tx: Box::new(signed_tx), contract_address, @@ -784,11 +764,7 @@ fn evm_try_unsafe_bridge_dst20( /// Returns the transaction's hash #[ffi_fallible] fn evm_try_get_tx_hash(raw_tx: &str) -> Result { - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; Ok(format!("{:?}", signed_tx.hash())) } @@ -804,7 +780,7 @@ fn evm_try_unsafe_cache_signed_tx(raw_tx: &str, instance: usize) -> Result<()> { SERVICES .evm .core - .signed_tx_cache + .tx_cache .pre_populate(raw_tx, *signed_tx)?; Ok(()) } @@ -836,10 +812,7 @@ fn evm_try_unsafe_is_smart_contract_in_template( fn evm_try_get_tx_miner_info_from_raw_tx(raw_tx: &str, mnview_ptr: usize) -> Result { let evm_services = &SERVICES.evm; - let signed_tx = evm_services - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = evm_services.core.tx_cache.try_get_or_create(raw_tx)?; let block_service = &evm_services.block; let attrs = block_service.get_attribute_vals(Some(mnview_ptr)); @@ -864,11 +837,7 @@ fn evm_try_get_tx_miner_info_from_raw_tx(raw_tx: &str, mnview_ptr: usize) -> Res #[ffi_fallible] fn evm_try_dispatch_pending_transactions_event(raw_tx: &str) -> Result<()> { - let signed_tx = SERVICES - .evm - .core - .signed_tx_cache - .try_get_or_create(raw_tx)?; + let signed_tx = SERVICES.evm.core.tx_cache.try_get_or_create(raw_tx)?; debug!( "[evm_try_dispatch_pending_transactions_event] {:#?}", diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index c9a60052efb..6f68b3b00a3 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -139,7 +139,7 @@ std::array getChainWork(std::array blockHash) { } rust::vec getPoolTransactions() { - std::multimap poolTransactionsByFee; + std::multimap poolTransactionsByEntryTime; for (auto mi = mempool.mapTx.get().begin(); mi != mempool.mapTx.get().end(); ++mi) { const auto &tx = mi->GetTx(); @@ -155,12 +155,13 @@ rust::vec getPoolTransactions() { } const auto obj = std::get(txMessage); - poolTransactionsByFee.emplace(mi->GetEVMRbfMinTipFee(), - TransactionData{ - static_cast(TransactionDataTxType::EVM), - HexStr(obj.evmTx), - static_cast(TransactionDataDirection::None), - }); + poolTransactionsByEntryTime.emplace(mi->GetTime(), + TransactionData{ + static_cast(TransactionDataTxType::EVM), + HexStr(obj.evmTx), + static_cast(TransactionDataDirection::None), + mi->GetTime(), + }); } else if (txType == CustomTxType::TransferDomain) { CCustomTxMessage txMessage{CTransferDomainMessage{}}; const auto res = @@ -176,26 +177,28 @@ rust::vec getPoolTransactions() { if (obj.transfers[0].first.domain == static_cast(VMDomain::DVM) && obj.transfers[0].second.domain == static_cast(VMDomain::EVM)) { - poolTransactionsByFee.emplace(mi->GetEVMRbfMinTipFee(), - TransactionData{ - static_cast(TransactionDataTxType::TransferDomain), - HexStr(obj.transfers[0].second.data), - static_cast(TransactionDataDirection::DVMToEVM), - }); + poolTransactionsByEntryTime.emplace(mi->GetTime(), + TransactionData{ + static_cast(TransactionDataTxType::TransferDomain), + HexStr(obj.transfers[0].second.data), + static_cast(TransactionDataDirection::DVMToEVM), + mi->GetTime(), + }); } else if (obj.transfers[0].first.domain == static_cast(VMDomain::EVM) && obj.transfers[0].second.domain == static_cast(VMDomain::DVM)) { - poolTransactionsByFee.emplace(mi->GetEVMRbfMinTipFee(), - TransactionData{ - static_cast(TransactionDataTxType::TransferDomain), - HexStr(obj.transfers[0].first.data), - static_cast(TransactionDataDirection::EVMToDVM), - }); + poolTransactionsByEntryTime.emplace(mi->GetTime(), + TransactionData{ + static_cast(TransactionDataTxType::TransferDomain), + HexStr(obj.transfers[0].first.data), + static_cast(TransactionDataDirection::EVMToDVM), + mi->GetTime(), + }); } } } rust::vec poolTransactions; - for (const auto &[key, txData] : poolTransactionsByFee) { + for (const auto &[key, txData] : poolTransactionsByEntryTime) { poolTransactions.push_back(txData); } diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index 9e247eece76..d1dd6c7c6b1 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -47,6 +47,7 @@ struct TransactionData { uint8_t txType; rust::string data; uint8_t direction; + int64_t entryTime; }; enum class TransactionDataTxType : uint8_t {