mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(rpc): add txpool namespace (#2591)
This commit is contained in:
@ -302,6 +302,11 @@ impl Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the transaction's nonce.
|
||||
pub fn to(&self) -> Option<Address> {
|
||||
self.kind().to()
|
||||
}
|
||||
|
||||
/// Get transaction type
|
||||
pub fn tx_type(&self) -> TxType {
|
||||
match self {
|
||||
@ -312,8 +317,8 @@ impl Transaction {
|
||||
}
|
||||
|
||||
/// Gets the transaction's value field.
|
||||
pub fn value(&self) -> &u128 {
|
||||
match self {
|
||||
pub fn value(&self) -> u128 {
|
||||
*match self {
|
||||
Transaction::Legacy(TxLegacy { value, .. }) => value,
|
||||
Transaction::Eip2930(TxEip2930 { value, .. }) => value,
|
||||
Transaction::Eip1559(TxEip1559 { value, .. }) => value,
|
||||
@ -678,6 +683,16 @@ pub enum TransactionKind {
|
||||
Call(Address),
|
||||
}
|
||||
|
||||
impl TransactionKind {
|
||||
/// Returns the address of the contract that will be called or will receive the transfer.
|
||||
pub fn to(self) -> Option<Address> {
|
||||
match self {
|
||||
TransactionKind::Create => None,
|
||||
TransactionKind::Call(to) => Some(to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Compact for TransactionKind {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
|
||||
@ -17,6 +17,7 @@ mod eth_filter;
|
||||
mod eth_pubsub;
|
||||
mod net;
|
||||
mod trace;
|
||||
mod txpool;
|
||||
mod web3;
|
||||
|
||||
/// re-export of all server traits
|
||||
@ -33,6 +34,7 @@ pub mod servers {
|
||||
eth_pubsub::EthPubSubApiServer,
|
||||
net::NetApiServer,
|
||||
trace::TraceApiServer,
|
||||
txpool::TxPoolApiServer,
|
||||
web3::Web3ApiServer,
|
||||
};
|
||||
}
|
||||
@ -51,6 +53,7 @@ pub mod clients {
|
||||
eth::EthApiClient,
|
||||
net::NetApiClient,
|
||||
trace::TraceApiClient,
|
||||
txpool::TxPoolApiClient,
|
||||
web3::Web3ApiClient,
|
||||
};
|
||||
}
|
||||
|
||||
36
crates/rpc/rpc-api/src/txpool.rs
Normal file
36
crates/rpc/rpc-api/src/txpool.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use jsonrpsee::{core::RpcResult as Result, proc_macros::rpc};
|
||||
use reth_primitives::Address;
|
||||
use reth_rpc_types::txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus};
|
||||
|
||||
/// Txpool rpc interface.
|
||||
#[cfg_attr(not(feature = "client"), rpc(server))]
|
||||
#[cfg_attr(feature = "client", rpc(server, client))]
|
||||
#[async_trait::async_trait]
|
||||
pub trait TxPoolApi {
|
||||
/// Returns the number of transactions currently pending for inclusion in the next block(s), as
|
||||
/// well as the ones that are being scheduled for future execution only.
|
||||
/// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status)
|
||||
#[method(name = "txpool_status")]
|
||||
async fn txpool_status(&self) -> Result<TxpoolStatus>;
|
||||
|
||||
/// Returns a summary of all the transactions currently pending for inclusion in the next
|
||||
/// block(s), as well as the ones that are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect) for more details
|
||||
#[method(name = "txpool_inspect")]
|
||||
async fn txpool_inspect(&self) -> Result<TxpoolInspect>;
|
||||
|
||||
/// Retrieves the transactions contained within the txpool, returning pending as well as queued
|
||||
/// transactions of this address, grouped by nonce.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details
|
||||
#[method(name = "txpool_contentFrom")]
|
||||
async fn txpool_content_from(&self, from: Address) -> Result<TxpoolContentFrom>;
|
||||
|
||||
/// Returns the details of all transactions currently pending for inclusion in the next
|
||||
/// block(s), as well as the ones that are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
|
||||
#[method(name = "txpool_content")]
|
||||
async fn txpool_content(&self) -> Result<TxpoolContent>;
|
||||
}
|
||||
@ -109,7 +109,7 @@ use reth_network_api::{NetworkInfo, Peers};
|
||||
use reth_provider::{BlockProvider, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory};
|
||||
use reth_rpc::{
|
||||
eth::cache::EthStateCache, AdminApi, DebugApi, EngineEthApi, EthApi, EthFilter, EthPubSub,
|
||||
EthSubscriptionIdProvider, NetApi, TraceApi, TracingCallGuard, Web3Api,
|
||||
EthSubscriptionIdProvider, NetApi, TraceApi, TracingCallGuard, TxPoolApi, Web3Api,
|
||||
};
|
||||
use reth_rpc_api::{servers::*, EngineApiServer};
|
||||
use reth_tasks::TaskSpawner;
|
||||
@ -531,6 +531,8 @@ pub enum RethRpcModule {
|
||||
Net,
|
||||
/// `trace_` module
|
||||
Trace,
|
||||
/// `txpool_` module
|
||||
Txpool,
|
||||
/// `web3_` module
|
||||
Web3,
|
||||
}
|
||||
@ -758,6 +760,9 @@ where
|
||||
.into_rpc()
|
||||
.into(),
|
||||
RethRpcModule::Web3 => Web3Api::new(self.network.clone()).into_rpc().into(),
|
||||
RethRpcModule::Txpool => {
|
||||
TxPoolApi::new(self.pool.clone()).into_rpc().into()
|
||||
}
|
||||
})
|
||||
.clone()
|
||||
})
|
||||
|
||||
@ -14,6 +14,7 @@ pub mod state;
|
||||
mod syncing;
|
||||
pub mod trace;
|
||||
mod transaction;
|
||||
pub mod txpool;
|
||||
mod work;
|
||||
|
||||
pub use account::*;
|
||||
|
||||
@ -161,7 +161,7 @@ impl Transaction {
|
||||
nonce: U256::from(signed_tx.nonce()),
|
||||
from: signer,
|
||||
to,
|
||||
value: U256::from(*signed_tx.value()),
|
||||
value: U256::from(signed_tx.value()),
|
||||
gas_price,
|
||||
max_fee_per_gas,
|
||||
max_priority_fee_per_gas: signed_tx.max_priority_fee_per_gas().map(U128::from),
|
||||
|
||||
520
crates/rpc/rpc-types/src/eth/txpool.rs
Normal file
520
crates/rpc/rpc-types/src/eth/txpool.rs
Normal file
@ -0,0 +1,520 @@
|
||||
//! Types for the `txpool` namespace: <https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool>
|
||||
|
||||
use crate::Transaction;
|
||||
use reth_primitives::{Address, U256, U64};
|
||||
use serde::{
|
||||
de::{self, Deserializer, Visitor},
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt, str::FromStr};
|
||||
|
||||
/// Transaction summary as found in the Txpool Inspection property.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TxpoolInspectSummary {
|
||||
/// Recipient (None when contract creation)
|
||||
pub to: Option<Address>,
|
||||
/// Transferred value
|
||||
pub value: U256,
|
||||
/// Gas amount
|
||||
pub gas: U256,
|
||||
/// Gas Price
|
||||
pub gas_price: U256,
|
||||
}
|
||||
|
||||
/// Visitor struct for TxpoolInspectSummary.
|
||||
struct TxpoolInspectSummaryVisitor;
|
||||
|
||||
/// Walk through the deserializer to parse a txpool inspection summary into the
|
||||
/// `TxpoolInspectSummary` struct.
|
||||
impl<'de> Visitor<'de> for TxpoolInspectSummaryVisitor {
|
||||
type Value = TxpoolInspectSummary;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter.write_str("to: value wei + gasLimit gas × gas_price wei")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let addr_split: Vec<&str> = value.split(": ").collect();
|
||||
if addr_split.len() != 2 {
|
||||
return Err(de::Error::custom("invalid format for TxpoolInspectSummary: to"))
|
||||
}
|
||||
let value_split: Vec<&str> = addr_split[1].split(" wei + ").collect();
|
||||
if value_split.len() != 2 {
|
||||
return Err(de::Error::custom("invalid format for TxpoolInspectSummary: gasLimit"))
|
||||
}
|
||||
let gas_split: Vec<&str> = value_split[1].split(" gas × ").collect();
|
||||
if gas_split.len() != 2 {
|
||||
return Err(de::Error::custom("invalid format for TxpoolInspectSummary: gas"))
|
||||
}
|
||||
let gas_price_split: Vec<&str> = gas_split[1].split(" wei").collect();
|
||||
if gas_price_split.len() != 2 {
|
||||
return Err(de::Error::custom("invalid format for TxpoolInspectSummary: gas_price"))
|
||||
}
|
||||
let addr = match addr_split[0] {
|
||||
"" => None,
|
||||
"0x" => None,
|
||||
"contract creation" => None,
|
||||
addr => {
|
||||
Some(Address::from_str(addr.trim_start_matches("0x")).map_err(de::Error::custom)?)
|
||||
}
|
||||
};
|
||||
let value = U256::from_str(value_split[0]).map_err(de::Error::custom)?;
|
||||
let gas = U256::from_str(gas_split[0]).map_err(de::Error::custom)?;
|
||||
let gas_price = U256::from_str(gas_price_split[0]).map_err(de::Error::custom)?;
|
||||
|
||||
Ok(TxpoolInspectSummary { to: addr, value, gas, gas_price })
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
self.visit_str(&value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the `Deserialize` trait for `TxpoolInspectSummary` struct.
|
||||
impl<'de> Deserialize<'de> for TxpoolInspectSummary {
|
||||
fn deserialize<D>(deserializer: D) -> Result<TxpoolInspectSummary, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_str(TxpoolInspectSummaryVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement the `Serialize` trait for `TxpoolInspectSummary` struct so that the
|
||||
/// format matches the one from geth.
|
||||
impl Serialize for TxpoolInspectSummary {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
let formatted_to = if let Some(to) = self.to {
|
||||
format!("{to:?}")
|
||||
} else {
|
||||
"contract creation".to_string()
|
||||
};
|
||||
let formatted = format!(
|
||||
"{}: {} wei + {} gas × {} wei",
|
||||
formatted_to, self.value, self.gas, self.gas_price
|
||||
);
|
||||
serializer.serialize_str(&formatted)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction Pool Content
|
||||
///
|
||||
/// The content inspection property can be queried to list the exact details of all
|
||||
/// the transactions currently pending for inclusion in the next block(s), as well
|
||||
/// as the ones that are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TxpoolContent {
|
||||
/// pending tx
|
||||
pub pending: BTreeMap<Address, BTreeMap<String, Transaction>>,
|
||||
/// queued tx
|
||||
pub queued: BTreeMap<Address, BTreeMap<String, Transaction>>,
|
||||
}
|
||||
|
||||
impl TxpoolContent {
|
||||
/// Removes the transactions from the given sender
|
||||
pub fn remove_from(&mut self, sender: &Address) -> TxpoolContentFrom {
|
||||
TxpoolContentFrom {
|
||||
pending: self.pending.remove(sender).unwrap_or_default(),
|
||||
queued: self.queued.remove(sender).unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction Pool Content From
|
||||
///
|
||||
/// Same as [TxpoolContent] but for a specific address.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TxpoolContentFrom {
|
||||
/// pending tx
|
||||
pub pending: BTreeMap<String, Transaction>,
|
||||
/// queued tx
|
||||
pub queued: BTreeMap<String, Transaction>,
|
||||
}
|
||||
|
||||
/// Transaction Pool Inspect
|
||||
///
|
||||
/// The inspect inspection property can be queried to list a textual summary
|
||||
/// of all the transactions currently pending for inclusion in the next block(s),
|
||||
/// as well as the ones that are being scheduled for future execution only.
|
||||
/// This is a method specifically tailored to developers to quickly see the
|
||||
/// transactions in the pool and find any potential issues.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect) for more details
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TxpoolInspect {
|
||||
/// pending tx
|
||||
pub pending: BTreeMap<Address, BTreeMap<String, TxpoolInspectSummary>>,
|
||||
/// queued tx
|
||||
pub queued: BTreeMap<Address, BTreeMap<String, TxpoolInspectSummary>>,
|
||||
}
|
||||
|
||||
/// Transaction Pool Status
|
||||
///
|
||||
/// The status inspection property can be queried for the number of transactions
|
||||
/// currently pending for inclusion in the next block(s), as well as the ones that
|
||||
/// are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status) for more details
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct TxpoolStatus {
|
||||
/// number of pending tx
|
||||
pub pending: U64,
|
||||
/// number of queued tx
|
||||
pub queued: U64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn serde_txpool_content() {
|
||||
// Gathered from geth v1.10.23-stable-d901d853/linux-amd64/go1.18.5
|
||||
// Addresses used as keys in `pending` and `queued` have been manually lowercased to
|
||||
// simplify the test.
|
||||
let txpool_content_json = r#"
|
||||
{
|
||||
"pending": {
|
||||
"0x00000000863b56a3c1f0f1be8bc4f8b7bd78f57a": {
|
||||
"29": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x00000000863b56a3c1f0f1be8bc4f8b7bd78f57a",
|
||||
"gas": "0x2af9e",
|
||||
"gasPrice": "0x218711a00",
|
||||
"maxFeePerGas": "0x218711a00",
|
||||
"maxPriorityFeePerGas": "0x3b9aca00",
|
||||
"hash": "0xfbc6fd04ba1c4114f06574263f04099b4fb2da72acc6f9709f0a3d2361308344",
|
||||
"input": "0x5ae401dc00000000000000000000000000000000000000000000000000000000636c757700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000e404e45aaf000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000863b56a3c1f0f1be8bc4f8b7bd78f57a000000000000000000000000000000000000000000000000000000007781df4000000000000000000000000000000000000000000000006c240454bf9c87cd84000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"nonce": "0x1d",
|
||||
"to": "0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x0",
|
||||
"r": "0xbb809ae71b03319ba2811ebd581c85665169143ffade86e07d2eb4cd03b544dc",
|
||||
"s": "0x65a2aa7e0e70356f765205a611d580de8e84fa79086f117fd9ab4765f5cf1339"
|
||||
}
|
||||
},
|
||||
"0x000042429c09de5881f05a0c2a068222f4f5b091": {
|
||||
"38": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x000042429c09de5881f05a0c2a068222f4f5b091",
|
||||
"gas": "0x61a80",
|
||||
"gasPrice": "0x2540be400",
|
||||
"hash": "0x054ad1ccf5917139a9b1952f62048f742255a7c11100f593c4f18c1ed49b8dfd",
|
||||
"input": "0x27dc297e800332e506f28f49a13c1edf087bdd6482d6cb3abdf2a4c455642aef1e98fc240000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002d7b22444149223a313439332e37342c2254555344223a313438392e36362c2255534443223a313439322e34387d00000000000000000000000000000000000000",
|
||||
"nonce": "0x26",
|
||||
"to": "0xabd279febe00c93fb0c9e683c6919ec4f107241f",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x0",
|
||||
"chainId": "0x1",
|
||||
"v": "0x26",
|
||||
"r": "0xaf46b2c0f067f7d1d63ac19daa349c0e1eb83f019ee00542ffa7095e05352e92",
|
||||
"s": "0x21d6d24d58ec361379ffffe4cc17bec8ce2b9f5f9759a91afc9a54dfdfa519c2"
|
||||
}
|
||||
},
|
||||
"0x000fab888651fbceb55de230493562159ead0340": {
|
||||
"12": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x000fab888651fbceb55de230493562159ead0340",
|
||||
"gas": "0x12fed",
|
||||
"gasPrice": "0x1a13b8600",
|
||||
"maxFeePerGas": "0x1a13b8600",
|
||||
"maxPriorityFeePerGas": "0x59682f00",
|
||||
"hash": "0xfae0cffdae6774abe11662a2cdbea019fce48fca87ba9ebf5e9e7c2454c01715",
|
||||
"input": "0xa9059cbb00000000000000000000000050272a56ef9aff7238e8b40347da62e87c1f69e200000000000000000000000000000000000000000000000000000000428d3dfc",
|
||||
"nonce": "0xc",
|
||||
"to": "0x8e8d6ab093905c400d583efd37fbeeb1ee1c0c39",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x0",
|
||||
"r": "0x7b717e689d1bd045ee7afd79b97219f2e36bd22a6a14e07023902194bca96fbf",
|
||||
"s": "0x7b0ba462c98e7b0f95a53f047cf568ee0443839628dfe4ab294bfab88fa8e251"
|
||||
}
|
||||
}
|
||||
},
|
||||
"queued": {
|
||||
"0x00b846f07f5e7c61569437ca16f88a9dfa00f1bf": {
|
||||
"143": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x00b846f07f5e7c61569437ca16f88a9dfa00f1bf",
|
||||
"gas": "0x33c3b",
|
||||
"gasPrice": "0x218711a00",
|
||||
"maxFeePerGas": "0x218711a00",
|
||||
"maxPriorityFeePerGas": "0x77359400",
|
||||
"hash": "0x68959706857f7a58d752ede0a5118a5f55f4ae40801f31377e1af201944720b2",
|
||||
"input": "0x03a9ea6d00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000f2ff840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000041d0c4694374d7893d63605625687be2f01028a5b49eca00f72901e773ad8ba7906e58d43e114a28353efaf8abd6a2675de83a3a07af579b8b268e6b714376610d1c00000000000000000000000000000000000000000000000000000000000000",
|
||||
"nonce": "0x8f",
|
||||
"to": "0xfbddadd80fe7bda00b901fbaf73803f2238ae655",
|
||||
"transactionIndex": null,
|
||||
"value": "0x1f58a57c1794eb",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x0",
|
||||
"r": "0x77d149add2b1b84af9408af55661b05b21e2a436f9bfcaa844584905a0f8f1ac",
|
||||
"s": "0x358d79063d702f0c3fb46ad0f6ce5db61f5fdb0b20359c8da2e72a11988db283"
|
||||
}
|
||||
},
|
||||
"0x025276ec2de8ee570cfd4c1010319f14a6d9f0dd": {
|
||||
"1": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x025276ec2de8ee570cfd4c1010319f14a6d9f0dd",
|
||||
"gas": "0x7918",
|
||||
"gasPrice": "0x12e531724e",
|
||||
"maxFeePerGas": "0x12e531724e",
|
||||
"maxPriorityFeePerGas": "0x59682f00",
|
||||
"hash": "0x35109918ab6129a4d69480514ebec0ea08dc4a4de032fec59003ea66718828c4",
|
||||
"input": "0x",
|
||||
"nonce": "0x1",
|
||||
"to": "0x025276ec2de8ee570cfd4c1010319f14a6d9f0dd",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x0",
|
||||
"r": "0x863ed0413a14f3f1695fd9728f1500a2b46e69d6f4c82408af15354cc5a667d6",
|
||||
"s": "0x2d503050aa1c9ecbb6df9957459c296f2f6190bc07aa09047d541233100b1c7a"
|
||||
},
|
||||
"4": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x025276ec2de8ee570cfd4c1010319f14a6d9f0dd",
|
||||
"gas": "0x7530",
|
||||
"gasPrice": "0x1919617600",
|
||||
"maxFeePerGas": "0x1919617600",
|
||||
"maxPriorityFeePerGas": "0x5c7261c0",
|
||||
"hash": "0xa58e54464b2ca62a5e2d976604ed9a53b13f8823a170ee4c3ae0cd91cde2a6c5",
|
||||
"input": "0x",
|
||||
"nonce": "0x4",
|
||||
"to": "0x025276ec2de8ee570cfd4c1010319f14a6d9f0dd",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x1",
|
||||
"r": "0xb6a571191c4b5b667876295571c42c9411bbb4569eea1a6ad149572e4efc55a9",
|
||||
"s": "0x248a72dab9b24568dd9cbe289c205eaba1a6b58b32b5a96c48554945d3fd0d86"
|
||||
}
|
||||
},
|
||||
"0x02666081cfb787de3562efbbca5f0fe890e927f1": {
|
||||
"44": {
|
||||
"blockHash": null,
|
||||
"blockNumber": null,
|
||||
"from": "0x02666081cfb787de3562efbbca5f0fe890e927f1",
|
||||
"gas": "0x16404",
|
||||
"gasPrice": "0x4bad00695",
|
||||
"maxFeePerGas": "0x4bad00695",
|
||||
"maxPriorityFeePerGas": "0xa3e9ab80",
|
||||
"hash": "0xf627e59d7a59eb650f4c9df222858572601a566263809fdacbb755ac2277a4a7",
|
||||
"input": "0x095ea7b300000000000000000000000029fbd00940df70cfc5dad3f2370686991e2bbf5cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"nonce": "0x2c",
|
||||
"to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
||||
"transactionIndex": null,
|
||||
"value": "0x0",
|
||||
"type": "0x2",
|
||||
"accessList": [],
|
||||
"chainId": "0x1",
|
||||
"v": "0x1",
|
||||
"r": "0xcfc88f55fc0779d12705acba58719cd7d0ed5b0c1a7c3c3682b56397ca493dd5",
|
||||
"s": "0x7e7dc008058c543ebfdae67154c797639447db5e8006f8fc0585352d857c1b6c"
|
||||
}
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let deserialized: TxpoolContent = serde_json::from_str(txpool_content_json).unwrap();
|
||||
let serialized: String = serde_json::to_string_pretty(&deserialized).unwrap();
|
||||
|
||||
let origin: serde_json::Value = serde_json::from_str(txpool_content_json).unwrap();
|
||||
let serialized_value = serde_json::to_value(deserialized.clone()).unwrap();
|
||||
assert_eq!(origin, serialized_value);
|
||||
assert_eq!(deserialized, serde_json::from_str::<TxpoolContent>(&serialized).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_txpool_inspect() {
|
||||
let txpool_inspect_json = r#"
|
||||
{
|
||||
"pending": {
|
||||
"0x0512261a7486b1e29704ac49a5eb355b6fd86872": {
|
||||
"124930": "0x000000000000000000000000000000000000007E: 0 wei + 100187 gas × 20000000000 wei"
|
||||
},
|
||||
"0x201354729f8d0f8b64e9a0c353c672c6a66b3857": {
|
||||
"252350": "0xd10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF: 0 wei + 65792 gas × 2000000000 wei",
|
||||
"252351": "0xd10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF: 0 wei + 65792 gas × 2000000000 wei",
|
||||
"252352": "0xd10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF: 0 wei + 65780 gas × 2000000000 wei",
|
||||
"252353": "0xd10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF: 0 wei + 65780 gas × 2000000000 wei"
|
||||
},
|
||||
"0x00000000863B56a3C1f0F1be8BC4F8b7BD78F57a": {
|
||||
"40": "contract creation: 0 wei + 612412 gas × 6000000000 wei"
|
||||
}
|
||||
},
|
||||
"queued": {
|
||||
"0x0f87ffcd71859233eb259f42b236c8e9873444e3": {
|
||||
"7": "0x3479BE69e07E838D9738a301Bb0c89e8EA2Bef4a: 1000000000000000 wei + 21000 gas × 10000000000 wei",
|
||||
"8": "0x73Aaf691bc33fe38f86260338EF88f9897eCaa4F: 1000000000000000 wei + 21000 gas × 10000000000 wei"
|
||||
},
|
||||
"0x307e8f249bcccfa5b245449256c5d7e6e079943e": {
|
||||
"3": "0x73Aaf691bc33fe38f86260338EF88f9897eCaa4F: 10000000000000000 wei + 21000 gas × 10000000000 wei"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let deserialized: TxpoolInspect = serde_json::from_str(txpool_inspect_json).unwrap();
|
||||
assert_eq!(deserialized, expected_txpool_inspect());
|
||||
|
||||
let serialized = serde_json::to_string(&deserialized).unwrap();
|
||||
let deserialized2: TxpoolInspect = serde_json::from_str(&serialized).unwrap();
|
||||
assert_eq!(deserialized2, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_txpool_status() {
|
||||
let txpool_status_json = r#"
|
||||
{
|
||||
"pending": "0x23",
|
||||
"queued": "0x20"
|
||||
}"#;
|
||||
let deserialized: TxpoolStatus = serde_json::from_str(txpool_status_json).unwrap();
|
||||
let serialized: String = serde_json::to_string_pretty(&deserialized).unwrap();
|
||||
assert_eq!(txpool_status_json.trim(), serialized);
|
||||
}
|
||||
|
||||
fn expected_txpool_inspect() -> TxpoolInspect {
|
||||
let mut pending_map = BTreeMap::new();
|
||||
let mut pending_map_inner = BTreeMap::new();
|
||||
pending_map_inner.insert(
|
||||
"124930".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("000000000000000000000000000000000000007E").unwrap()),
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(100187u128),
|
||||
gas_price: U256::from(20000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map.insert(
|
||||
Address::from_str("0512261a7486b1e29704ac49a5eb355b6fd86872").unwrap(),
|
||||
pending_map_inner.clone(),
|
||||
);
|
||||
pending_map_inner.clear();
|
||||
pending_map_inner.insert(
|
||||
"252350".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("d10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF").unwrap()),
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(65792u128),
|
||||
gas_price: U256::from(2000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map_inner.insert(
|
||||
"252351".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("d10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF").unwrap()),
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(65792u128),
|
||||
gas_price: U256::from(2000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map_inner.insert(
|
||||
"252352".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("d10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF").unwrap()),
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(65780u128),
|
||||
gas_price: U256::from(2000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map_inner.insert(
|
||||
"252353".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("d10e3Be2bc8f959Bc8C41CF65F60dE721cF89ADF").unwrap()),
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(65780u128),
|
||||
gas_price: U256::from(2000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map.insert(
|
||||
Address::from_str("201354729f8d0f8b64e9a0c353c672c6a66b3857").unwrap(),
|
||||
pending_map_inner.clone(),
|
||||
);
|
||||
pending_map_inner.clear();
|
||||
pending_map_inner.insert(
|
||||
"40".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: None,
|
||||
value: U256::from(0u128),
|
||||
gas: U256::from(612412u128),
|
||||
gas_price: U256::from(6000000000u128),
|
||||
},
|
||||
);
|
||||
pending_map.insert(
|
||||
Address::from_str("00000000863B56a3C1f0F1be8BC4F8b7BD78F57a").unwrap(),
|
||||
pending_map_inner,
|
||||
);
|
||||
let mut queued_map = BTreeMap::new();
|
||||
let mut queued_map_inner = BTreeMap::new();
|
||||
queued_map_inner.insert(
|
||||
"7".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("3479BE69e07E838D9738a301Bb0c89e8EA2Bef4a").unwrap()),
|
||||
value: U256::from(1000000000000000u128),
|
||||
gas: U256::from(21000u128),
|
||||
gas_price: U256::from(10000000000u128),
|
||||
},
|
||||
);
|
||||
queued_map_inner.insert(
|
||||
"8".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("73Aaf691bc33fe38f86260338EF88f9897eCaa4F").unwrap()),
|
||||
value: U256::from(1000000000000000u128),
|
||||
gas: U256::from(21000u128),
|
||||
gas_price: U256::from(10000000000u128),
|
||||
},
|
||||
);
|
||||
queued_map.insert(
|
||||
Address::from_str("0f87ffcd71859233eb259f42b236c8e9873444e3").unwrap(),
|
||||
queued_map_inner.clone(),
|
||||
);
|
||||
queued_map_inner.clear();
|
||||
queued_map_inner.insert(
|
||||
"3".to_string(),
|
||||
TxpoolInspectSummary {
|
||||
to: Some(Address::from_str("73Aaf691bc33fe38f86260338EF88f9897eCaa4F").unwrap()),
|
||||
value: U256::from(10000000000000000u128),
|
||||
gas: U256::from(21000u128),
|
||||
gas_price: U256::from(10000000000u128),
|
||||
},
|
||||
);
|
||||
queued_map.insert(
|
||||
Address::from_str("307e8f249bcccfa5b245449256c5d7e6e079943e").unwrap(),
|
||||
queued_map_inner,
|
||||
);
|
||||
|
||||
TxpoolInspect { pending: pending_map, queued: queued_map }
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,7 @@ pub mod eth;
|
||||
mod layers;
|
||||
mod net;
|
||||
mod trace;
|
||||
mod txpool;
|
||||
mod web3;
|
||||
|
||||
pub use admin::AdminApi;
|
||||
@ -29,6 +30,7 @@ pub use eth::{EthApi, EthApiSpec, EthFilter, EthPubSub, EthSubscriptionIdProvide
|
||||
pub use layers::{AuthLayer, AuthValidator, Claims, JwtAuthValidator, JwtError, JwtSecret};
|
||||
pub use net::NetApi;
|
||||
pub use trace::TraceApi;
|
||||
pub use txpool::TxPoolApi;
|
||||
pub use web3::Web3Api;
|
||||
|
||||
pub(crate) mod result;
|
||||
|
||||
147
crates/rpc/rpc/src/txpool.rs
Normal file
147
crates/rpc/rpc/src/txpool.rs
Normal file
@ -0,0 +1,147 @@
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee::core::RpcResult as Result;
|
||||
use reth_primitives::{Address, U256, U64};
|
||||
use reth_rpc_api::TxPoolApiServer;
|
||||
use reth_rpc_types::{
|
||||
txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
|
||||
Transaction,
|
||||
};
|
||||
use reth_transaction_pool::{AllPoolTransactions, PoolTransaction, TransactionPool};
|
||||
use std::collections::BTreeMap;
|
||||
use tracing::trace;
|
||||
|
||||
/// `txpool` API implementation.
|
||||
///
|
||||
/// This type provides the functionality for handling `txpool` related requests.
|
||||
#[derive(Clone)]
|
||||
pub struct TxPoolApi<Pool> {
|
||||
/// An interface to interact with the pool
|
||||
pool: Pool,
|
||||
}
|
||||
|
||||
impl<Pool> TxPoolApi<Pool> {
|
||||
/// Creates a new instance of `TxpoolApi`.
|
||||
pub fn new(pool: Pool) -> Self {
|
||||
TxPoolApi { pool }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pool> TxPoolApi<Pool>
|
||||
where
|
||||
Pool: TransactionPool + 'static,
|
||||
{
|
||||
fn content(&self) -> TxpoolContent {
|
||||
#[inline]
|
||||
fn insert<T: PoolTransaction>(
|
||||
tx: &T,
|
||||
content: &mut BTreeMap<Address, BTreeMap<String, Transaction>>,
|
||||
) {
|
||||
let entry = content.entry(tx.sender()).or_default();
|
||||
let key = tx.nonce().to_string();
|
||||
let tx = tx.to_recovered_transaction();
|
||||
let tx = Transaction::from_recovered(tx);
|
||||
entry.insert(key, tx);
|
||||
}
|
||||
|
||||
let AllPoolTransactions { pending, queued } = self.pool.all_transactions();
|
||||
|
||||
let mut content = TxpoolContent::default();
|
||||
for pending in pending {
|
||||
insert(&pending.transaction, &mut content.pending);
|
||||
}
|
||||
for queued in queued {
|
||||
insert(&queued.transaction, &mut content.queued);
|
||||
}
|
||||
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Pool> TxPoolApiServer for TxPoolApi<Pool>
|
||||
where
|
||||
Pool: TransactionPool + 'static,
|
||||
{
|
||||
/// Returns the number of transactions currently pending for inclusion in the next block(s), as
|
||||
/// well as the ones that are being scheduled for future execution only.
|
||||
/// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status)
|
||||
///
|
||||
/// Handler for `txpool_status`
|
||||
async fn txpool_status(&self) -> Result<TxpoolStatus> {
|
||||
trace!(target: "rpc::eth", "Serving txpool_status");
|
||||
let all = self.pool.all_transactions();
|
||||
Ok(TxpoolStatus {
|
||||
pending: U64::from(all.pending.len()),
|
||||
queued: U64::from(all.queued.len()),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns a summary of all the transactions currently pending for inclusion in the next
|
||||
/// block(s), as well as the ones that are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect) for more details
|
||||
///
|
||||
/// Handler for `txpool_inspect`
|
||||
async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
|
||||
trace!(target: "rpc::eth", "Serving txpool_inspect");
|
||||
|
||||
#[inline]
|
||||
fn insert<T: PoolTransaction>(
|
||||
tx: &T,
|
||||
inspect: &mut BTreeMap<Address, BTreeMap<String, TxpoolInspectSummary>>,
|
||||
) {
|
||||
let entry = inspect.entry(tx.sender()).or_default();
|
||||
let key = tx.nonce().to_string();
|
||||
let tx = tx.to_recovered_transaction();
|
||||
let to = tx.to();
|
||||
let gas_price = tx.transaction.max_fee_per_gas();
|
||||
let value = tx.value();
|
||||
let gas = tx.gas_limit();
|
||||
let summary = TxpoolInspectSummary {
|
||||
to,
|
||||
value: U256::from(value),
|
||||
gas: U256::from(gas),
|
||||
gas_price: U256::from(gas_price),
|
||||
};
|
||||
entry.insert(key, summary);
|
||||
}
|
||||
|
||||
let mut inspect = TxpoolInspect::default();
|
||||
let AllPoolTransactions { pending, queued } = self.pool.all_transactions();
|
||||
|
||||
for pending in pending {
|
||||
insert(&pending.transaction, &mut inspect.pending);
|
||||
}
|
||||
for queued in queued {
|
||||
insert(&queued.transaction, &mut inspect.queued);
|
||||
}
|
||||
|
||||
Ok(inspect)
|
||||
}
|
||||
|
||||
/// Retrieves the transactions contained within the txpool, returning pending as well as queued
|
||||
/// transactions of this address, grouped by nonce.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details
|
||||
/// Handler for `txpool_contentFrom`
|
||||
async fn txpool_content_from(&self, from: Address) -> Result<TxpoolContentFrom> {
|
||||
trace!(target: "rpc::eth", ?from, "Serving txpool_contentFrom");
|
||||
Ok(self.content().remove_from(&from))
|
||||
}
|
||||
|
||||
/// Returns the details of all transactions currently pending for inclusion in the next
|
||||
/// block(s), as well as the ones that are being scheduled for future execution only.
|
||||
///
|
||||
/// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
|
||||
/// Handler for `txpool_inspect`
|
||||
async fn txpool_content(&self) -> Result<TxpoolContent> {
|
||||
trace!(target: "rpc::eth", "Serving txpool_inspect");
|
||||
Ok(self.content())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Pool> std::fmt::Debug for TxPoolApi<Pool> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("TxpoolApi").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
@ -84,9 +84,9 @@ pub use crate::{
|
||||
config::PoolConfig,
|
||||
ordering::{CostOrdering, TransactionOrdering},
|
||||
traits::{
|
||||
BestTransactions, BlockInfo, CanonicalStateUpdate, ChangedAccount, PoolTransaction,
|
||||
PooledTransaction, PropagateKind, PropagatedTransactions, TransactionOrigin,
|
||||
TransactionPool,
|
||||
AllPoolTransactions, BestTransactions, BlockInfo, CanonicalStateUpdate, ChangedAccount,
|
||||
PoolTransaction, PooledTransaction, PropagateKind, PropagatedTransactions,
|
||||
TransactionOrigin, TransactionPool,
|
||||
},
|
||||
validate::{
|
||||
EthTransactionValidator, TransactionValidationOutcome, TransactionValidator,
|
||||
@ -313,6 +313,18 @@ where
|
||||
Box::new(self.pool.best_transactions())
|
||||
}
|
||||
|
||||
fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
|
||||
self.pool.pending_transactions()
|
||||
}
|
||||
|
||||
fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
|
||||
self.pool.queued_transactions()
|
||||
}
|
||||
|
||||
fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction> {
|
||||
self.pool.all_transactions()
|
||||
}
|
||||
|
||||
fn remove_transactions(
|
||||
&self,
|
||||
hashes: impl IntoIterator<Item = TxHash>,
|
||||
|
||||
@ -74,8 +74,8 @@ use crate::{
|
||||
txpool::{SenderInfo, TxPool},
|
||||
},
|
||||
traits::{
|
||||
BlockInfo, NewTransactionEvent, PoolSize, PoolTransaction, PropagatedTransactions,
|
||||
TransactionOrigin,
|
||||
AllPoolTransactions, BlockInfo, NewTransactionEvent, PoolSize, PoolTransaction,
|
||||
PropagatedTransactions, TransactionOrigin,
|
||||
},
|
||||
validate::{TransactionValidationOutcome, ValidPoolTransaction},
|
||||
CanonicalStateUpdate, ChangedAccount, PoolConfig, TransactionOrdering, TransactionValidator,
|
||||
@ -396,6 +396,25 @@ where
|
||||
self.pool.read().best_transactions()
|
||||
}
|
||||
|
||||
/// Returns all transactions from the pending sub-pool
|
||||
pub(crate) fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
|
||||
self.pool.read().pending_transactions()
|
||||
}
|
||||
|
||||
/// Returns all transactions from parked pools
|
||||
pub(crate) fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
|
||||
self.pool.read().queued_transactions()
|
||||
}
|
||||
|
||||
/// Returns all transactions in the pool
|
||||
pub(crate) fn all_transactions(&self) -> AllPoolTransactions<T::Transaction> {
|
||||
let pool = self.pool.read();
|
||||
AllPoolTransactions {
|
||||
pending: pool.pending_transactions(),
|
||||
queued: pool.queued_transactions(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes and returns all matching transactions from the pool.
|
||||
pub(crate) fn remove_transactions(
|
||||
&self,
|
||||
|
||||
@ -57,6 +57,13 @@ impl<T: ParkedOrd> ParkedPool<T> {
|
||||
self.best.insert(transaction);
|
||||
}
|
||||
|
||||
/// Returns an iterator over all transactions in the pool
|
||||
pub(crate) fn all(
|
||||
&self,
|
||||
) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
|
||||
self.by_id.values().map(|tx| tx.transaction.clone().into())
|
||||
}
|
||||
|
||||
/// Removes the transaction from the pool
|
||||
pub(crate) fn remove_transaction(
|
||||
&mut self,
|
||||
|
||||
@ -84,6 +84,13 @@ impl<T: TransactionOrdering> PendingPool<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over all transactions in the pool
|
||||
pub(crate) fn all(
|
||||
&self,
|
||||
) -> impl Iterator<Item = Arc<ValidPoolTransaction<T::Transaction>>> + '_ {
|
||||
self.by_id.values().map(|tx| tx.transaction.transaction.clone())
|
||||
}
|
||||
|
||||
/// Removes all transactions and their dependent transaction from the subpool that no longer
|
||||
/// satisfy the given basefee (`tx.fee < basefee`)
|
||||
///
|
||||
|
||||
@ -181,6 +181,18 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
self.pending_pool.best()
|
||||
}
|
||||
|
||||
/// Returns all transactions from the pending sub-pool
|
||||
pub(crate) fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
|
||||
self.pending_pool.all().collect()
|
||||
}
|
||||
|
||||
/// Returns all transactions from parked pools
|
||||
pub(crate) fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
|
||||
let mut queued = self.basefee_pool.all().collect::<Vec<_>>();
|
||||
queued.extend(self.queued_pool.all());
|
||||
queued
|
||||
}
|
||||
|
||||
/// Returns `true` if the transaction with the given hash is already included in this pool.
|
||||
pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
|
||||
self.all_transactions.contains(tx_hash)
|
||||
|
||||
@ -122,6 +122,28 @@ pub trait TransactionPool: Send + Sync + Clone {
|
||||
&self,
|
||||
) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>>;
|
||||
|
||||
/// Returns all transactions that can be included in the next block.
|
||||
///
|
||||
/// This is primarily used for the `txpool_` RPC namespace: <https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool> which distinguishes between `pending` and `queued` transactions, where `pending` are transactions ready for inclusion in the next block and `queued` are transactions that are ready for inclusion in future blocks.
|
||||
///
|
||||
/// Consumer: RPC
|
||||
fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>>;
|
||||
|
||||
/// Returns all transactions that can be included in _future_ blocks.
|
||||
///
|
||||
/// This and [Self::pending_transactions] are mutually exclusive.
|
||||
///
|
||||
/// Consumer: RPC
|
||||
fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>>;
|
||||
|
||||
/// Returns all transactions that are currently in the pool grouped by whether they are ready
|
||||
/// for inclusion in the next block or not.
|
||||
///
|
||||
/// This is primarily used for the `txpool_` namespace: <https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool>
|
||||
///
|
||||
/// Consumer: RPC
|
||||
fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction>;
|
||||
|
||||
/// Removes all transactions corresponding to the given hashes.
|
||||
///
|
||||
/// Also removes all _dependent_ transactions.
|
||||
@ -169,6 +191,31 @@ pub trait TransactionPool: Send + Sync + Clone {
|
||||
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>>;
|
||||
}
|
||||
|
||||
/// A Helper type that bundles all transactions in the pool.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct AllPoolTransactions<T: PoolTransaction> {
|
||||
/// Transactions that are ready for inclusion in the next block.
|
||||
pub pending: Vec<Arc<ValidPoolTransaction<T>>>,
|
||||
/// Transactions that are ready for inclusion in _future_ blocks, but are currently parked,
|
||||
/// because they depend on other transactions that are not yet included in the pool (nonce gap)
|
||||
/// or otherwise blocked.
|
||||
pub queued: Vec<Arc<ValidPoolTransaction<T>>>,
|
||||
}
|
||||
|
||||
// === impl AllPoolTransactions ===
|
||||
|
||||
impl<T: PoolTransaction> AllPoolTransactions<T> {
|
||||
/// Returns an iterator over all pending [TransactionSignedEcRecovered] transactions.
|
||||
pub fn pending_recovered(&self) -> impl Iterator<Item = TransactionSignedEcRecovered> + '_ {
|
||||
self.pending.iter().map(|tx| tx.transaction.to_recovered_transaction())
|
||||
}
|
||||
|
||||
/// Returns an iterator over all queued [TransactionSignedEcRecovered] transactions.
|
||||
pub fn queued_recovered(&self) -> impl Iterator<Item = TransactionSignedEcRecovered> + '_ {
|
||||
self.queued.iter().map(|tx| tx.transaction.to_recovered_transaction())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a transaction that was propagated over the network.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct PropagatedTransactions(pub HashMap<TxHash, Vec<PropagateKind>>);
|
||||
|
||||
Reference in New Issue
Block a user