From 9caf5563559ac38c96a3c40b7b8c406ede39a0fc Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 7 Jun 2023 14:32:18 +0800 Subject: [PATCH 01/17] Add new filter type --- client/rpc/src/eth/filter.rs | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 593d4c2b71..76f27e9a0c 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -23,6 +23,7 @@ use ethereum_types::{H256, U256}; use jsonrpsee::core::{async_trait, RpcResult}; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; +use sc_transaction_pool::{ChainApi, Pool}; use sp_api::ProvideRuntimeApi; use sp_blockchain::HeaderBackend; use sp_core::hashing::keccak_256; @@ -36,9 +37,10 @@ use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus}; use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err}; -pub struct EthFilter { +pub struct EthFilter { client: Arc, backend: Arc + Send + Sync>, + graph: Arc>, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -46,10 +48,11 @@ pub struct EthFilter { _marker: PhantomData, } -impl EthFilter { +impl EthFilter { pub fn new( client: Arc, backend: Arc + Send + Sync>, + graph: Arc>, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -58,6 +61,7 @@ impl EthFilter { Self { client, backend, + graph, filter_pool, max_stored_filters, max_past_logs, @@ -67,8 +71,9 @@ impl EthFilter { } } -impl EthFilter +impl EthFilter where + A: ChainApi, B: BlockT, C: HeaderBackend, { @@ -106,11 +111,26 @@ where }; response } + + fn pending_transactions(&self) -> RpcResult> { + let txs_ready = self + .graph + .validated_pool() + .ready() + .map(|in_pool_tx| in_pool_tx.data().clone()) + .collect(); + + todo!(); + // let txs_pending = txs_ready.into_iter().filter_map(|xt| match xt.0.function { + // RuntimeCall + // }) + } } #[async_trait] -impl EthFilterApiServer for EthFilter +impl EthFilterApiServer for EthFilter where + A: ChainApi + 'static, B: BlockT, C: ProvideRuntimeApi, C::Api: EthereumRuntimeRPCApi, @@ -126,7 +146,7 @@ where } fn new_pending_transaction_filter(&self) -> RpcResult { - Err(internal_err("Method not available.")) + self.create_filter(FilterType::PendingTransaction) } async fn filter_changes(&self, index: Index) -> RpcResult { From 6d90da681ce0dec4e349c65688f962835d76218b Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 7 Jun 2023 15:18:10 +0800 Subject: [PATCH 02/17] Add txpool client side --- Cargo.lock | 2 + client/rpc-core/src/lib.rs | 2 + client/rpc-core/src/txpool.rs | 36 ++++++ client/rpc-core/src/types/mod.rs | 2 + client/rpc-core/src/types/txpool.rs | 170 +++++++++++++++++++++++++ client/rpc/Cargo.toml | 2 + client/rpc/src/eth/filter.rs | 26 ++-- client/rpc/src/lib.rs | 1 + client/rpc/src/txpool.rs | 184 ++++++++++++++++++++++++++++ primitives/rpc/src/lib.rs | 25 ++++ 10 files changed, 437 insertions(+), 13 deletions(-) create mode 100644 client/rpc-core/src/txpool.rs create mode 100644 client/rpc-core/src/types/txpool.rs create mode 100644 client/rpc/src/txpool.rs diff --git a/Cargo.lock b/Cargo.lock index 9dc7aeb3f4..674cf9b17c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2228,6 +2228,8 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", + "serde", + "sha3", "sp-api", "sp-block-builder", "sp-blockchain", diff --git a/client/rpc-core/src/lib.rs b/client/rpc-core/src/lib.rs index 701c095e2f..d5bc8fc8a5 100644 --- a/client/rpc-core/src/lib.rs +++ b/client/rpc-core/src/lib.rs @@ -23,6 +23,7 @@ pub mod types; mod eth; mod eth_pubsub; mod net; +mod txpool; mod web3; pub use self::{ @@ -30,4 +31,5 @@ pub use self::{ eth_pubsub::EthPubSubApiServer, net::NetApiServer, web3::Web3ApiServer, + txpool::TxPoolApiServer, }; diff --git a/client/rpc-core/src/txpool.rs b/client/rpc-core/src/txpool.rs new file mode 100644 index 0000000000..e5bdca20ee --- /dev/null +++ b/client/rpc-core/src/txpool.rs @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2015-2022 Parity Technologies (UK) Ltd. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! tx pool rpc interface + +use crate::types::*; +use ethereum_types::U256; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; + +/// TxPool rpc interface +#[rpc(server)] +pub trait TxPoolApi { + #[method(name = "txpool_content")] + fn content(&self) -> RpcResult>>; + + #[method(name = "txpool_inspect")] + fn inspect(&self) -> RpcResult>>; + + #[method(name = "txpool_status")] + fn status(&self) -> RpcResult>; +} diff --git a/client/rpc-core/src/types/mod.rs b/client/rpc-core/src/types/mod.rs index 4384415428..62ce7b5a52 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; +mod txpool; mod work; pub mod pubsub; @@ -55,5 +56,6 @@ pub use self::{ }, transaction::{LocalTransactionStatus, RichRawTransaction, Transaction}, transaction_request::{TransactionMessage, TransactionRequest}, + txpool::{Summary, TransactionMap, TxPoolResult, Get, TxPoolTransaction}, work::Work, }; diff --git a/client/rpc-core/src/types/txpool.rs b/client/rpc-core/src/types/txpool.rs new file mode 100644 index 0000000000..b84164a994 --- /dev/null +++ b/client/rpc-core/src/types/txpool.rs @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2015-2022 Parity Technologies (UK) Ltd. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; +use ethereum_types::{H160, H256, U256}; +use serde::{Serialize, Serializer}; +use crate::types::Bytes; +use std::collections::HashMap; + +pub type TransactionMap = HashMap>; + +pub trait Get { + fn get(hash: H256, from_address: H160, txn: &EthereumTransaction) -> Self; +} + +#[derive(Debug, Serialize)] +pub struct TxPoolResult { + pub pending: T, + pub queued: T, +} + +#[derive(Clone, Debug)] +pub struct Summary { + pub to: Option, + pub value: U256, + pub gas: U256, + pub gas_price: U256, +} + +impl Serialize for Summary { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let res = format!( + "0x{:x}: {} wei + {} gas x {} wei", + self.to.unwrap_or_default(), + self.value, + self.gas, + self.gas_price + ); + serializer.serialize_str(&res) + } +} + +impl Get for Summary { + fn get(_hash: H256, _from_address: H160, txn: &EthereumTransaction) -> Self { + let (action, value, gas_price, gas_limit) = match txn { + EthereumTransaction::Legacy(t) => (t.action, t.value, t.gas_price, t.gas_limit), + EthereumTransaction::EIP2930(t) => (t.action, t.value, t.gas_price, t.gas_limit), + EthereumTransaction::EIP1559(t) => (t.action, t.value, t.max_fee_per_gas, t.gas_limit), + }; + Self { + to: match action { + TransactionAction::Call(to) => Some(to), + _ => None, + }, + value, + gas_price, + gas: gas_limit, + } + } +} + +#[derive(Debug, Default, Clone, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TxPoolTransaction { + /// Hash + pub hash: H256, + /// Nonce + pub nonce: U256, + /// Block hash + #[serde(serialize_with = "block_hash_serialize")] + pub block_hash: Option, + /// Block number + pub block_number: Option, + /// Sender + pub from: H160, + /// Recipient + #[serde(serialize_with = "to_serialize")] + pub to: Option, + /// Transfered value + pub value: U256, + /// Gas Price + pub gas_price: U256, + /// Gas + pub gas: U256, + /// Data + pub input: Bytes, + /// Transaction Index + pub transaction_index: Option, +} + +fn block_hash_serialize(hash: &Option, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_str(&format!("0x{:x}", hash.unwrap_or_default())) +} + +fn to_serialize(hash: &Option, serializer: S) -> Result +where + S: Serializer, +{ + serializer.serialize_str(&format!("0x{:x}", hash.unwrap_or_default())) +} + +impl Get for TxPoolTransaction { + fn get(hash: H256, from_address: H160, txn: &EthereumTransaction) -> Self { + let (nonce, action, value, gas_price, gas_limit, input) = match txn { + EthereumTransaction::Legacy(t) => ( + t.nonce, + t.action, + t.value, + t.gas_price, + t.gas_limit, + t.input.clone(), + ), + EthereumTransaction::EIP2930(t) => ( + t.nonce, + t.action, + t.value, + t.gas_price, + t.gas_limit, + t.input.clone(), + ), + EthereumTransaction::EIP1559(t) => ( + t.nonce, + t.action, + t.value, + t.max_fee_per_gas, + t.gas_limit, + t.input.clone(), + ), + }; + Self { + hash, + nonce, + block_hash: None, + block_number: None, + from: from_address, + to: match action { + TransactionAction::Call(to) => Some(to), + _ => None, + }, + value, + gas_price, + gas: gas_limit, + input: Bytes(input), + transaction_index: None, + } + } +} + + diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 820bdbb4ed..29c579fe5e 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -24,6 +24,8 @@ prometheus = { version = "0.13.1", default-features = false } rand = "0.8" rlp = { workspace = true } scale-codec = { package = "parity-scale-codec", workspace = true } +serde = { workspace = true } +sha3 = { version = "0.10" } tokio = { version = "1.24", features = ["sync"] } # Substrate diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 76f27e9a0c..ef0dfc86b4 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -112,19 +112,19 @@ where response } - fn pending_transactions(&self) -> RpcResult> { - let txs_ready = self - .graph - .validated_pool() - .ready() - .map(|in_pool_tx| in_pool_tx.data().clone()) - .collect(); - - todo!(); - // let txs_pending = txs_ready.into_iter().filter_map(|xt| match xt.0.function { - // RuntimeCall - // }) - } + // fn pending_transactions(&self) -> RpcResult> { + // let txs_ready = self + // .graph + // .validated_pool() + // .ready() + // .map(|in_pool_tx| in_pool_tx.data().clone()) + // .collect(); + + // todo!(); + // // let txs_pending = txs_ready.into_iter().filter_map(|xt| match xt.0.function { + // // RuntimeCall + // // }) + // } } #[async_trait] diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 2cc91cc820..0bb371b883 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -30,6 +30,7 @@ mod eth; mod eth_pubsub; mod net; mod signer; +mod txpool; mod web3; pub use self::{ diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs new file mode 100644 index 0000000000..02606e1742 --- /dev/null +++ b/client/rpc/src/txpool.rs @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 +// This file is part of Frontier. +// +// Copyright (c) 2020-2022 Parity Technologies (UK) Ltd. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use crate::{internal_err, public_key}; +use ethereum::TransactionV2; +use ethereum_types::{H160, H256, U256}; +use fc_rpc_core::{ + types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, + TxPoolApiServer, +}; +use fp_rpc::{TxPoolResponse, TxPoolRuntimeApi}; +use jsonrpsee::core::RpcResult; +use serde::Serialize; +use sha3::{Digest, Keccak256}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc}; +// substrate +use sc_transaction_pool::{ChainApi, Pool}; +use sc_transaction_pool_api::InPoolTransaction; +use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_runtime::traits::Block as BlockT; + +pub struct TxPool { + client: Arc, + graph: Arc>, + _marker: PhantomData, +} + +impl TxPool +where + C: ProvideRuntimeApi, + C: HeaderMetadata + HeaderBackend + 'static, + C: Send + Sync + 'static, + B: BlockT + Send + Sync + 'static, + A: ChainApi + 'static, + C::Api: TxPoolRuntimeApi, +{ + /// Use the transaction graph interface to get the extrinsics currently in the ready and future + /// queues. + fn map_build(&self) -> RpcResult>> + where + T: Get + Serialize, + { + // Collect transactions in the ready validated pool. + let txs_ready = self + .graph + .validated_pool() + .ready() + .map(|in_pool_tx| in_pool_tx.data().clone()) + .collect(); + + // Collect transactions in the future validated pool. + let txs_future = self + .graph + .validated_pool() + .futures() + .iter() + .map(|(_hash, extrinsic)| extrinsic.clone()) + .collect(); + + // Use the runtime to match the (here) opaque extrinsics against ethereum transactions. + let best_block = self.client.info().best_hash; + let api = self.client.runtime_api(); + let api_version = + if let Ok(Some(api_version)) = api.api_version::>(best_block) { + api_version + } else { + return Err(internal_err( + "failed to retrieve Runtime Api version".to_string(), + )); + }; + let ethereum_txns: TxPoolResponse = if api_version == 1 { + #[allow(deprecated)] + let res = api.extrinsic_filter_before_version_2(best_block, txs_ready, txs_future) + .map_err(|err| { + internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err)) + })?; + TxPoolResponse { + ready: res + .ready + .iter() + .map(|t| TransactionV2::Legacy(t.clone())) + .collect(), + future: res + .future + .iter() + .map(|t| TransactionV2::Legacy(t.clone())) + .collect(), + } + } else { + api.extrinsic_filter(best_block, txs_ready, txs_future) + .map_err(|err| { + internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err)) + })? + }; + // Build the T response. + let mut pending = TransactionMap::::new(); + for txn in ethereum_txns.ready.iter() { + let hash = txn.hash(); + let nonce = match txn { + TransactionV2::Legacy(t) => t.nonce, + TransactionV2::EIP2930(t) => t.nonce, + TransactionV2::EIP1559(t) => t.nonce, + }; + let from_address = match public_key(txn) { + Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Err(_e) => H160::default(), + }; + pending + .entry(from_address) + .or_insert_with(HashMap::new) + .insert(nonce, T::get(hash, from_address, txn)); + } + let mut queued = TransactionMap::::new(); + for txn in ethereum_txns.future.iter() { + let hash = txn.hash(); + let nonce = match txn { + TransactionV2::Legacy(t) => t.nonce, + TransactionV2::EIP2930(t) => t.nonce, + TransactionV2::EIP1559(t) => t.nonce, + }; + let from_address = match public_key(txn) { + Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Err(_e) => H160::default(), + }; + queued + .entry(from_address) + .or_insert_with(HashMap::new) + .insert(nonce, T::get(hash, from_address, txn)); + } + Ok(TxPoolResult { pending, queued }) + } +} + +impl TxPool { + pub fn new(client: Arc, graph: Arc>) -> Self { + Self { + client, + graph, + _marker: PhantomData, + } + } +} + +impl TxPoolApiServer for TxPool +where + C: ProvideRuntimeApi, + C: HeaderMetadata + HeaderBackend, + C: Send + Sync + 'static, + B: BlockT + Send + Sync + 'static, + A: ChainApi + 'static, + C::Api: TxPoolRuntimeApi, +{ + fn content(&self) -> RpcResult>> { + self.map_build::() + } + + fn inspect(&self) -> RpcResult>> { + self.map_build::() + } + + fn status(&self) -> RpcResult> { + let status = self.graph.validated_pool().status(); + Ok(TxPoolResult { + pending: U256::from(status.ready), + queued: U256::from(status.future), + }) + } +} diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index e00d447dd1..7c0f5b77aa 100644 --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -40,6 +40,18 @@ pub struct TransactionStatus { pub logs_bloom: Bloom, } +#[derive(Eq, PartialEq, Clone, Encode, Decode, sp_runtime::RuntimeDebug)] +pub struct TxPoolResponseLegacy { + pub ready: Vec, + pub future: Vec, +} + +#[derive(Eq, PartialEq, Clone, Encode, Decode, sp_runtime::RuntimeDebug)] +pub struct TxPoolResponse { + pub ready: Vec, + pub future: Vec, +} + pub trait RuntimeStorageOverride: Send + Sync { fn is_enabled() -> bool; @@ -215,6 +227,19 @@ sp_api::decl_runtime_apis! { #[changed_in(2)] fn convert_transaction(transaction: ethereum::TransactionV0) -> ::Extrinsic; } + + #[api_version(2)] + pub trait TxPoolRuntimeApi { + #[changed_in(2)] + fn extrinsic_filter( + xt_ready: Vec<::Extrinsic>, + xt_future: Vec<::Extrinsic>, + ) -> TxPoolResponseLegacy; + fn extrinsic_filter( + xt_ready: Vec<::Extrinsic>, + xt_future: Vec<::Extrinsic>, + ) -> TxPoolResponse; + } } pub trait ConvertTransaction { From 6c473f5857d6678ae688c6a2b0a674284fd2520d Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 7 Jun 2023 15:38:44 +0800 Subject: [PATCH 03/17] Fix node compile --- client/rpc-core/src/lib.rs | 2 +- client/rpc-core/src/types/mod.rs | 2 +- client/rpc-core/src/types/txpool.rs | 4 +--- template/node/src/eth.rs | 4 +++- template/node/src/rpc/eth.rs | 12 +++++++++--- template/node/src/rpc/mod.rs | 1 + template/runtime/src/lib.rs | 27 +++++++++++++++++++++++++++ 7 files changed, 43 insertions(+), 9 deletions(-) diff --git a/client/rpc-core/src/lib.rs b/client/rpc-core/src/lib.rs index d5bc8fc8a5..c5728a8e7e 100644 --- a/client/rpc-core/src/lib.rs +++ b/client/rpc-core/src/lib.rs @@ -30,6 +30,6 @@ pub use self::{ eth::{EthApiServer, EthFilterApiServer}, eth_pubsub::EthPubSubApiServer, net::NetApiServer, - web3::Web3ApiServer, txpool::TxPoolApiServer, + web3::Web3ApiServer, }; diff --git a/client/rpc-core/src/types/mod.rs b/client/rpc-core/src/types/mod.rs index 62ce7b5a52..98b6e5b417 100644 --- a/client/rpc-core/src/types/mod.rs +++ b/client/rpc-core/src/types/mod.rs @@ -56,6 +56,6 @@ pub use self::{ }, transaction::{LocalTransactionStatus, RichRawTransaction, Transaction}, transaction_request::{TransactionMessage, TransactionRequest}, - txpool::{Summary, TransactionMap, TxPoolResult, Get, TxPoolTransaction}, + 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 b84164a994..ef83123839 100644 --- a/client/rpc-core/src/types/txpool.rs +++ b/client/rpc-core/src/types/txpool.rs @@ -16,10 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::types::Bytes; use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; use ethereum_types::{H160, H256, U256}; use serde::{Serialize, Serializer}; -use crate::types::Bytes; use std::collections::HashMap; pub type TransactionMap = HashMap>; @@ -166,5 +166,3 @@ impl Get for TxPoolTransaction { } } } - - diff --git a/template/node/src/eth.rs b/template/node/src/eth.rs index 8f28a4b637..23b4ec7a7a 100644 --- a/template/node/src/eth.rs +++ b/template/node/src/eth.rs @@ -125,6 +125,7 @@ pub trait EthCompatRuntimeApiCollection: sp_api::ApiExt + fp_rpc::EthereumRuntimeRPCApi + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::TxPoolRuntimeApi where >::StateBackend: sp_api::StateBackend, { @@ -134,7 +135,8 @@ impl EthCompatRuntimeApiCollection for Api where Api: sp_api::ApiExt + fp_rpc::EthereumRuntimeRPCApi - + fp_rpc::ConvertTransactionRuntimeApi, + + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::TxPoolRuntimeApi, >::StateBackend: sp_api::StateBackend, { } diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 4adcb199d9..4fa53fae09 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -20,7 +20,9 @@ use sp_runtime::traits::Block as BlockT; 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}; +use fp_rpc::{ + ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi, TxPoolRuntimeApi, +}; /// Extra dependencies for Ethereum compatibility. pub struct EthDeps { @@ -99,7 +101,10 @@ pub fn create_eth>( where B: BlockT, C: CallApiAt + ProvideRuntimeApi, - C::Api: BlockBuilderApi + EthereumRuntimeRPCApi + ConvertTransactionRuntimeApi, + C::Api: BlockBuilderApi + + EthereumRuntimeRPCApi + + ConvertTransactionRuntimeApi + + TxPoolRuntimeApi, C: BlockchainEvents + 'static, C: HeaderBackend + HeaderMetadata + StorageProvider, BE: Backend + 'static, @@ -141,7 +146,7 @@ where Eth::new( client.clone(), pool.clone(), - graph, + graph.clone(), converter, sync.clone(), vec![], @@ -163,6 +168,7 @@ where EthFilter::new( client.clone(), frontier_backend, + graph.clone(), filter_pool, 500_usize, // max stored filters max_past_logs, diff --git a/template/node/src/rpc/mod.rs b/template/node/src/rpc/mod.rs index e1357ce716..559697b6dc 100644 --- a/template/node/src/rpc/mod.rs +++ b/template/node/src/rpc/mod.rs @@ -65,6 +65,7 @@ where C::Api: sp_block_builder::BlockBuilder, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: fp_rpc::ConvertTransactionRuntimeApi, + C::Api: fp_rpc::TxPoolRuntimeApi, C::Api: fp_rpc::EthereumRuntimeRPCApi, C: BlockchainEvents + 'static, C: HeaderBackend diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 59981a59a2..832562f4ac 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -769,6 +769,33 @@ impl_runtime_apis! { } } + impl fp_rpc::TxPoolRuntimeApi for Runtime { + fn extrinsic_filter( + xts_ready: Vec<::Extrinsic>, + xts_future: Vec<::Extrinsic>, + ) -> fp_rpc::TxPoolResponse { + // frontier + use pallet_ethereum::Call::transact; + + fp_rpc::TxPoolResponse { + ready: xts_ready + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + future: xts_future + .into_iter() + .filter_map(|xt| match xt.0.function { + RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), + _ => None, + }) + .collect(), + } + } + } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< Block, Balance, From a805411d1fd7d8f028df8c04a723044e63478ce9 Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 7 Jun 2023 15:44:32 +0800 Subject: [PATCH 04/17] Fix rpc --- client/rpc/src/lib.rs | 4 +++- template/node/src/rpc/eth.rs | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index 0bb371b883..bd4ec59689 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -38,11 +38,13 @@ pub use self::{ eth_pubsub::{EthPubSub, EthereumSubIdProvider}, net::Net, signer::{EthDevSigner, EthSigner}, + txpool::TxPool, web3::Web3, }; pub use ethereum::TransactionV2 as EthereumTransaction; pub use fc_rpc_core::{ - EthApiServer, EthFilterApiServer, EthPubSubApiServer, NetApiServer, Web3ApiServer, + EthApiServer, EthFilterApiServer, EthPubSubApiServer, NetApiServer, TxPoolApiServer, + Web3ApiServer, }; pub use fc_storage::{ OverrideHandle, RuntimeApiStorageOverride, SchemaV1Override, SchemaV2Override, diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 4fa53fae09..02914a1cf5 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}; +pub use fc_rpc::{EthBlockDataCacheTask, EthConfig, OverrideHandle, StorageOverride, TxPool}; pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool}; pub use fc_storage::overrides_handle; use fp_rpc::{ @@ -114,7 +114,7 @@ where { use fc_rpc::{ Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, - EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, + EthPubSubApiServer, EthSigner, Net, NetApiServer, TxPoolApiServer, Web3, Web3ApiServer, }; let EthDeps { @@ -200,7 +200,8 @@ where .into_rpc(), )?; - io.merge(Web3::new(client).into_rpc())?; + io.merge(Web3::new(client.clone()).into_rpc())?; + io.merge(TxPool::new(client, graph).into_rpc())?; Ok(io) } From 1d614a243f7cdf626a1ced3f125b652769e1903f Mon Sep 17 00:00:00 2001 From: bear Date: Wed, 7 Jun 2023 17:28:30 +0800 Subject: [PATCH 05/17] Dev filter_changes --- client/rpc-core/src/types/filter.rs | 3 +- client/rpc/src/eth/filter.rs | 88 ++++++++++++++++++---------- client/rpc/src/txpool.rs | 89 +++++++++++++++++------------ template/node/src/rpc/eth.rs | 5 +- 4 files changed, 117 insertions(+), 68 deletions(-) diff --git a/client/rpc-core/src/types/filter.rs b/client/rpc-core/src/types/filter.rs index 6fa1adfc46..4d7dd09a9a 100644 --- a/client/rpc-core/src/types/filter.rs +++ b/client/rpc-core/src/types/filter.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use std::{ - collections::BTreeMap, + collections::{BTreeMap, HashSet}, sync::{Arc, Mutex}, }; @@ -460,6 +460,7 @@ pub struct FilterPoolItem { pub last_poll: BlockNumber, pub filter_type: FilterType, pub at_block: u64, + pub pending_transaction_hashes: HashSet, } /// On-memory stored filters created through the `eth_newFilter` RPC. diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index ef0dfc86b4..a6adf924fb 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -16,16 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::{marker::PhantomData, sync::Arc, time}; +use std::{collections::HashSet, marker::PhantomData, sync::Arc, time}; use ethereum::BlockV2 as EthereumBlock; use ethereum_types::{H256, U256}; use jsonrpsee::core::{async_trait, RpcResult}; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; -use sc_transaction_pool::{ChainApi, Pool}; +use sc_transaction_pool::ChainApi; use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; +use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::hashing::keccak_256; use sp_runtime::{ generic::BlockId, @@ -33,14 +33,14 @@ use sp_runtime::{ }; // Frontier use fc_rpc_core::{types::*, EthFilterApiServer}; -use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus}; +use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; -use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err}; +use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; pub struct EthFilter { client: Arc, backend: Arc + Send + Sync>, - graph: Arc>, + tx_pool: TxPool, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -52,7 +52,7 @@ impl EthFilter { pub fn new( client: Arc, backend: Arc + Send + Sync>, - graph: Arc>, + tx_pool: TxPool, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -61,7 +61,7 @@ impl EthFilter { Self { client, backend, - graph, + tx_pool, filter_pool, max_stored_filters, max_past_logs, @@ -73,9 +73,11 @@ impl EthFilter { impl EthFilter where - A: ChainApi, + A: ChainApi + 'static, B: BlockT, - C: HeaderBackend, + C: HeaderMetadata + HeaderBackend + 'static, + C: ProvideRuntimeApi, + C::Api: TxPoolRuntimeApi, { fn create_filter(&self, filter_type: FilterType) -> RpcResult { let block_number = @@ -95,6 +97,12 @@ where Some((k, _)) => *k, None => U256::zero(), }; + let pending_transaction_hashes = if let FilterType::PendingTransaction = filter_type { + let ethereum_txs = self.tx_pool.tx_pool_response()?; + ethereum_txs.ready.into_iter().map(|tx| tx.hash()).collect() + } else { + HashSet::new() + }; // Assume `max_stored_filters` is always < U256::max. let key = last_key.checked_add(U256::one()).unwrap(); locked.insert( @@ -103,6 +111,7 @@ where last_poll: BlockNumber::Num(block_number), filter_type, at_block: block_number, + pending_transaction_hashes, }, ); Ok(key) @@ -111,30 +120,19 @@ where }; response } - - // fn pending_transactions(&self) -> RpcResult> { - // let txs_ready = self - // .graph - // .validated_pool() - // .ready() - // .map(|in_pool_tx| in_pool_tx.data().clone()) - // .collect(); - - // todo!(); - // // let txs_pending = txs_ready.into_iter().filter_map(|xt| match xt.0.function { - // // RuntimeCall - // // }) - // } } #[async_trait] impl EthFilterApiServer for EthFilter where - A: ChainApi + 'static, + A: ChainApi + 'static, B: BlockT, C: ProvideRuntimeApi, - C::Api: EthereumRuntimeRPCApi, - C: HeaderBackend + StorageProvider + 'static, + C::Api: EthereumRuntimeRPCApi + TxPoolRuntimeApi, + C: HeaderMetadata + + HeaderBackend + + StorageProvider + + 'static, BE: Backend + 'static, { fn new_filter(&self, filter: Filter) -> RpcResult { @@ -163,6 +161,9 @@ where last: u64, next: u64, }, + PendingTransaction { + new_hashes: Vec, + }, Log { filter: Filter, from_number: NumberFor, @@ -191,11 +192,40 @@ where last_poll: BlockNumber::Num(next), filter_type: pool_item.filter_type.clone(), at_block: pool_item.at_block, + pending_transaction_hashes: HashSet::new(), }, ); FuturePath::::Block { last, next } } + FilterType::PendingTransaction => { + let previous_hashes = pool_item.pending_transaction_hashes; + let current_hashes: HashSet = self + .tx_pool + .tx_pool_response()? + .ready + .into_iter() + .map(|tx| tx.hash()) + .collect(); + + // Update filter `last_poll`. + locked.insert( + key, + FilterPoolItem { + last_poll: BlockNumber::Num(block_number + 1), + filter_type: pool_item.filter_type.clone(), + at_block: pool_item.at_block, + pending_transaction_hashes: current_hashes.clone(), + }, + ); + + let mew_hashes = current_hashes + .difference(&previous_hashes) + .collect::>(); + FuturePath::PendingTransaction { + new_hashes: mew_hashes.into_iter().map(|h| *h).collect(), + } + } // For each event since last poll, get a vector of ethereum logs. FilterType::Log(filter) => { // Update filter `last_poll`. @@ -205,6 +235,7 @@ where last_poll: BlockNumber::Num(block_number + 1), filter_type: pool_item.filter_type.clone(), at_block: pool_item.at_block, + pending_transaction_hashes: HashSet::new(), }, ); @@ -242,8 +273,6 @@ where current_number, } } - // Should never reach here. - _ => FuturePath::Error(internal_err("Method not available.")), } } else { FuturePath::Error(internal_err(format!("Filter id {:?} does not exist.", key))) @@ -277,6 +306,7 @@ where } Ok(FilterChanges::Hashes(ethereum_hashes)) } + FuturePath::PendingTransaction { new_hashes } => Ok(FilterChanges::Hashes(new_hashes)), FuturePath::Log { filter, from_number, diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 02606e1742..39660da06e 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -41,6 +41,16 @@ pub struct TxPool { _marker: PhantomData, } +impl Clone for TxPool { + fn clone(&self) -> Self { + Self { + client: self.client.clone(), + graph: self.graph.clone(), + _marker: PhantomData, + } + } +} + impl TxPool where C: ProvideRuntimeApi, @@ -56,6 +66,47 @@ where where T: Get + Serialize, { + // Get the pending and queued ethereum transactions. + let ethereum_txns = self.tx_pool_response()?; + // Build the T response. + let mut pending = TransactionMap::::new(); + for txn in ethereum_txns.ready.iter() { + let hash = txn.hash(); + let nonce = match txn { + TransactionV2::Legacy(t) => t.nonce, + TransactionV2::EIP2930(t) => t.nonce, + TransactionV2::EIP1559(t) => t.nonce, + }; + let from_address = match public_key(txn) { + Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Err(_e) => H160::default(), + }; + pending + .entry(from_address) + .or_insert_with(HashMap::new) + .insert(nonce, T::get(hash, from_address, txn)); + } + let mut queued = TransactionMap::::new(); + for txn in ethereum_txns.future.iter() { + let hash = txn.hash(); + let nonce = match txn { + TransactionV2::Legacy(t) => t.nonce, + TransactionV2::EIP2930(t) => t.nonce, + TransactionV2::EIP1559(t) => t.nonce, + }; + let from_address = match public_key(txn) { + Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Err(_e) => H160::default(), + }; + queued + .entry(from_address) + .or_insert_with(HashMap::new) + .insert(nonce, T::get(hash, from_address, txn)); + } + Ok(TxPoolResult { pending, queued }) + } + + pub(crate) fn tx_pool_response(&self) -> RpcResult { // Collect transactions in the ready validated pool. let txs_ready = self .graph @@ -108,42 +159,8 @@ where internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err)) })? }; - // Build the T response. - let mut pending = TransactionMap::::new(); - for txn in ethereum_txns.ready.iter() { - let hash = txn.hash(); - let nonce = match txn { - TransactionV2::Legacy(t) => t.nonce, - TransactionV2::EIP2930(t) => t.nonce, - TransactionV2::EIP1559(t) => t.nonce, - }; - let from_address = match public_key(txn) { - Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), - Err(_e) => H160::default(), - }; - pending - .entry(from_address) - .or_insert_with(HashMap::new) - .insert(nonce, T::get(hash, from_address, txn)); - } - let mut queued = TransactionMap::::new(); - for txn in ethereum_txns.future.iter() { - let hash = txn.hash(); - let nonce = match txn { - TransactionV2::Legacy(t) => t.nonce, - TransactionV2::EIP2930(t) => t.nonce, - TransactionV2::EIP1559(t) => t.nonce, - }; - let from_address = match public_key(txn) { - Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), - Err(_e) => H160::default(), - }; - queued - .entry(from_address) - .or_insert_with(HashMap::new) - .insert(nonce, T::get(hash, from_address, txn)); - } - Ok(TxPoolResult { pending, queued }) + + Ok(ethereum_txns) } } diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 02914a1cf5..f755a63690 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -163,12 +163,13 @@ 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, - graph.clone(), + tx_pool.clone(), filter_pool, 500_usize, // max stored filters max_past_logs, @@ -201,7 +202,7 @@ where )?; io.merge(Web3::new(client.clone()).into_rpc())?; - io.merge(TxPool::new(client, graph).into_rpc())?; + io.merge(tx_pool.into_rpc())?; Ok(io) } From 0ed2039dc4c1abb1c799d1ffb99cfe2a228fb1b8 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 14:02:56 +0800 Subject: [PATCH 06/17] Add feature and format --- client/rpc-core/src/types/txpool.rs | 6 ++++-- client/rpc/src/lib.rs | 1 + client/rpc/src/txpool.rs | 13 ++++++++----- template/node/Cargo.toml | 1 + template/node/src/eth.rs | 4 ++-- template/node/src/rpc/eth.rs | 3 ++- template/node/src/rpc/mod.rs | 2 +- 7 files changed, 19 insertions(+), 11 deletions(-) diff --git a/client/rpc-core/src/types/txpool.rs b/client/rpc-core/src/types/txpool.rs index ef83123839..f1789b893b 100644 --- a/client/rpc-core/src/types/txpool.rs +++ b/client/rpc-core/src/types/txpool.rs @@ -16,11 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::types::Bytes; +use std::collections::HashMap; +// crates.io use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; use ethereum_types::{H160, H256, U256}; use serde::{Serialize, Serializer}; -use std::collections::HashMap; +// frontier +use crate::types::Bytes; pub type TransactionMap = HashMap>; diff --git a/client/rpc/src/lib.rs b/client/rpc/src/lib.rs index bd4ec59689..c9e78b379c 100644 --- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -41,6 +41,7 @@ pub use self::{ txpool::TxPool, web3::Web3, }; + pub use ethereum::TransactionV2 as EthereumTransaction; pub use fc_rpc_core::{ EthApiServer, EthFilterApiServer, EthPubSubApiServer, NetApiServer, TxPoolApiServer, diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 39660da06e..8fbe7db8aa 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -16,18 +16,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::{internal_err, public_key}; +use std::{collections::HashMap, marker::PhantomData, sync::Arc}; + use ethereum::TransactionV2; use ethereum_types::{H160, H256, U256}; +use jsonrpsee::core::RpcResult; +use serde::Serialize; +use sha3::{Digest, Keccak256}; +// frontier +use crate::{internal_err, public_key}; use fc_rpc_core::{ types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, TxPoolApiServer, }; use fp_rpc::{TxPoolResponse, TxPoolRuntimeApi}; -use jsonrpsee::core::RpcResult; -use serde::Serialize; -use sha3::{Digest, Keccak256}; -use std::{collections::HashMap, marker::PhantomData, sync::Arc}; // substrate use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::InPoolTransaction; @@ -68,6 +70,7 @@ where { // Get the pending and queued ethereum transactions. let ethereum_txns = self.tx_pool_response()?; + // Build the T response. let mut pending = TransactionMap::::new(); for txn in ethereum_txns.ready.iter() { diff --git a/template/node/Cargo.toml b/template/node/Cargo.toml index 95d238afc1..4cf21cb013 100644 --- a/template/node/Cargo.toml +++ b/template/node/Cargo.toml @@ -89,6 +89,7 @@ default = ["with-rocksdb-weights"] with-rocksdb-weights = ["frontier-template-runtime/with-rocksdb-weights"] with-paritydb-weights = ["frontier-template-runtime/with-paritydb-weights"] rpc-binary-search-estimate = ["fc-rpc/rpc-binary-search-estimate"] +txpool = [] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", diff --git a/template/node/src/eth.rs b/template/node/src/eth.rs index 23b4ec7a7a..1c41f911d2 100644 --- a/template/node/src/eth.rs +++ b/template/node/src/eth.rs @@ -123,8 +123,8 @@ pub fn new_frontier_partial( /// A set of APIs that ethereum-compatible runtimes must implement. pub trait EthCompatRuntimeApiCollection: sp_api::ApiExt - + fp_rpc::EthereumRuntimeRPCApi + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::EthereumRuntimeRPCApi + fp_rpc::TxPoolRuntimeApi where >::StateBackend: sp_api::StateBackend, @@ -134,8 +134,8 @@ where impl EthCompatRuntimeApiCollection for Api where Api: sp_api::ApiExt - + fp_rpc::EthereumRuntimeRPCApi + fp_rpc::ConvertTransactionRuntimeApi + + fp_rpc::EthereumRuntimeRPCApi + fp_rpc::TxPoolRuntimeApi, >::StateBackend: sp_api::StateBackend, { diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index f755a63690..1455eceb78 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -102,8 +102,8 @@ where B: BlockT, C: CallApiAt + ProvideRuntimeApi, C::Api: BlockBuilderApi - + EthereumRuntimeRPCApi + ConvertTransactionRuntimeApi + + EthereumRuntimeRPCApi + TxPoolRuntimeApi, C: BlockchainEvents + 'static, C: HeaderBackend + HeaderMetadata + StorageProvider, @@ -202,6 +202,7 @@ where )?; io.merge(Web3::new(client.clone()).into_rpc())?; + #[cfg(feature = "txpool")] io.merge(tx_pool.into_rpc())?; Ok(io) diff --git a/template/node/src/rpc/mod.rs b/template/node/src/rpc/mod.rs index 559697b6dc..3e6daa4691 100644 --- a/template/node/src/rpc/mod.rs +++ b/template/node/src/rpc/mod.rs @@ -65,8 +65,8 @@ where C::Api: sp_block_builder::BlockBuilder, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: fp_rpc::ConvertTransactionRuntimeApi, - C::Api: fp_rpc::TxPoolRuntimeApi, C::Api: fp_rpc::EthereumRuntimeRPCApi, + C::Api: fp_rpc::TxPoolRuntimeApi, C: BlockchainEvents + 'static, C: HeaderBackend + HeaderMetadata From d300cb9a53f1b7a850d2fb9a9254256ce60aab18 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 14:41:52 +0800 Subject: [PATCH 07/17] Use sp_core::hashing --- Cargo.lock | 1 - client/rpc-core/src/txpool.rs | 4 +++- client/rpc/Cargo.toml | 1 - client/rpc/src/txpool.rs | 6 +++--- template/node/src/rpc/eth.rs | 4 +++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 674cf9b17c..1152a84f39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2229,7 +2229,6 @@ dependencies = [ "sc-transaction-pool-api", "sc-utils", "serde", - "sha3", "sp-api", "sp-block-builder", "sp-blockchain", diff --git a/client/rpc-core/src/txpool.rs b/client/rpc-core/src/txpool.rs index e5bdca20ee..082e8097b3 100644 --- a/client/rpc-core/src/txpool.rs +++ b/client/rpc-core/src/txpool.rs @@ -18,9 +18,11 @@ //! tx pool rpc interface -use crate::types::*; +// crates.io use ethereum_types::U256; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +// frontier +use crate::types::*; /// TxPool rpc interface #[rpc(server)] diff --git a/client/rpc/Cargo.toml b/client/rpc/Cargo.toml index 29c579fe5e..000f065a44 100644 --- a/client/rpc/Cargo.toml +++ b/client/rpc/Cargo.toml @@ -25,7 +25,6 @@ rand = "0.8" rlp = { workspace = true } scale-codec = { package = "parity-scale-codec", workspace = true } serde = { workspace = true } -sha3 = { version = "0.10" } tokio = { version = "1.24", features = ["sync"] } # Substrate diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 8fbe7db8aa..f61794c179 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -22,7 +22,6 @@ use ethereum::TransactionV2; use ethereum_types::{H160, H256, U256}; use jsonrpsee::core::RpcResult; use serde::Serialize; -use sha3::{Digest, Keccak256}; // frontier use crate::{internal_err, public_key}; use fc_rpc_core::{ @@ -35,6 +34,7 @@ use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::InPoolTransaction; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_core::hashing::keccak_256; use sp_runtime::traits::Block as BlockT; pub struct TxPool { @@ -81,7 +81,7 @@ where TransactionV2::EIP1559(t) => t.nonce, }; let from_address = match public_key(txn) { - Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Ok(pk) => H160::from(H256::from_slice(keccak_256(&pk).as_slice())), Err(_e) => H160::default(), }; pending @@ -98,7 +98,7 @@ where TransactionV2::EIP1559(t) => t.nonce, }; let from_address = match public_key(txn) { - Ok(pk) => H160::from(H256::from_slice(Keccak256::digest(&pk).as_slice())), + Ok(pk) => H160::from(H256::from_slice(keccak_256(&pk).as_slice())), Err(_e) => H160::default(), }; queued diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 1455eceb78..211fce9e9c 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -112,9 +112,11 @@ where A: ChainApi + 'static, CT: ConvertTransaction<::Extrinsic> + Send + Sync + 'static, { + #[cfg(feature = "txpool")] + use fc_rpc::TxPoolApiServer; use fc_rpc::{ Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, - EthPubSubApiServer, EthSigner, Net, NetApiServer, TxPoolApiServer, Web3, Web3ApiServer, + EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, }; let EthDeps { From 38ef8366b204f6c7d9083f67e22aec8f63a70735 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 15:09:20 +0800 Subject: [PATCH 08/17] Fix clippy --- client/rpc/src/eth/filter.rs | 2 +- template/node/src/rpc/eth.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index a6adf924fb..3397af290c 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -223,7 +223,7 @@ where .difference(&previous_hashes) .collect::>(); FuturePath::PendingTransaction { - new_hashes: mew_hashes.into_iter().map(|h| *h).collect(), + new_hashes: mew_hashes.into_iter().copied().collect(), } } // For each event since last poll, get a vector of ethereum logs. diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 211fce9e9c..186c96893b 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -203,7 +203,7 @@ where .into_rpc(), )?; - io.merge(Web3::new(client.clone()).into_rpc())?; + io.merge(Web3::new(client).into_rpc())?; #[cfg(feature = "txpool")] io.merge(tx_pool.into_rpc())?; From ffff9e5a27fc4488083bc4069cf61a647b2d2a4e Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 15:16:53 +0800 Subject: [PATCH 09/17] Format code --- client/rpc-core/src/txpool.rs | 4 ++-- client/rpc-core/src/types/txpool.rs | 4 ++-- client/rpc/src/eth/filter.rs | 19 +++++++++++-------- client/rpc/src/txpool.rs | 2 +- template/runtime/src/lib.rs | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/client/rpc-core/src/txpool.rs b/client/rpc-core/src/txpool.rs index 082e8097b3..dcbc54597a 100644 --- a/client/rpc-core/src/txpool.rs +++ b/client/rpc-core/src/txpool.rs @@ -18,10 +18,10 @@ //! tx pool rpc interface -// crates.io +// Crates.io use ethereum_types::U256; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -// frontier +// Frontier use crate::types::*; /// TxPool rpc interface diff --git a/client/rpc-core/src/types/txpool.rs b/client/rpc-core/src/types/txpool.rs index f1789b893b..95c855571d 100644 --- a/client/rpc-core/src/types/txpool.rs +++ b/client/rpc-core/src/types/txpool.rs @@ -17,11 +17,11 @@ // along with this program. If not, see . use std::collections::HashMap; -// crates.io +// Crates.io use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; use ethereum_types::{H160, H256, U256}; use serde::{Serialize, Serializer}; -// frontier +// Frontier use crate::types::Bytes; pub type TransactionMap = HashMap>; diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 3397af290c..6d05ccbd0a 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -17,10 +17,14 @@ // along with this program. If not, see . use std::{collections::HashSet, marker::PhantomData, sync::Arc, time}; - +// Crates.io use ethereum::BlockV2 as EthereumBlock; use ethereum_types::{H256, U256}; use jsonrpsee::core::{async_trait, RpcResult}; +// Frontier +use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; +use fc_rpc_core::{types::*, EthFilterApiServer}; +use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; use sc_transaction_pool::ChainApi; @@ -31,11 +35,6 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor, One, Saturating, UniqueSaturatedInto}, }; -// Frontier -use fc_rpc_core::{types::*, EthFilterApiServer}; -use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; - -use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; pub struct EthFilter { client: Arc, @@ -98,8 +97,12 @@ where None => U256::zero(), }; let pending_transaction_hashes = if let FilterType::PendingTransaction = filter_type { - let ethereum_txs = self.tx_pool.tx_pool_response()?; - ethereum_txs.ready.into_iter().map(|tx| tx.hash()).collect() + self.tx_pool + .tx_pool_response()? + .ready + .into_iter() + .map(|tx| tx.hash()) + .collect() } else { HashSet::new() }; diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index f61794c179..91095b1f96 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -22,7 +22,7 @@ use ethereum::TransactionV2; use ethereum_types::{H160, H256, U256}; use jsonrpsee::core::RpcResult; use serde::Serialize; -// frontier +// Frontier use crate::{internal_err, public_key}; use fc_rpc_core::{ types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 832562f4ac..8465a66f61 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -774,7 +774,7 @@ impl_runtime_apis! { xts_ready: Vec<::Extrinsic>, xts_future: Vec<::Extrinsic>, ) -> fp_rpc::TxPoolResponse { - // frontier + // Frontier use pallet_ethereum::Call::transact; fp_rpc::TxPoolResponse { From a198f7045b34b348dda4f20e6b87213397eb4040 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 17:28:46 +0800 Subject: [PATCH 10/17] Add pending transaction polling ts tests --- ts-tests/tests/test-filter-api.ts | 39 +++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ts-tests/tests/test-filter-api.ts b/ts-tests/tests/test-filter-api.ts index f321a83621..f39387bd81 100644 --- a/ts-tests/tests/test-filter-api.ts +++ b/ts-tests/tests/test-filter-api.ts @@ -8,6 +8,7 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { const TEST_CONTRACT_BYTECODE = "0x608060405234801561001057600080fd5b50610041337fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61004660201b60201c565b610291565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156100e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b6101028160025461020960201b610c7c1790919060201c565b60028190555061015d816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461020960201b610c7c1790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b600080828401905083811015610287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b610e3a806102a06000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806370a082311161005b57806370a08231146101fd578063a457c2d714610255578063a9059cbb146102bb578063dd62ed3e1461032157610088565b8063095ea7b31461008d57806318160ddd146100f357806323b872dd146101115780633950935114610197575b600080fd5b6100d9600480360360408110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610399565b604051808215151515815260200191505060405180910390f35b6100fb6103b7565b6040518082815260200191505060405180910390f35b61017d6004803603606081101561012757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506103c1565b604051808215151515815260200191505060405180910390f35b6101e3600480360360408110156101ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061049a565b604051808215151515815260200191505060405180910390f35b61023f6004803603602081101561021357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061054d565b6040518082815260200191505060405180910390f35b6102a16004803603604081101561026b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610595565b604051808215151515815260200191505060405180910390f35b610307600480360360408110156102d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610662565b604051808215151515815260200191505060405180910390f35b6103836004803603604081101561033757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610680565b6040518082815260200191505060405180910390f35b60006103ad6103a6610707565b848461070f565b6001905092915050565b6000600254905090565b60006103ce848484610906565b61048f846103da610707565b61048a85604051806060016040528060288152602001610d7060289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610440610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b61070f565b600190509392505050565b60006105436104a7610707565b8461053e85600160006104b8610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7c90919063ffffffff16565b61070f565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006106586105a2610707565b8461065385604051806060016040528060258152602001610de160259139600160006105cc610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b61070f565b6001905092915050565b600061067661066f610707565b8484610906565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610795576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180610dbd6024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561081b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610d286022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561098c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180610d986025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a12576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610d056023913960400191505060405180910390fd5b610a7d81604051806060016040528060268152602001610d4a602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b10816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7c90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610c69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c2e578082015181840152602081019050610c13565b50505050905090810190601f168015610c5b5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610cfa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b809150509291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820c7a5ffabf642bda14700b2de42f8c57b36621af020441df825de45fd2b3e1c5c64736f6c63430005100032"; + var nonce = 0; async function sendTransaction(context) { const tx = await context.web3.eth.accounts.signTransaction( { @@ -16,10 +17,11 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { value: "0x00", gasPrice: "0x3B9ACA00", gas: "0x100000", + nonce: nonce, }, GENESIS_ACCOUNT_PRIVATE_KEY ); - + nonce = nonce + 1; await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); return tx; } @@ -54,10 +56,8 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { }); step("should return unsupported error for Pending Transaction filter creation", async function () { - let r = await customRequest(context.web3, "eth_newPendingTransactionFilter", []); - expect(r.error).to.include({ - message: "Method not available.", - }); + let createFilter = await customRequest(context.web3, "eth_newPendingTransactionFilter", []); + expect(createFilter.result).to.be.eq("0x4"); }); step("should return responses for Block filter polling.", async function () { @@ -87,6 +87,31 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { expect(poll.result[1]).to.be.eq(block_b.hash); }); + step("should return responses for pending transaction polling.", async function () { + let poll = await customRequest(context.web3, "eth_getFilterChanges", ["0x4"]); + expect(poll.result.length).to.be.eq(0); + + // fist polling + let tx = await sendTransaction(context); + poll = await customRequest(context.web3, "eth_getFilterChanges", ["0x4"]); + expect(poll.result.length).to.be.eq(1); + expect(poll.result).contains(tx.transactionHash); + + // second polling + let tx1 = await sendTransaction(context); + let tx2 = await sendTransaction(context); + poll = await customRequest(context.web3, "eth_getFilterChanges", ["0x4"]); + expect(poll.result.length).to.be.eq(2); + expect(poll.result).contains(tx1.transactionHash); + expect(poll.result).contains(tx2.transactionHash); + + await createAndFinalizeBlock(context.web3); + + // the last polling after finalized block + poll = await customRequest(context.web3, "eth_getFilterChanges", ["0x4"]); + expect(poll.result.length).to.be.eq(0); + }); + step("should return responses for Log filter polling.", async function () { // Create contract. let tx = await sendTransaction(context); @@ -157,7 +182,7 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { // Should return error if does not exist. let r = await customRequest(context.web3, "eth_uninstallFilter", [filterId]); expect(r.error).to.include({ - message: "Filter id 6 does not exist.", + message: "Filter id 7 does not exist.", }); }); @@ -174,7 +199,7 @@ describeWithFrontier("Frontier RPC (EthFilterApi)", (context) => { let r = await customRequest(context.web3, "eth_getFilterChanges", [filterId]); expect(r.error).to.include({ - message: "Filter id 6 does not exist.", + message: "Filter id 7 does not exist.", }); }); From 8ca5ea3882631eb394d9b01f74d319a39087ec02 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 18:18:51 +0800 Subject: [PATCH 11/17] Add txpool ts-test --- .github/workflows/rust.yml | 2 +- ts-tests/tests/txpool.ts | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 ts-tests/tests/txpool.ts diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a40b4ef118..ddcd06546c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -49,7 +49,7 @@ jobs: - name: Build client run: | cd template/node - cargo build --release --locked --verbose --features rpc-binary-search-estimate + cargo build --release --locked --verbose --features rpc-binary-search-estimate,txpool - name: Use Node.js 18 uses: actions/setup-node@v3 with: diff --git a/ts-tests/tests/txpool.ts b/ts-tests/tests/txpool.ts new file mode 100644 index 0000000000..102368ec0a --- /dev/null +++ b/ts-tests/tests/txpool.ts @@ -0,0 +1,59 @@ +import { expect } from "chai"; +import { step } from "mocha-steps"; + +import { GENESIS_ACCOUNT, GENESIS_ACCOUNT_PRIVATE_KEY } from "./config"; +import { describeWithFrontier, customRequest } from "./util"; + +describeWithFrontier("Frontier RPC (TxPoolApi)", (context) => { + const TEST_CONTRACT_BYTECODE = + "0x608060405234801561001057600080fd5b50610041337fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61004660201b60201c565b610291565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156100e9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b6101028160025461020960201b610c7c1790919060201c565b60028190555061015d816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205461020960201b610c7c1790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b600080828401905083811015610287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b610e3a806102a06000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806370a082311161005b57806370a08231146101fd578063a457c2d714610255578063a9059cbb146102bb578063dd62ed3e1461032157610088565b8063095ea7b31461008d57806318160ddd146100f357806323b872dd146101115780633950935114610197575b600080fd5b6100d9600480360360408110156100a357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610399565b604051808215151515815260200191505060405180910390f35b6100fb6103b7565b6040518082815260200191505060405180910390f35b61017d6004803603606081101561012757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506103c1565b604051808215151515815260200191505060405180910390f35b6101e3600480360360408110156101ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061049a565b604051808215151515815260200191505060405180910390f35b61023f6004803603602081101561021357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061054d565b6040518082815260200191505060405180910390f35b6102a16004803603604081101561026b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610595565b604051808215151515815260200191505060405180910390f35b610307600480360360408110156102d157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610662565b604051808215151515815260200191505060405180910390f35b6103836004803603604081101561033757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610680565b6040518082815260200191505060405180910390f35b60006103ad6103a6610707565b848461070f565b6001905092915050565b6000600254905090565b60006103ce848484610906565b61048f846103da610707565b61048a85604051806060016040528060288152602001610d7060289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610440610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b61070f565b600190509392505050565b60006105436104a7610707565b8461053e85600160006104b8610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7c90919063ffffffff16565b61070f565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60006106586105a2610707565b8461065385604051806060016040528060258152602001610de160259139600160006105cc610707565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b61070f565b6001905092915050565b600061067661066f610707565b8484610906565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610795576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180610dbd6024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561081b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610d286022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561098c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180610d986025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a12576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610d056023913960400191505060405180910390fd5b610a7d81604051806060016040528060268152602001610d4a602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610bbc9092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b10816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610c7c90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610c69576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c2e578082015181840152602081019050610c13565b50505050905090810190601f168015610c5b5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b600080828401905083811015610cfa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b809150509291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa265627a7a72315820c7a5ffabf642bda14700b2de42f8c57b36621af020441df825de45fd2b3e1c5c64736f6c63430005100032"; + + var nonce = 0; + let pending_tx; + let future_tx; + async function sendTransaction(context, nonce) { + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + data: TEST_CONTRACT_BYTECODE, + value: "0x00", + gasPrice: "0x3B9ACA00", + gas: "0x100000", + nonce: nonce, + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + return tx; + } + + step("txpool_status should return correct result", async function () { + let txpoolStatus = await customRequest(context.web3, "txpool_status", []); + expect(txpoolStatus.result.pending).to.be.equal("0x0"); + expect(txpoolStatus.result.queued).to.be.equal("0x0"); + + pending_tx = await sendTransaction(context, nonce); + future_tx = await sendTransaction(context, nonce + 3); + txpoolStatus = await customRequest(context.web3, "txpool_status", []); + expect(txpoolStatus.result.pending).to.be.equal("0x1"); + expect(txpoolStatus.result.queued).to.be.equal("0x1"); + }); + + step("txpool_content should return correct result", async function () { + let txpoolContent = await customRequest(context.web3, "txpool_content", []); + expect(txpoolContent.result.pending[GENESIS_ACCOUNT]["0x0"].nonce).to.be.equal("0x0"); + expect(txpoolContent.result.pending[GENESIS_ACCOUNT]["0x0"].hash).to.be.equal(pending_tx.transactionHash); + expect(txpoolContent.result.queued[GENESIS_ACCOUNT]["0x3"].nonce).to.be.equal("0x3"); + expect(txpoolContent.result.queued[GENESIS_ACCOUNT]["0x3"].hash).to.be.equal(future_tx.transactionHash); + }); + + step("txpool_inspect should return correct result", async function () { + let txpoolInspect = await customRequest(context.web3, "txpool_inspect", []); + expect(txpoolInspect.result.pending[GENESIS_ACCOUNT]["0x0"]).to.be.equal( + "0x0000000000000000000000000000000000000000: 0 wei + 1048576 gas x 1000000000 wei" + ); + expect(txpoolInspect.result.queued[GENESIS_ACCOUNT]["0x3"]).to.be.equal( + "0x0000000000000000000000000000000000000000: 0 wei + 1048576 gas x 1000000000 wei" + ); + }); +}); From 2648b622813d47cf754497cbeadab8e256725eb5 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 18:19:49 +0800 Subject: [PATCH 12/17] Fix clippy CI --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ddcd06546c..45bbf43471 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -91,4 +91,4 @@ jobs: - name: Rustfmt run: cargo fmt --all -- --check - name: Clippy - run: cargo clippy --all --features runtime-benchmarks,try-runtime -- -D warnings + run: cargo clippy --all --features runtime-benchmarks,try-runtime,txpool -- -D warnings From 976070d63ae358985fc871ea18a0eaa6d01c3c35 Mon Sep 17 00:00:00 2001 From: bear Date: Thu, 8 Jun 2023 19:41:40 +0800 Subject: [PATCH 13/17] Fix review --- client/rpc-core/src/txpool.rs | 1 - client/rpc-core/src/types/txpool.rs | 2 +- client/rpc/src/eth/filter.rs | 10 +++++----- client/rpc/src/txpool.rs | 14 +++++++------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/client/rpc-core/src/txpool.rs b/client/rpc-core/src/txpool.rs index dcbc54597a..3cea401121 100644 --- a/client/rpc-core/src/txpool.rs +++ b/client/rpc-core/src/txpool.rs @@ -18,7 +18,6 @@ //! tx pool rpc interface -// Crates.io use ethereum_types::U256; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; // Frontier diff --git a/client/rpc-core/src/types/txpool.rs b/client/rpc-core/src/types/txpool.rs index 95c855571d..ed70f504ec 100644 --- a/client/rpc-core/src/types/txpool.rs +++ b/client/rpc-core/src/types/txpool.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use std::collections::HashMap; -// Crates.io + use ethereum::{TransactionAction, TransactionV2 as EthereumTransaction}; use ethereum_types::{H160, H256, U256}; use serde::{Serialize, Serializer}; diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 6d05ccbd0a..2b7cfe355d 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -17,14 +17,10 @@ // along with this program. If not, see . use std::{collections::HashSet, marker::PhantomData, sync::Arc, time}; -// Crates.io + use ethereum::BlockV2 as EthereumBlock; use ethereum_types::{H256, U256}; use jsonrpsee::core::{async_trait, RpcResult}; -// Frontier -use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; -use fc_rpc_core::{types::*, EthFilterApiServer}; -use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; // Substrate use sc_client_api::backend::{Backend, StorageProvider}; use sc_transaction_pool::ChainApi; @@ -35,6 +31,10 @@ use sp_runtime::{ generic::BlockId, traits::{Block as BlockT, NumberFor, One, Saturating, UniqueSaturatedInto}, }; +// Frontier +use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; +use fc_rpc_core::{types::*, EthFilterApiServer}; +use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; pub struct EthFilter { client: Arc, diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 91095b1f96..5862bf1600 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -22,13 +22,6 @@ use ethereum::TransactionV2; use ethereum_types::{H160, H256, U256}; use jsonrpsee::core::RpcResult; use serde::Serialize; -// Frontier -use crate::{internal_err, public_key}; -use fc_rpc_core::{ - types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, - TxPoolApiServer, -}; -use fp_rpc::{TxPoolResponse, TxPoolRuntimeApi}; // substrate use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::InPoolTransaction; @@ -36,6 +29,13 @@ use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::hashing::keccak_256; use sp_runtime::traits::Block as BlockT; +// Frontier +use crate::{internal_err, public_key}; +use fc_rpc_core::{ + types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, + TxPoolApiServer, +}; +use fp_rpc::{TxPoolResponse, TxPoolRuntimeApi}; pub struct TxPool { client: Arc, From 1a383615467fb64fa3df1c31df480c7d0ec13f4d Mon Sep 17 00:00:00 2001 From: bear Date: Fri, 9 Jun 2023 09:52:51 +0800 Subject: [PATCH 14/17] Remove `TxPoolRuntimeApi` --- client/rpc/src/eth/filter.rs | 6 ++--- client/rpc/src/txpool.rs | 52 +++++++++--------------------------- primitives/rpc/src/lib.rs | 19 ------------- template/node/src/eth.rs | 4 +-- template/node/src/rpc/eth.rs | 9 ++----- template/node/src/rpc/mod.rs | 1 - template/runtime/src/lib.rs | 27 ------------------- 7 files changed, 19 insertions(+), 99 deletions(-) diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 2b7cfe355d..6e70e6673a 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -34,7 +34,7 @@ use sp_runtime::{ // Frontier use crate::{eth::cache::EthBlockDataCacheTask, frontier_backend_client, internal_err, TxPool}; use fc_rpc_core::{types::*, EthFilterApiServer}; -use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus, TxPoolRuntimeApi}; +use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus}; pub struct EthFilter { client: Arc, @@ -76,7 +76,7 @@ where B: BlockT, C: HeaderMetadata + HeaderBackend + 'static, C: ProvideRuntimeApi, - C::Api: TxPoolRuntimeApi, + C::Api: EthereumRuntimeRPCApi, { fn create_filter(&self, filter_type: FilterType) -> RpcResult { let block_number = @@ -131,7 +131,7 @@ where A: ChainApi + 'static, B: BlockT, C: ProvideRuntimeApi, - C::Api: EthereumRuntimeRPCApi + TxPoolRuntimeApi, + C::Api: EthereumRuntimeRPCApi, C: HeaderMetadata + HeaderBackend + StorageProvider diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 5862bf1600..34d4c2160b 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -25,7 +25,7 @@ use serde::Serialize; // substrate use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::InPoolTransaction; -use sp_api::{ApiExt, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; use sp_core::hashing::keccak_256; use sp_runtime::traits::Block as BlockT; @@ -35,7 +35,7 @@ use fc_rpc_core::{ types::{Get, Summary, TransactionMap, TxPoolResult, TxPoolTransaction}, TxPoolApiServer, }; -use fp_rpc::{TxPoolResponse, TxPoolRuntimeApi}; +use fp_rpc::{EthereumRuntimeRPCApi, TxPoolResponse}; pub struct TxPool { client: Arc, @@ -56,11 +56,11 @@ impl Clone for TxPool { impl TxPool where C: ProvideRuntimeApi, + C::Api: EthereumRuntimeRPCApi, C: HeaderMetadata + HeaderBackend + 'static, C: Send + Sync + 'static, B: BlockT + Send + Sync + 'static, A: ChainApi + 'static, - C::Api: TxPoolRuntimeApi, { /// Use the transaction graph interface to get the extrinsics currently in the ready and future /// queues. @@ -130,40 +130,14 @@ where // Use the runtime to match the (here) opaque extrinsics against ethereum transactions. let best_block = self.client.info().best_hash; let api = self.client.runtime_api(); - let api_version = - if let Ok(Some(api_version)) = api.api_version::>(best_block) { - api_version - } else { - return Err(internal_err( - "failed to retrieve Runtime Api version".to_string(), - )); - }; - let ethereum_txns: TxPoolResponse = if api_version == 1 { - #[allow(deprecated)] - let res = api.extrinsic_filter_before_version_2(best_block, txs_ready, txs_future) - .map_err(|err| { - internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err)) - })?; - TxPoolResponse { - ready: res - .ready - .iter() - .map(|t| TransactionV2::Legacy(t.clone())) - .collect(), - future: res - .future - .iter() - .map(|t| TransactionV2::Legacy(t.clone())) - .collect(), - } - } else { - api.extrinsic_filter(best_block, txs_ready, txs_future) - .map_err(|err| { - internal_err(format!("fetch runtime extrinsic filter failed: {:?}", err)) - })? - }; + let ready = api + .extrinsic_filter(best_block, txs_ready) + .map_err(|err| internal_err(format!("fetch ready transactions failed: {:?}", err)))?; + let future = api + .extrinsic_filter(best_block, txs_future) + .map_err(|err| internal_err(format!("fetch future transactions failed: {:?}", err)))?; - Ok(ethereum_txns) + Ok(TxPoolResponse { ready, future }) } } @@ -179,12 +153,12 @@ impl TxPool { impl TxPoolApiServer for TxPool where + A: ChainApi + 'static, + B: BlockT + Send + Sync + 'static, C: ProvideRuntimeApi, C: HeaderMetadata + HeaderBackend, C: Send + Sync + 'static, - B: BlockT + Send + Sync + 'static, - A: ChainApi + 'static, - C::Api: TxPoolRuntimeApi, + C::Api: EthereumRuntimeRPCApi, { fn content(&self) -> RpcResult>> { self.map_build::() diff --git a/primitives/rpc/src/lib.rs b/primitives/rpc/src/lib.rs index 7c0f5b77aa..e06a58ed0c 100644 --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -40,12 +40,6 @@ pub struct TransactionStatus { pub logs_bloom: Bloom, } -#[derive(Eq, PartialEq, Clone, Encode, Decode, sp_runtime::RuntimeDebug)] -pub struct TxPoolResponseLegacy { - pub ready: Vec, - pub future: Vec, -} - #[derive(Eq, PartialEq, Clone, Encode, Decode, sp_runtime::RuntimeDebug)] pub struct TxPoolResponse { pub ready: Vec, @@ -227,19 +221,6 @@ sp_api::decl_runtime_apis! { #[changed_in(2)] fn convert_transaction(transaction: ethereum::TransactionV0) -> ::Extrinsic; } - - #[api_version(2)] - pub trait TxPoolRuntimeApi { - #[changed_in(2)] - fn extrinsic_filter( - xt_ready: Vec<::Extrinsic>, - xt_future: Vec<::Extrinsic>, - ) -> TxPoolResponseLegacy; - fn extrinsic_filter( - xt_ready: Vec<::Extrinsic>, - xt_future: Vec<::Extrinsic>, - ) -> TxPoolResponse; - } } pub trait ConvertTransaction { diff --git a/template/node/src/eth.rs b/template/node/src/eth.rs index 1c41f911d2..765ba6c3ae 100644 --- a/template/node/src/eth.rs +++ b/template/node/src/eth.rs @@ -125,7 +125,6 @@ pub trait EthCompatRuntimeApiCollection: sp_api::ApiExt + fp_rpc::ConvertTransactionRuntimeApi + fp_rpc::EthereumRuntimeRPCApi - + fp_rpc::TxPoolRuntimeApi where >::StateBackend: sp_api::StateBackend, { @@ -135,8 +134,7 @@ impl EthCompatRuntimeApiCollection for Api where Api: sp_api::ApiExt + fp_rpc::ConvertTransactionRuntimeApi - + fp_rpc::EthereumRuntimeRPCApi - + fp_rpc::TxPoolRuntimeApi, + + fp_rpc::EthereumRuntimeRPCApi, >::StateBackend: sp_api::StateBackend, { } diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 186c96893b..730d239ba9 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -20,9 +20,7 @@ use sp_runtime::traits::Block as BlockT; pub use fc_rpc::{EthBlockDataCacheTask, EthConfig, OverrideHandle, StorageOverride, TxPool}; pub use fc_rpc_core::types::{FeeHistoryCache, FeeHistoryCacheLimit, FilterPool}; pub use fc_storage::overrides_handle; -use fp_rpc::{ - ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi, TxPoolRuntimeApi, -}; +use fp_rpc::{ConvertTransaction, ConvertTransactionRuntimeApi, EthereumRuntimeRPCApi}; /// Extra dependencies for Ethereum compatibility. pub struct EthDeps { @@ -101,10 +99,7 @@ pub fn create_eth>( where B: BlockT, C: CallApiAt + ProvideRuntimeApi, - C::Api: BlockBuilderApi - + ConvertTransactionRuntimeApi - + EthereumRuntimeRPCApi - + TxPoolRuntimeApi, + C::Api: BlockBuilderApi + ConvertTransactionRuntimeApi + EthereumRuntimeRPCApi, C: BlockchainEvents + 'static, C: HeaderBackend + HeaderMetadata + StorageProvider, BE: Backend + 'static, diff --git a/template/node/src/rpc/mod.rs b/template/node/src/rpc/mod.rs index 3e6daa4691..e1357ce716 100644 --- a/template/node/src/rpc/mod.rs +++ b/template/node/src/rpc/mod.rs @@ -66,7 +66,6 @@ where C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, C::Api: fp_rpc::ConvertTransactionRuntimeApi, C::Api: fp_rpc::EthereumRuntimeRPCApi, - C::Api: fp_rpc::TxPoolRuntimeApi, C: BlockchainEvents + 'static, C: HeaderBackend + HeaderMetadata diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 8465a66f61..59981a59a2 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -769,33 +769,6 @@ impl_runtime_apis! { } } - impl fp_rpc::TxPoolRuntimeApi for Runtime { - fn extrinsic_filter( - xts_ready: Vec<::Extrinsic>, - xts_future: Vec<::Extrinsic>, - ) -> fp_rpc::TxPoolResponse { - // Frontier - use pallet_ethereum::Call::transact; - - fp_rpc::TxPoolResponse { - ready: xts_ready - .into_iter() - .filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), - _ => None, - }) - .collect(), - future: xts_future - .into_iter() - .filter_map(|xt| match xt.0.function { - RuntimeCall::Ethereum(transact { transaction }) => Some(transaction), - _ => None, - }) - .collect(), - } - } - } - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< Block, Balance, From 50607384387187a0c4f7e698b7dc5f10b77c4ab9 Mon Sep 17 00:00:00 2001 From: bear Date: Fri, 9 Jun 2023 10:01:49 +0800 Subject: [PATCH 15/17] Clean trait bound --- client/rpc/src/eth/filter.rs | 4 ++-- client/rpc/src/txpool.rs | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 6e70e6673a..99afb77589 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -39,7 +39,7 @@ use fp_rpc::{EthereumRuntimeRPCApi, TransactionStatus}; pub struct EthFilter { client: Arc, backend: Arc + Send + Sync>, - tx_pool: TxPool, + tx_pool: TxPool, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, @@ -51,7 +51,7 @@ impl EthFilter { pub fn new( client: Arc, backend: Arc + Send + Sync>, - tx_pool: TxPool, + tx_pool: TxPool, filter_pool: FilterPool, max_stored_filters: usize, max_past_logs: u32, diff --git a/client/rpc/src/txpool.rs b/client/rpc/src/txpool.rs index 34d4c2160b..ab8e7c54a3 100644 --- a/client/rpc/src/txpool.rs +++ b/client/rpc/src/txpool.rs @@ -26,7 +26,7 @@ use serde::Serialize; use sc_transaction_pool::{ChainApi, Pool}; use sc_transaction_pool_api::InPoolTransaction; use sp_api::ProvideRuntimeApi; -use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_blockchain::HeaderBackend; use sp_core::hashing::keccak_256; use sp_runtime::traits::Block as BlockT; // Frontier @@ -37,13 +37,13 @@ use fc_rpc_core::{ }; use fp_rpc::{EthereumRuntimeRPCApi, TxPoolResponse}; -pub struct TxPool { +pub struct TxPool { client: Arc, graph: Arc>, _marker: PhantomData, } -impl Clone for TxPool { +impl Clone for TxPool { fn clone(&self) -> Self { Self { client: self.client.clone(), @@ -53,14 +53,13 @@ impl Clone for TxPool { } } -impl TxPool +impl TxPool where - C: ProvideRuntimeApi, - C::Api: EthereumRuntimeRPCApi, - C: HeaderMetadata + HeaderBackend + 'static, - C: Send + Sync + 'static, - B: BlockT + Send + Sync + 'static, A: ChainApi + 'static, + B: BlockT + Send + Sync + 'static, + C: Send + Sync + 'static, + C: HeaderBackend + ProvideRuntimeApi, + C::Api: EthereumRuntimeRPCApi, { /// Use the transaction graph interface to get the extrinsics currently in the ready and future /// queues. @@ -141,7 +140,7 @@ where } } -impl TxPool { +impl TxPool { pub fn new(client: Arc, graph: Arc>) -> Self { Self { client, @@ -151,13 +150,12 @@ impl TxPool { } } -impl TxPoolApiServer for TxPool +impl TxPoolApiServer for TxPool where A: ChainApi + 'static, B: BlockT + Send + Sync + 'static, - C: ProvideRuntimeApi, - C: HeaderMetadata + HeaderBackend, C: Send + Sync + 'static, + C: HeaderBackend + ProvideRuntimeApi, C::Api: EthereumRuntimeRPCApi, { fn content(&self) -> RpcResult>> { From babcc8b74d36c173bc2ccd17a7dbdbec5becef4c Mon Sep 17 00:00:00 2001 From: bear Date: Fri, 9 Jun 2023 10:54:25 +0800 Subject: [PATCH 16/17] Clean trait bound --- client/rpc/src/eth/filter.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/client/rpc/src/eth/filter.rs b/client/rpc/src/eth/filter.rs index 99afb77589..3921ad98f7 100644 --- a/client/rpc/src/eth/filter.rs +++ b/client/rpc/src/eth/filter.rs @@ -25,7 +25,7 @@ use jsonrpsee::core::{async_trait, RpcResult}; use sc_client_api::backend::{Backend, StorageProvider}; use sc_transaction_pool::ChainApi; use sp_api::ProvideRuntimeApi; -use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; +use sp_blockchain::HeaderBackend; use sp_core::hashing::keccak_256; use sp_runtime::{ generic::BlockId, @@ -74,8 +74,7 @@ impl EthFilter where A: ChainApi + 'static, B: BlockT, - C: HeaderMetadata + HeaderBackend + 'static, - C: ProvideRuntimeApi, + C: HeaderBackend + ProvideRuntimeApi + 'static, C::Api: EthereumRuntimeRPCApi, { fn create_filter(&self, filter_type: FilterType) -> RpcResult { @@ -130,12 +129,8 @@ impl EthFilterApiServer for EthFilter where A: ChainApi + 'static, B: BlockT, - C: ProvideRuntimeApi, + C: HeaderBackend + ProvideRuntimeApi + StorageProvider + 'static, C::Api: EthereumRuntimeRPCApi, - C: HeaderMetadata - + HeaderBackend - + StorageProvider - + 'static, BE: Backend + 'static, { fn new_filter(&self, filter: Filter) -> RpcResult { @@ -525,9 +520,8 @@ async fn filter_range_logs_indexed( ) -> RpcResult<()> where B: BlockT, - C: ProvideRuntimeApi, + C: HeaderBackend + ProvideRuntimeApi + StorageProvider + 'static, C::Api: EthereumRuntimeRPCApi, - C: HeaderBackend + StorageProvider + 'static, BE: Backend + 'static, { use std::time::Instant; From 76d0769120f5354e6238764877d39ae5330de023 Mon Sep 17 00:00:00 2001 From: bear Date: Sun, 25 Jun 2023 13:19:53 +0800 Subject: [PATCH 17/17] Remove feature `txpool` --- .github/workflows/rust.yml | 4 ++-- template/node/Cargo.toml | 1 - template/node/src/rpc/eth.rs | 5 +---- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 45bbf43471..a40b4ef118 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -49,7 +49,7 @@ jobs: - name: Build client run: | cd template/node - cargo build --release --locked --verbose --features rpc-binary-search-estimate,txpool + cargo build --release --locked --verbose --features rpc-binary-search-estimate - name: Use Node.js 18 uses: actions/setup-node@v3 with: @@ -91,4 +91,4 @@ jobs: - name: Rustfmt run: cargo fmt --all -- --check - name: Clippy - run: cargo clippy --all --features runtime-benchmarks,try-runtime,txpool -- -D warnings + run: cargo clippy --all --features runtime-benchmarks,try-runtime -- -D warnings diff --git a/template/node/Cargo.toml b/template/node/Cargo.toml index b5ca1e7ece..d6e8d53589 100644 --- a/template/node/Cargo.toml +++ b/template/node/Cargo.toml @@ -89,7 +89,6 @@ default = ["with-rocksdb-weights"] with-rocksdb-weights = ["frontier-template-runtime/with-rocksdb-weights"] with-paritydb-weights = ["frontier-template-runtime/with-paritydb-weights"] rpc-binary-search-estimate = ["fc-rpc/rpc-binary-search-estimate"] -txpool = [] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "frame-benchmarking-cli/runtime-benchmarks", diff --git a/template/node/src/rpc/eth.rs b/template/node/src/rpc/eth.rs index 9ccaf759d3..2117cc6ba7 100644 --- a/template/node/src/rpc/eth.rs +++ b/template/node/src/rpc/eth.rs @@ -107,11 +107,9 @@ where A: ChainApi + 'static, CT: ConvertTransaction<::Extrinsic> + Send + Sync + 'static, { - #[cfg(feature = "txpool")] - use fc_rpc::TxPoolApiServer; use fc_rpc::{ Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, - EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, + EthPubSubApiServer, EthSigner, Net, NetApiServer, TxPoolApiServer, Web3, Web3ApiServer, }; let EthDeps { @@ -199,7 +197,6 @@ where )?; io.merge(Web3::new(client).into_rpc())?; - #[cfg(feature = "txpool")] io.merge(tx_pool.into_rpc())?; Ok(io)