diff --git a/client/rpc-core/Cargo.toml b/client/rpc-core/Cargo.toml index 7f555e6e33..aeafd4acaa 100644 --- a/client/rpc-core/Cargo.toml +++ b/client/rpc-core/Cargo.toml @@ -17,3 +17,6 @@ jsonrpsee = { workspace = true, features = ["server", "macros"] } rustc-hex = "2.1.0" serde = { workspace = true } serde_json = { workspace = true } + +[features] +txpool = [] diff --git a/client/rpc-core/src/lib.rs b/client/rpc-core/src/lib.rs index c5728a8e7e..7f29588ba8 100644 --- a/client/rpc-core/src/lib.rs +++ b/client/rpc-core/src/lib.rs @@ -23,13 +23,15 @@ pub mod types; mod eth; mod eth_pubsub; mod net; +#[cfg(feature = "txpool")] mod txpool; mod web3; +#[cfg(feature = "txpool")] +pub use self::txpool::TxPoolApiServer; pub use self::{ eth::{EthApiServer, EthFilterApiServer}, eth_pubsub::EthPubSubApiServer, net::NetApiServer, - txpool::TxPoolApiServer, web3::Web3ApiServer, }; diff --git a/client/rpc-core/src/types/call_request.rs b/client/rpc-core/src/types/call_request.rs index b699e0aea1..96d151a71a 100644 --- a/client/rpc-core/src/types/call_request.rs +++ b/client/rpc-core/src/types/call_request.rs @@ -18,11 +18,12 @@ use std::collections::BTreeMap; -use crate::types::{deserialize_data_or_input, Bytes}; use ethereum::AccessListItem; use ethereum_types::{H160, H256, U256}; use serde::Deserialize; +use crate::types::{deserialize_data_or_input, Bytes}; + /// Call request #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] diff --git a/client/rpc-core/src/types/mod.rs b/client/rpc-core/src/types/mod.rs index eb9fccbc0b..e5a7981cf1 100644 --- a/client/rpc-core/src/types/mod.rs +++ b/client/rpc-core/src/types/mod.rs @@ -31,6 +31,7 @@ mod receipt; mod sync; mod transaction; mod transaction_request; +#[cfg(feature = "txpool")] mod txpool; mod work; @@ -38,6 +39,8 @@ pub mod pubsub; use serde::{de::Error, Deserialize, Deserializer}; +#[cfg(feature = "txpool")] +pub use self::txpool::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}; pub use self::{ account_info::{AccountInfo, EthAccount, ExtAccountInfo, RecoveredAccount, StorageProof}, block::{Block, BlockTransactions, Header, Rich, RichBlock, RichHeader}, @@ -58,7 +61,6 @@ pub use self::{ }, transaction::{LocalTransactionStatus, RichRawTransaction, Transaction}, transaction_request::{TransactionMessage, TransactionRequest}, - txpool::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, work::Work, }; diff --git a/client/rpc-core/src/types/txpool.rs b/client/rpc-core/src/types/txpool.rs index ed70f504ec..5fd9bcb31a 100644 --- a/client/rpc-core/src/types/txpool.rs +++ b/client/rpc-core/src/types/txpool.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; use ethereum_types::{H160, H256, U256}; use serde::{Serialize, Serializer}; -// Frontier + use crate::types::Bytes; pub type TransactionMap = HashMap>; diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 492844d60e..e08070e713 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -73,4 +73,5 @@ rocksdb = [ "fc-db/rocksdb", "fc-mapping-sync/rocksdb", ] +txpool = ["fc-rpc-core/txpool"] rpc-binary-search-estimate = [] diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 21bde32018..57e4051810 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -23,7 +23,8 @@ use ethereum_types::{H256, U256}; use jsonrpsee::core::{async_trait, RpcResult}; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; -use sc_transaction_pool::ChainApi; +use sc_transaction_pool::{ChainApi, Pool}; +use sc_transaction_pool_api::InPoolTransaction; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::hashing::keccak_256; @@ -35,12 +36,12 @@ use sp_runtime::{ use fc_rpc_core::{types::*, EthFilterApiServer}; use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus}; -use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; +use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err}; pub struct EthFilter { client: Arc, backend: Arc + Send + Sync>, - tx_pool: TxPool, + graph: Arc>, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -52,7 +53,7 @@ impl EthFilter { pub fn new( client: Arc, backend: Arc + Send + Sync>, - tx_pool: TxPool, + graph: Arc>, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -61,7 +62,7 @@ impl EthFilter { Self { client, backend, - tx_pool, + graph, filter_pool, max_stored_filters, max_past_logs, @@ -80,8 +81,9 @@ where A: ChainApi + 'static, { fn create_filter(&self, filter_type: FilterType) -> RpcResult { - let block_number = - UniqueSaturatedInto::::unique_saturated_into(self.client.info().best_number); + let info = self.client.info(); + let best_hash = info.best_hash; + let best_number = UniqueSaturatedInto::::unique_saturated_into(info.best_number); let pool = self.filter_pool.clone(); let response = if let Ok(locked) = &mut pool.lock() { if locked.len() >= self.max_stored_filters { @@ -97,24 +99,35 @@ where Some((k, _)) => *k, None => U256::zero(), }; + let pending_transaction_hashes = if let FilterType::PendingTransaction = filter_type { - self.tx_pool - .tx_pool_response()? - .ready + let txs_ready = self + .graph + .validated_pool() + .ready() + .map(|in_pool_tx| in_pool_tx.data().clone()) + .collect(); + // Use the runtime to match the (here) opaque extrinsics against ethereum transactions. + let api = self.client.runtime_api(); + api.extrinsic_filter(best_hash, txs_ready) + .map_err(|err| { + internal_err(format!("fetch ready transactions failed: {err:?}")) + })? .into_iter() .map(|tx| tx.hash()) - .collect() + .collect::>() } else { HashSet::new() }; + // Assume `max_stored_filters` is always < U256::max. let key = last_key.checked_add(U256::one()).unwrap(); locked.insert( key, FilterPoolItem { - last_poll: BlockNumber::Num(block_number), + last_poll: BlockNumber::Num(best_number), filter_type, - at_block: block_number, + at_block: best_number, pending_transaction_hashes, }, ); @@ -174,8 +187,9 @@ where } let key = U256::from(index.value()); - let block_number = - UniqueSaturatedInto::::unique_saturated_into(self.client.info().best_number); + let info = self.client.info(); + let best_hash = info.best_hash; + let best_number = UniqueSaturatedInto::::unique_saturated_into(info.best_number); let pool = self.filter_pool.clone(); // Try to lock. let path = if let Ok(locked) = &mut pool.lock() { @@ -185,7 +199,7 @@ where // For each block created since last poll, get a vector of ethereum hashes. FilterType::Block => { let last = pool_item.last_poll.to_min_block_num().unwrap(); - let next = block_number + 1; + let next = best_number + 1; // Update filter `last_poll`. locked.insert( key, @@ -201,19 +215,28 @@ where } FilterType::PendingTransaction => { let previous_hashes = pool_item.pending_transaction_hashes; - let current_hashes: HashSet = self - .tx_pool - .tx_pool_response()? - .ready + let txs_ready = self + .graph + .validated_pool() + .ready() + .map(|in_pool_tx| in_pool_tx.data().clone()) + .collect(); + // Use the runtime to match the (here) opaque extrinsics against ethereum transactions. + let api = self.client.runtime_api(); + let current_hashes = api + .extrinsic_filter(best_hash, txs_ready) + .map_err(|err| { + internal_err(format!("fetch ready transactions failed: {err:?}")) + })? .into_iter() .map(|tx| tx.hash()) - .collect(); + .collect::>(); // Update filter `last_poll`. locked.insert( key, FilterPoolItem { - last_poll: BlockNumber::Num(block_number + 1), + last_poll: BlockNumber::Num(best_number + 1), filter_type: pool_item.filter_type.clone(), at_block: pool_item.at_block, pending_transaction_hashes: current_hashes.clone(), @@ -233,7 +256,7 @@ where locked.insert( key, FilterPoolItem { - last_poll: BlockNumber::Num(block_number + 1), + last_poll: BlockNumber::Num(best_number + 1), filter_type: pool_item.filter_type.clone(), at_block: pool_item.at_block, pending_transaction_hashes: HashSet::new(), diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index c9e78b379c..9964cad1e4 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -30,22 +30,24 @@ mod eth; mod eth_pubsub; mod net; mod signer; +#[cfg(feature = "txpool")] mod txpool; mod web3; +#[cfg(feature = "txpool")] +pub use self::txpool::TxPool; pub use self::{ eth::{format, EstimateGasAdapter, Eth, EthBlockDataCacheTask, EthConfig, EthFilter, EthTask}, eth_pubsub::{EthPubSub, EthereumSubIdProvider}, net::Net, signer::{EthDevSigner, EthSigner}, - txpool::TxPool, web3::Web3, }; - pub use ethereum::TransactionV2 as EthereumTransaction; +#[cfg(feature = "txpool")] +pub use fc_rpc_core::TxPoolApiServer; pub use fc_rpc_core::{ - EthApiServer, EthFilterApiServer, EthPubSubApiServer, NetApiServer, TxPoolApiServer, - Web3ApiServer, + EthApiServer, EthFilterApiServer, EthPubSubApiServer, NetApiServer, Web3ApiServer, }; pub use fc_storage::{ OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override, diff --git a/template/node/Cargo.toml b/template/node/Cargo.toml index 1a641e9cfc..d389cea3c3 100644 --- a/template/node/Cargo.toml +++ b/template/node/Cargo.toml @@ -89,6 +89,7 @@ default = [ "with-rocksdb-weights", "rocksdb", "sql", + "txpool", ] rocksdb = [ "sc-cli/rocksdb", @@ -104,6 +105,7 @@ sql = [ ] with-rocksdb-weights = ["frontier-template-runtime/with-rocksdb-weights"] with-paritydb-weights = ["frontier-template-runtime/with-paritydb-weights"] +txpool = ["fc-rpc/txpool"] rpc-binary-search-estimate = ["fc-rpc/rpc-binary-search-estimate"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 2117cc6ba7..b019fa2e33 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -17,7 +17,7 @@ use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::H256; use sp_runtime::traits::Block as BlockT; // Frontier -pub use fc_rpc::{EthBlockDataCacheTask, EthConfig, OverrideHandle, StorageOverride, TxPool}; +pub use fc_rpc::{EthBlockDataCacheTask, EthConfig, OverrideHandle, StorageOverride}; pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool}; pub use fc_storage::overrides_handle; use fp_rpc::{ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi}; @@ -109,8 +109,10 @@ where { use fc_rpc::{ Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, - EthPubSubApiServer, EthSigner, Net, NetApiServer, TxPoolApiServer, Web3, Web3ApiServer, + EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, }; + #[cfg(feature = "txpool")] + use fc_rpc::{TxPool, TxPoolApiServer}; let EthDeps { client, @@ -158,13 +160,12 @@ where .into_rpc(), )?; - let tx_pool = TxPool::new(client.clone(), graph); if let Some(filter_pool) = filter_pool { io.merge( EthFilter::new( client.clone(), frontier_backend, - tx_pool.clone(), + graph.clone(), filter_pool, 500_usize, // max stored filters max_past_logs, @@ -196,8 +197,10 @@ where .into_rpc(), )?; - io.merge(Web3::new(client).into_rpc())?; - io.merge(tx_pool.into_rpc())?; + io.merge(Web3::new(client.clone()).into_rpc())?; + + #[cfg(feature = "txpool")] + io.merge(TxPool::new(client, graph).into_rpc())?; Ok(io) }