diff --git a/Cargo.lock b/Cargo.lock index 6b809a08dbac..8f1cccc13ad7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8383,6 +8383,7 @@ dependencies = [ "reth-tasks", "reth-testing-utils", "reth-tokio-util", + "reth-transaction-pool", "serde", "thiserror", "tokio", @@ -8497,6 +8498,7 @@ dependencies = [ name = "reth-rpc-types" version = "1.0.6" dependencies = [ + "alloy-eips", "alloy-primitives", "alloy-rpc-types", "alloy-rpc-types-admin", @@ -8513,6 +8515,7 @@ dependencies = [ "op-alloy-rpc-types", "op-alloy-rpc-types-engine", "rand 0.8.5", + "serde", ] [[package]] @@ -8764,6 +8767,7 @@ dependencies = [ "reth-metrics", "reth-primitives", "reth-provider", + "reth-rpc-types", "reth-storage-api", "reth-tasks", "reth-tracing", diff --git a/crates/node/builder/src/launch/engine.rs b/crates/node/builder/src/launch/engine.rs index 506d3b8f5c96..4c2a125b340f 100644 --- a/crates/node/builder/src/launch/engine.rs +++ b/crates/node/builder/src/launch/engine.rs @@ -267,6 +267,7 @@ where ctx.chain_spec(), beacon_engine_handle, ctx.components().payload_builder().clone().into(), + ctx.components().pool().clone(), Box::new(ctx.task_executor().clone()), client, EngineCapabilities::default(), diff --git a/crates/node/builder/src/launch/mod.rs b/crates/node/builder/src/launch/mod.rs index 0d03f8f7ebfe..2e0b9bec4e4d 100644 --- a/crates/node/builder/src/launch/mod.rs +++ b/crates/node/builder/src/launch/mod.rs @@ -352,6 +352,7 @@ where ctx.chain_spec(), beacon_engine_handle, ctx.components().payload_builder().clone().into(), + ctx.components().pool().clone(), Box::new(ctx.task_executor().clone()), client, EngineCapabilities::default(), diff --git a/crates/rpc/rpc-api/src/engine.rs b/crates/rpc/rpc-api/src/engine.rs index 23537b5271c3..c0e72bf1ab17 100644 --- a/crates/rpc/rpc-api/src/engine.rs +++ b/crates/rpc/rpc-api/src/engine.rs @@ -14,8 +14,8 @@ use reth_rpc_types::{ ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, TransitionConfiguration, }, state::StateOverride, - BlockOverrides, EIP1186AccountProofResponse, Filter, JsonStorageKey, Log, SyncStatus, - TransactionRequest, + BlobAndProofV1, BlockOverrides, EIP1186AccountProofResponse, Filter, JsonStorageKey, Log, + SyncStatus, TransactionRequest, }; // NOTE: We can't use associated types in the `EngineApi` trait because of jsonrpsee, so we use a // generic here. It would be nice if the rpc macro would understand which types need to have serde. @@ -213,6 +213,13 @@ pub trait EngineApi { /// See also #[method(name = "exchangeCapabilities")] async fn exchange_capabilities(&self, capabilities: Vec) -> RpcResult>; + + /// Fetch blobs for the consensus layer from the in-memory blob cache. + #[method(name = "getBlobsV1")] + async fn get_blobs_v1( + &self, + transaction_ids: Vec, + ) -> RpcResult>>; } /// A subset of the ETH rpc interface: diff --git a/crates/rpc/rpc-builder/tests/it/utils.rs b/crates/rpc/rpc-builder/tests/it/utils.rs index 85d81ea39f09..14104492000c 100644 --- a/crates/rpc/rpc-builder/tests/it/utils.rs +++ b/crates/rpc/rpc-builder/tests/it/utils.rs @@ -17,7 +17,10 @@ use reth_rpc_layer::JwtSecret; use reth_rpc_server_types::RpcModuleSelection; use reth_rpc_types::engine::{ClientCode, ClientVersionV1}; use reth_tasks::TokioTaskExecutor; -use reth_transaction_pool::test_utils::{TestPool, TestPoolBuilder}; +use reth_transaction_pool::{ + noop::NoopTransactionPool, + test_utils::{TestPool, TestPoolBuilder}, +}; use tokio::sync::mpsc::unbounded_channel; /// Localhost with port 0 so a free port is used. @@ -43,6 +46,7 @@ pub async fn launch_auth(secret: JwtSecret) -> AuthServerHandle { MAINNET.clone(), beacon_engine_handle, spawn_test_payload_service().into(), + NoopTransactionPool::default(), Box::::default(), client, EngineCapabilities::default(), diff --git a/crates/rpc/rpc-engine-api/Cargo.toml b/crates/rpc/rpc-engine-api/Cargo.toml index d067515f6c2a..8415c594b724 100644 --- a/crates/rpc/rpc-engine-api/Cargo.toml +++ b/crates/rpc/rpc-engine-api/Cargo.toml @@ -25,6 +25,7 @@ reth-tasks.workspace = true reth-rpc-types-compat.workspace = true reth-engine-primitives.workspace = true reth-evm.workspace = true +reth-transaction-pool.workspace = true # async tokio = { workspace = true, features = ["sync"] } diff --git a/crates/rpc/rpc-engine-api/src/capabilities.rs b/crates/rpc/rpc-engine-api/src/capabilities.rs index eb796aebcd0c..de4d96231538 100644 --- a/crates/rpc/rpc-engine-api/src/capabilities.rs +++ b/crates/rpc/rpc-engine-api/src/capabilities.rs @@ -19,6 +19,7 @@ pub const CAPABILITIES: &[&str] = &[ "engine_getPayloadBodiesByRangeV1", "engine_getPayloadBodiesByHashV2", "engine_getPayloadBodiesByRangeV2", + "engine_getBlobsV1", ]; // The list of all supported Engine capabilities available over the engine endpoint. diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index d22590a3aa08..6571ffd8bc7d 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -16,17 +16,21 @@ use reth_primitives::{ Block, BlockHash, BlockHashOrNumber, BlockNumber, EthereumHardfork, B256, U64, }; use reth_rpc_api::EngineApiServer; -use reth_rpc_types::engine::{ - CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, - ExecutionPayloadBodiesV2, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, - ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, - TransitionConfiguration, +use reth_rpc_types::{ + engine::{ + CancunPayloadFields, ClientVersionV1, ExecutionPayload, ExecutionPayloadBodiesV1, + ExecutionPayloadBodiesV2, ExecutionPayloadInputV2, ExecutionPayloadV1, ExecutionPayloadV3, + ExecutionPayloadV4, ForkchoiceState, ForkchoiceUpdated, PayloadId, PayloadStatus, + TransitionConfiguration, + }, + BlobAndProofV1, }; use reth_rpc_types_compat::engine::payload::{ convert_payload_input_v2_to_payload, convert_to_payload_body_v1, convert_to_payload_body_v2, }; use reth_storage_api::{BlockReader, HeaderProvider, StateProviderFactory}; use reth_tasks::TaskSpawner; +use reth_transaction_pool::TransactionPool; use std::{sync::Arc, time::Instant}; use tokio::sync::oneshot; use tracing::{trace, warn}; @@ -37,13 +41,16 @@ pub type EngineApiSender = oneshot::Sender>; /// The upper limit for payload bodies request. const MAX_PAYLOAD_BODIES_LIMIT: u64 = 1024; +/// The upper limit blobs `eth_getBlobs`. +const MAX_BLOB_LIMIT: usize = 128; + /// The Engine API implementation that grants the Consensus layer access to data and /// functions in the Execution layer that are crucial for the consensus process. -pub struct EngineApi { - inner: Arc>, +pub struct EngineApi { + inner: Arc>, } -struct EngineApiInner { +struct EngineApiInner { /// The provider to interact with the chain. provider: Provider, /// Consensus configuration @@ -60,19 +67,24 @@ struct EngineApiInner { client: ClientVersionV1, /// The list of all supported Engine capabilities available over the engine endpoint. capabilities: EngineCapabilities, + /// Transaction pool. + tx_pool: Pool, } -impl EngineApi +impl EngineApi where Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static, EngineT: EngineTypes, + Pool: TransactionPool + 'static, { /// Create new instance of [`EngineApi`]. + #[allow(clippy::too_many_arguments)] pub fn new( provider: Provider, chain_spec: Arc, beacon_consensus: BeaconConsensusEngineHandle, payload_store: PayloadStore, + tx_pool: Pool, task_spawner: Box, client: ClientVersionV1, capabilities: EngineCapabilities, @@ -86,6 +98,7 @@ where metrics: EngineApiMetrics::default(), client, capabilities, + tx_pool, }); Self { inner } } @@ -609,10 +622,11 @@ where } #[async_trait] -impl EngineApiServer for EngineApi +impl EngineApiServer for EngineApi where Provider: HeaderProvider + BlockReader + StateProviderFactory + EvmEnvProvider + 'static, EngineT: EngineTypes, + Pool: TransactionPool + 'static, { /// Handler for `engine_newPayloadV1` /// See also @@ -904,9 +918,25 @@ where async fn exchange_capabilities(&self, _capabilities: Vec) -> RpcResult> { Ok(self.inner.capabilities.list()) } + + async fn get_blobs_v1( + &self, + versioned_hashes: Vec, + ) -> RpcResult>> { + trace!(target: "rpc::engine", "Serving engine_getBlobsV1"); + if versioned_hashes.len() > MAX_BLOB_LIMIT { + return Err(EngineApiError::BlobRequestTooLarge { len: versioned_hashes.len() }.into()) + } + + Ok(self + .inner + .tx_pool + .get_blobs_for_versioned_hashes(&versioned_hashes) + .map_err(|err| EngineApiError::Internal(Box::new(err)))?) + } } -impl std::fmt::Debug for EngineApi +impl std::fmt::Debug for EngineApi where EngineT: EngineTypes, { @@ -920,20 +950,21 @@ mod tests { use super::*; use assert_matches::assert_matches; use reth_beacon_consensus::{BeaconConsensusEngineEvent, BeaconEngineMessage}; - use reth_ethereum_engine_primitives::EthEngineTypes; - use reth_testing_utils::generators::random_block; - use reth_chainspec::MAINNET; + use reth_ethereum_engine_primitives::EthEngineTypes; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_primitives::SealedBlock; use reth_provider::test_utils::MockEthProvider; use reth_rpc_types::engine::{ClientCode, ClientVersionV1}; use reth_rpc_types_compat::engine::payload::execution_payload_from_sealed_block; use reth_tasks::TokioTaskExecutor; + use reth_testing_utils::generators::random_block; use reth_tokio_util::EventSender; + use reth_transaction_pool::noop::NoopTransactionPool; use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver}; - fn setup_engine_api() -> (EngineApiTestHandle, EngineApi, EthEngineTypes>) + fn setup_engine_api( + ) -> (EngineApiTestHandle, EngineApi, EthEngineTypes, NoopTransactionPool>) { let client = ClientVersionV1 { code: ClientCode::RH, @@ -953,6 +984,7 @@ mod tests { chain_spec.clone(), BeaconConsensusEngineHandle::new(to_engine, event_sender), payload_store.into(), + NoopTransactionPool::default(), task_executor, client, EngineCapabilities::default(), diff --git a/crates/rpc/rpc-engine-api/src/error.rs b/crates/rpc/rpc-engine-api/src/error.rs index a1e4dc328995..17c527956ac0 100644 --- a/crates/rpc/rpc-engine-api/src/error.rs +++ b/crates/rpc/rpc-engine-api/src/error.rs @@ -42,6 +42,12 @@ pub enum EngineApiError { /// The length that was requested. len: u64, }, + /// Too many requested versioned hashes for blobs request + #[error("requested blob count too large: {len}")] + BlobRequestTooLarge { + /// The length that was requested. + len: usize, + }, /// Thrown if `engine_getPayloadBodiesByRangeV1` contains an invalid range #[error("invalid start ({start}) or count ({count})")] InvalidBodiesRange { @@ -145,7 +151,8 @@ impl From for jsonrpsee_types::error::ErrorObject<'static> { error.to_string(), None::<()>, ), - EngineApiError::PayloadRequestTooLarge { .. } => { + EngineApiError::PayloadRequestTooLarge { .. } | + EngineApiError::BlobRequestTooLarge { .. } => { jsonrpsee_types::error::ErrorObject::owned( REQUEST_TOO_LARGE_CODE, REQUEST_TOO_LARGE_MESSAGE, diff --git a/crates/rpc/rpc-types/Cargo.toml b/crates/rpc/rpc-types/Cargo.toml index 32362cc3007c..8d3973a56b97 100644 --- a/crates/rpc/rpc-types/Cargo.toml +++ b/crates/rpc/rpc-types/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] # ethereum +alloy-eips.workspace = true alloy-primitives = { workspace = true, features = ["rand", "rlp", "serde"] } alloy-rpc-types.workspace = true alloy-rpc-types-admin.workspace = true @@ -32,6 +33,7 @@ op-alloy-rpc-types-engine.workspace = true # misc jsonrpsee-types = { workspace = true, optional = true } +serde.workspace = true [dev-dependencies] # misc diff --git a/crates/rpc/rpc-types/src/lib.rs b/crates/rpc/rpc-types/src/lib.rs index dc0eb3dec5c9..03c681a8b8a4 100644 --- a/crates/rpc/rpc-types/src/lib.rs +++ b/crates/rpc/rpc-types/src/lib.rs @@ -61,6 +61,18 @@ pub use eth::{ }, }; +use alloy_eips::eip4844::{Blob, Bytes48}; +use serde::{Deserialize, Serialize}; + +/// Blob type returned in responses to `engine_getBlobsV1`: +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct BlobAndProofV1 { + /// The blob data. + pub blob: Box, + /// The KZG proof for the blob. + pub proof: Bytes48, +} + /// Optimism specific rpc types. pub mod optimism { pub use op_alloy_rpc_types::*; diff --git a/crates/transaction-pool/Cargo.toml b/crates/transaction-pool/Cargo.toml index 95ebea623364..1daa6b4b2149 100644 --- a/crates/transaction-pool/Cargo.toml +++ b/crates/transaction-pool/Cargo.toml @@ -18,6 +18,7 @@ reth-chainspec.workspace = true reth-eth-wire-types.workspace = true reth-primitives = { workspace = true, features = ["c-kzg", "secp256k1"] } reth-execution-types.workspace = true +reth-rpc-types.workspace = true reth-fs-util.workspace = true reth-storage-api.workspace = true reth-tasks.workspace = true diff --git a/crates/transaction-pool/src/blobstore/disk.rs b/crates/transaction-pool/src/blobstore/disk.rs index c43d4565080a..94b200590f55 100644 --- a/crates/transaction-pool/src/blobstore/disk.rs +++ b/crates/transaction-pool/src/blobstore/disk.rs @@ -5,6 +5,7 @@ use alloy_primitives::{TxHash, B256}; use alloy_rlp::{Decodable, Encodable}; use parking_lot::{Mutex, RwLock}; use reth_primitives::BlobTransactionSidecar; +use reth_rpc_types::BlobAndProofV1; use schnellru::{ByLength, LruMap}; use std::{collections::HashSet, fmt, fs, io, path::PathBuf, sync::Arc}; use tracing::{debug, trace}; @@ -128,6 +129,31 @@ impl BlobStore for DiskFileBlobStore { self.inner.get_exact(txs) } + fn get_by_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + let mut result = vec![None; versioned_hashes.len()]; + for (_tx_hash, blob_sidecar) in self.inner.blob_cache.lock().iter() { + for (i, blob_versioned_hash) in blob_sidecar.versioned_hashes().enumerate() { + for (j, target_versioned_hash) in versioned_hashes.iter().enumerate() { + if blob_versioned_hash == *target_versioned_hash { + result[j].get_or_insert_with(|| BlobAndProofV1 { + blob: Box::new(blob_sidecar.blobs[i]), + proof: blob_sidecar.proofs[i], + }); + } + } + } + + // Return early if all blobs are found. + if result.iter().all(|blob| blob.is_some()) { + break; + } + } + Ok(result) + } + fn data_size_hint(&self) -> Option { Some(self.inner.size_tracker.data_size()) } diff --git a/crates/transaction-pool/src/blobstore/mem.rs b/crates/transaction-pool/src/blobstore/mem.rs index 0d8cbda35970..ebde21fb4dab 100644 --- a/crates/transaction-pool/src/blobstore/mem.rs +++ b/crates/transaction-pool/src/blobstore/mem.rs @@ -3,6 +3,7 @@ use crate::blobstore::{ }; use alloy_primitives::B256; use parking_lot::RwLock; +use reth_rpc_types::BlobAndProofV1; use std::{collections::HashMap, sync::Arc}; /// An in-memory blob store. @@ -113,6 +114,31 @@ impl BlobStore for InMemoryBlobStore { Ok(items) } + fn get_by_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + let mut result = vec![None; versioned_hashes.len()]; + for (_tx_hash, blob_sidecar) in self.inner.store.read().iter() { + for (i, blob_versioned_hash) in blob_sidecar.versioned_hashes().enumerate() { + for (j, target_versioned_hash) in versioned_hashes.iter().enumerate() { + if blob_versioned_hash == *target_versioned_hash { + result[j].get_or_insert_with(|| BlobAndProofV1 { + blob: Box::new(blob_sidecar.blobs[i]), + proof: blob_sidecar.proofs[i], + }); + } + } + } + + // Return early if all blobs are found. + if result.iter().all(|blob| blob.is_some()) { + break; + } + } + Ok(result) + } + fn data_size_hint(&self) -> Option { Some(self.inner.size_tracker.data_size()) } diff --git a/crates/transaction-pool/src/blobstore/mod.rs b/crates/transaction-pool/src/blobstore/mod.rs index ea973003bfa1..3f38b41f4cb0 100644 --- a/crates/transaction-pool/src/blobstore/mod.rs +++ b/crates/transaction-pool/src/blobstore/mod.rs @@ -5,6 +5,7 @@ pub use disk::{DiskFileBlobStore, DiskFileBlobStoreConfig, OpenDiskFileBlobStore pub use mem::InMemoryBlobStore; pub use noop::NoopBlobStore; use reth_primitives::BlobTransactionSidecar; +use reth_rpc_types::BlobAndProofV1; use std::{ fmt, sync::atomic::{AtomicUsize, Ordering}, @@ -65,6 +66,12 @@ pub trait BlobStore: fmt::Debug + Send + Sync + 'static { /// Returns an error if any of the blobs are not found in the blob store. fn get_exact(&self, txs: Vec) -> Result, BlobStoreError>; + /// Return the [`BlobTransactionSidecar`]s for a list of blob versioned hashes. + fn get_by_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError>; + /// Data size of all transactions in the blob store. fn data_size_hint(&self) -> Option; diff --git a/crates/transaction-pool/src/blobstore/noop.rs b/crates/transaction-pool/src/blobstore/noop.rs index 975e97c111b4..e8d2931730ca 100644 --- a/crates/transaction-pool/src/blobstore/noop.rs +++ b/crates/transaction-pool/src/blobstore/noop.rs @@ -1,5 +1,6 @@ use crate::blobstore::{BlobStore, BlobStoreCleanupStat, BlobStoreError, BlobTransactionSidecar}; use alloy_primitives::B256; +use reth_rpc_types::BlobAndProofV1; /// A blobstore implementation that does nothing #[derive(Clone, Copy, Debug, PartialOrd, PartialEq, Eq, Default)] @@ -49,6 +50,13 @@ impl BlobStore for NoopBlobStore { Err(BlobStoreError::MissingSidecar(txs[0])) } + fn get_by_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + Ok(vec![None; versioned_hashes.len()]) + } + fn data_size_hint(&self) -> Option { Some(0) } diff --git a/crates/transaction-pool/src/lib.rs b/crates/transaction-pool/src/lib.rs index 75b1324ba5c4..bd734e18b31a 100644 --- a/crates/transaction-pool/src/lib.rs +++ b/crates/transaction-pool/src/lib.rs @@ -151,11 +151,12 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] use crate::{identifier::TransactionId, pool::PoolInner}; -use alloy_primitives::{Address, TxHash, U256}; +use alloy_primitives::{Address, TxHash, B256, U256}; use aquamarine as _; use reth_eth_wire_types::HandleMempoolData; use reth_execution_types::ChangedAccount; use reth_primitives::{BlobTransactionSidecar, PooledTransactionsElement}; +use reth_rpc_types::BlobAndProofV1; use reth_storage_api::StateProviderFactory; use std::{collections::HashSet, sync::Arc}; use tokio::sync::mpsc::Receiver; @@ -526,6 +527,13 @@ where self.pool.blob_store().get_exact(tx_hashes) } + fn get_blobs_for_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + self.pool.blob_store().get_by_versioned_hashes(versioned_hashes) + } + /// Returns all pending transactions filtered by [`TransactionOrigin`] fn get_pending_transactions_by_origin( &self, diff --git a/crates/transaction-pool/src/noop.rs b/crates/transaction-pool/src/noop.rs index 7a6939d31885..aaa221c53f11 100644 --- a/crates/transaction-pool/src/noop.rs +++ b/crates/transaction-pool/src/noop.rs @@ -16,9 +16,10 @@ use crate::{ PooledTransactionsElement, PropagatedTransactions, TransactionEvents, TransactionOrigin, TransactionPool, TransactionValidationOutcome, TransactionValidator, ValidPoolTransaction, }; -use alloy_primitives::{Address, TxHash, U256}; +use alloy_primitives::{Address, TxHash, B256, U256}; use reth_eth_wire_types::HandleMempoolData; use reth_primitives::BlobTransactionSidecar; +use reth_rpc_types::BlobAndProofV1; use std::{collections::HashSet, marker::PhantomData, sync::Arc}; use tokio::sync::{mpsc, mpsc::Receiver}; @@ -244,6 +245,13 @@ impl TransactionPool for NoopTransactionPool { Err(BlobStoreError::MissingSidecar(tx_hashes[0])) } + fn get_blobs_for_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError> { + Ok(vec![None; versioned_hashes.len()]) + } + fn get_pending_transactions_by_origin( &self, _origin: TransactionOrigin, diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index cd96c30c0f17..c0e5fae154a0 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -17,6 +17,7 @@ use reth_primitives::{ PooledTransactionsElementEcRecovered, SealedBlock, Transaction, TransactionSignedEcRecovered, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID, }; +use reth_rpc_types::BlobAndProofV1; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::{ @@ -414,6 +415,12 @@ pub trait TransactionPool: Send + Sync + Clone { &self, tx_hashes: Vec, ) -> Result, BlobStoreError>; + + /// Return the [`BlobTransactionSidecar`]s for a list of blob versioned hashes. + fn get_blobs_for_versioned_hashes( + &self, + versioned_hashes: &[B256], + ) -> Result>, BlobStoreError>; } /// Extension for [TransactionPool] trait that allows to set the current block info.