diff --git a/Cargo.lock b/Cargo.lock index aedc8a659c9..7a394e5a92f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3392,6 +3392,7 @@ dependencies = [ "alloy-eips 1.0.5", "alloy-evm", "alloy-genesis", + "alloy-network", "alloy-op-evm", "alloy-primitives", "alloy-rlp", @@ -3405,21 +3406,135 @@ dependencies = [ "op-alloy-consensus", "op-alloy-rpc-types-engine", "op-revm", + "reth-basic-payload-builder", "reth-chain-state", + "reth-chainspec", + "reth-cli", + "reth-cli-commands", + "reth-cli-runner", + "reth-cli-util", "reth-codecs", + "reth-codecs-derive", + "reth-config", + "reth-consensus", + "reth-consensus-common", + "reth-consensus-debug-client", + "reth-db", + "reth-db-api", + "reth-db-common", + "reth-db-models", + "reth-discv4", + "reth-discv5", + "reth-dns-discovery", + "reth-downloaders", + "reth-e2e-test-utils", + "reth-ecies", + "reth-engine-local", + "reth-engine-primitives", + "reth-engine-service", + "reth-engine-tree", + "reth-engine-util", + "reth-era", + "reth-era-downloader", + "reth-era-utils", + "reth-errors", + "reth-eth-wire", + "reth-eth-wire-types", "reth-ethereum", + "reth-ethereum-cli", + "reth-ethereum-consensus", + "reth-ethereum-engine-primitives", + "reth-ethereum-forks", + "reth-ethereum-payload-builder", + "reth-ethereum-primitives", + "reth-etl", + "reth-evm", + "reth-evm-ethereum", + "reth-execution-errors", + "reth-execution-types", + "reth-exex", + "reth-exex-test-utils", + "reth-exex-types", + "reth-fs-util", + "reth-invalid-block-hooks", + "reth-ipc", + "reth-libmdbx", + "reth-mdbx-sys", + "reth-metrics", + "reth-net-banlist", + "reth-net-nat", + "reth-network", + "reth-network-api", + "reth-network-p2p", "reth-network-peers", + "reth-network-types", + "reth-nippy-jar", + "reth-node-api", "reth-node-builder", + "reth-node-core", + "reth-node-ethereum", + "reth-node-events", + "reth-node-metrics", + "reth-node-types", "reth-op", + "reth-optimism-chainspec", + "reth-optimism-cli", "reth-optimism-consensus", + "reth-optimism-evm", "reth-optimism-forks", + "reth-optimism-node", + "reth-optimism-payload-builder", + "reth-optimism-primitives", + "reth-optimism-rpc", + "reth-optimism-storage", + "reth-optimism-txpool", "reth-payload-builder", + "reth-payload-builder-primitives", + "reth-payload-primitives", + "reth-payload-util", + "reth-payload-validator", + "reth-primitives", + "reth-primitives-traits", + "reth-provider", + "reth-prune", + "reth-prune-types", + "reth-ress-protocol", + "reth-ress-provider", + "reth-revm", + "reth-rpc", "reth-rpc-api", + "reth-rpc-api-testing-util", + "reth-rpc-builder", "reth-rpc-engine-api", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-layer", + "reth-rpc-server-types", + "reth-rpc-types-compat", + "reth-stages", + "reth-stages-api", + "reth-stages-types", + "reth-stateless", + "reth-static-file", + "reth-static-file-types", + "reth-storage-api", + "reth-storage-errors", + "reth-tasks", + "reth-testing-utils", + "reth-tokio-util", + "reth-tracing", + "reth-transaction-pool", + "reth-trie", + "reth-trie-common", + "reth-trie-db", + "reth-trie-parallel", + "reth-trie-sparse", + "reth-zstd-compressors", "revm", "revm-primitives", "serde", "test-fuzz", + "tokio", ] [[package]] diff --git a/examples/custom-node/Cargo.toml b/examples/custom-node/Cargo.toml index 886f2509fe0..fa0bf4ade6c 100644 --- a/examples/custom-node/Cargo.toml +++ b/examples/custom-node/Cargo.toml @@ -19,11 +19,126 @@ reth-rpc-api.workspace = true reth-rpc-engine-api.workspace = true reth-ethereum = { workspace = true, features = ["node-api", "network", "evm", "pool"] } +reth-basic-payload-builder.workspace = true +reth-chainspec.workspace = true +reth-cli.workspace = true +reth-cli-commands.workspace = true +reth-cli-runner.workspace = true +reth-cli-util.workspace = true +reth-codecs-derive.workspace = true +reth-config.workspace = true +reth-consensus.workspace = true +reth-consensus-common.workspace = true +reth-consensus-debug-client.workspace = true +reth-db.workspace = true +reth-db-api.workspace = true +reth-db-common.workspace = true +reth-db-models.workspace = true +reth-discv4.workspace = true +reth-discv5.workspace = true +reth-dns-discovery.workspace = true +reth-downloaders.workspace = true +reth-e2e-test-utils.workspace = true +reth-ecies.workspace = true +reth-engine-local.workspace = true +reth-engine-primitives.workspace = true +reth-engine-tree.workspace = true +reth-engine-service.workspace = true +reth-engine-util.workspace = true +reth-era.workspace = true +reth-era-downloader.workspace = true +reth-era-utils.workspace = true +reth-errors.workspace = true +reth-eth-wire.workspace = true +reth-eth-wire-types.workspace = true +reth-ethereum-cli.workspace = true +reth-ethereum-consensus.workspace = true +reth-ethereum-engine-primitives.workspace = true +reth-ethereum-forks.workspace = true +reth-ethereum-payload-builder.workspace = true +reth-ethereum-primitives.workspace = true +reth-etl.workspace = true +reth-evm.workspace = true +reth-evm-ethereum.workspace = true +reth-optimism-evm.workspace = true +reth-execution-errors.workspace = true +reth-execution-types.workspace = true +reth-exex.workspace = true +reth-exex-test-utils.workspace = true +reth-exex-types.workspace = true +reth-fs-util.workspace = true +reth-invalid-block-hooks.workspace = true +reth-ipc.workspace = true +reth-libmdbx.workspace = true +reth-mdbx-sys.workspace = true +reth-metrics.workspace = true +reth-net-banlist.workspace = true +reth-net-nat.workspace = true +reth-network.workspace = true +reth-network-api.workspace = true +reth-network-p2p.workspace = true +reth-network-types.workspace = true +reth-nippy-jar.workspace = true +reth-node-api.workspace = true +reth-node-core.workspace = true +reth-node-ethereum.workspace = true +reth-node-events.workspace = true +reth-node-metrics.workspace = true +reth-optimism-node.workspace = true +reth-node-types.workspace = true +reth-optimism-chainspec.workspace = true +reth-optimism-cli.workspace = true +reth-optimism-payload-builder.workspace = true +reth-optimism-primitives.workspace = true +reth-optimism-rpc.workspace = true +reth-optimism-storage.workspace = true +reth-optimism-txpool.workspace = true +reth-payload-builder-primitives.workspace = true +reth-payload-primitives.workspace = true +reth-payload-validator.workspace = true +reth-payload-util.workspace = true +reth-primitives.workspace = true +reth-primitives-traits.workspace = true +reth-provider.workspace = true +reth-prune.workspace = true +reth-prune-types.workspace = true +reth-revm.workspace = true +reth-rpc.workspace = true +reth-rpc-api-testing-util.workspace = true +reth-rpc-builder.workspace = true +reth-rpc-eth-api.workspace = true +reth-rpc-eth-types.workspace = true +reth-rpc-layer.workspace = true +reth-rpc-server-types.workspace = true +reth-rpc-types-compat.workspace = true +reth-stages.workspace = true +reth-stages-api.workspace = true +reth-stages-types.workspace = true +reth-stateless.workspace = true +reth-static-file.workspace = true +reth-static-file-types.workspace = true +reth-storage-api.workspace = true +reth-storage-errors.workspace = true +reth-tasks.workspace = true +reth-testing-utils.workspace = true +reth-tokio-util.workspace = true +reth-tracing.workspace = true +reth-transaction-pool.workspace = true +reth-trie.workspace = true +reth-trie-common.workspace = true +reth-trie-db.workspace = true +reth-trie-parallel.workspace = true +reth-trie-sparse.workspace = true +reth-zstd-compressors.workspace = true +reth-ress-protocol.workspace = true +reth-ress-provider.workspace = true + # revm revm.workspace = true revm-primitives.workspace = true # alloy +alloy-network.workspace = true alloy-consensus = { workspace = true, features = ["serde"] } alloy-eips.workspace = true alloy-evm.workspace = true @@ -43,6 +158,7 @@ derive_more.workspace = true eyre.workspace = true jsonrpsee.workspace = true serde.workspace = true +tokio.workspace = true modular-bitfield.workspace = true diff --git a/examples/custom-node/src/chainspec.rs b/examples/custom-node/src/chainspec.rs index 3ac6b51f149..bec80e4139b 100644 --- a/examples/custom-node/src/chainspec.rs +++ b/examples/custom-node/src/chainspec.rs @@ -14,6 +14,12 @@ pub struct CustomChainSpec { genesis_header: SealedHeader, } +impl CustomChainSpec { + pub fn inner(&self) -> &OpChainSpec { + &self.inner + } +} + impl Hardforks for CustomChainSpec { fn fork(&self, fork: H) -> reth_ethereum::chainspec::ForkCondition { self.inner.fork(fork) diff --git a/examples/custom-node/src/evm.rs b/examples/custom-node/src/evm.rs index 18dfc790ec0..05409243931 100644 --- a/examples/custom-node/src/evm.rs +++ b/examples/custom-node/src/evm.rs @@ -1,15 +1,24 @@ -use crate::chainspec::CustomChainSpec; -use alloy_consensus::{Block, Header}; +use crate::{ + chainspec::CustomChainSpec, + primitives::{block::Block, tx, CustomHeader, CustomNodePrimitives, CustomTransaction}, +}; +use alloy_consensus::Header; +use alloy_eips::Encodable2718; use alloy_evm::{ block::{ BlockExecutionError, BlockExecutionResult, BlockExecutor, BlockExecutorFactory, BlockExecutorFor, ExecutableTx, OnStateHook, }, precompiles::PrecompilesMap, - Database, Evm, EvmEnv, + Database, Evm, EvmEnv, FromRecoveredTx, FromTxWithEncoded, +}; +use alloy_op_evm::{ + block::receipt_builder::OpReceiptBuilder, OpBlockExecutionCtx, OpBlockExecutor, OpEvm, }; -use alloy_op_evm::{OpBlockExecutionCtx, OpBlockExecutor, OpEvm}; +use alloy_primitives::{Address, Bytes, TxKind, B256, U256}; +use op_alloy_consensus::OpTxEnvelope; use op_revm::{OpSpecId, OpTransaction}; +use reth_chainspec::{ChainSpecProvider, EthChainSpec}; use reth_ethereum::{ evm::primitives::{ execute::{BlockAssembler, BlockAssemblerInput}, @@ -23,14 +32,140 @@ use reth_op::{ node::{ OpBlockAssembler, OpEvmConfig, OpEvmFactory, OpNextBlockEnvAttributes, OpRethReceiptBuilder, }, - DepositReceipt, OpPrimitives, OpReceipt, OpTransactionSigned, -}; -use revm::{ - context::{result::ExecutionResult, TxEnv}, - database::State, + DepositReceipt, OpReceipt, OpTransactionSigned, }; +use reth_primitives_traits::NodePrimitives; +use reth_revm::context::TxEnv; +use revm::{context::result::ExecutionResult, database::State}; use std::sync::Arc; +pub struct CustomTxEnv(TxEnv); + +impl revm::context::Transaction for CustomTxEnv { + type AccessListItem<'a> + = ::AccessListItem<'a> + where + Self: 'a; + type Authorization<'a> + = ::Authorization<'a> + where + Self: 'a; + + fn tx_type(&self) -> u8 { + self.0.tx_type() + } + + fn caller(&self) -> Address { + self.0.caller() + } + + fn gas_limit(&self) -> u64 { + self.0.gas_limit() + } + + fn value(&self) -> U256 { + self.0.value() + } + + fn input(&self) -> &Bytes { + self.0.input() + } + + fn nonce(&self) -> u64 { + self.0.nonce() + } + + fn kind(&self) -> TxKind { + self.0.kind() + } + + fn chain_id(&self) -> Option { + self.0.chain_id() + } + + fn gas_price(&self) -> u128 { + self.0.gas_price() + } + + fn access_list(&self) -> Option>> { + self.0.access_list() + } + + fn blob_versioned_hashes(&self) -> &[B256] { + self.0.blob_versioned_hashes() + } + + fn max_fee_per_blob_gas(&self) -> u128 { + self.0.max_fee_per_blob_gas() + } + + fn authorization_list_len(&self) -> usize { + self.0.authorization_list_len() + } + + fn authorization_list(&self) -> impl Iterator> { + self.0.authorization_list() + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.0.max_priority_fee_per_gas() + } +} + +impl FromRecoveredTx for CustomTxEnv { + fn from_recovered_tx(tx: &CustomTransaction, sender: Address) -> Self { + CustomTxEnv(match tx { + CustomTransaction::BuiltIn(tx) => TxEnv::from_recovered_tx(tx, sender), + CustomTransaction::Other(tx) => TxEnv::from_recovered_tx(tx, sender), + }) + } +} + +impl FromTxWithEncoded for CustomTxEnv { + fn from_encoded_tx(tx: &CustomTransaction, sender: Address, encoded: Bytes) -> Self { + CustomTxEnv(match tx { + CustomTransaction::BuiltIn(tx) => TxEnv::from_encoded_tx(tx, sender, encoded), + CustomTransaction::Other(tx) => TxEnv::from_encoded_tx(tx, sender, encoded), + }) + } +} + +pub struct CustomEvmTransaction(OpTransaction); + +impl FromRecoveredTx for CustomEvmTransaction { + fn from_recovered_tx(tx: &CustomTransaction, sender: Address) -> Self { + match tx { + CustomTransaction::BuiltIn(tx) => { + let tx = OpTransaction::::from_recovered_tx(tx, sender); + + CustomEvmTransaction(OpTransaction { + base: CustomTxEnv(tx.base), + enveloped_tx: tx.enveloped_tx, + deposit: tx.deposit, + }) + } + CustomTransaction::Other(_) => todo!(), + } + } +} + +impl FromTxWithEncoded for CustomEvmTransaction { + fn from_encoded_tx(tx: &CustomTransaction, sender: Address, encoded: Bytes) -> Self { + match tx { + CustomTransaction::BuiltIn(tx) => { + let tx = OpTransaction::::from_encoded_tx(tx, sender, encoded.into()); + + CustomEvmTransaction(OpTransaction { + base: CustomTxEnv(tx.base), + enveloped_tx: tx.enveloped_tx, + deposit: tx.deposit, + }) + } + CustomTransaction::Other(_) => todo!(), + } + } +} + pub struct CustomBlockExecutor { inner: OpBlockExecutor>, } @@ -38,9 +173,9 @@ pub struct CustomBlockExecutor { impl<'db, DB, E> BlockExecutor for CustomBlockExecutor where DB: Database + 'db, - E: Evm, Tx = OpTransaction>, + E: Evm, Tx = CustomEvmTransaction>, { - type Transaction = OpTransactionSigned; + type Transaction = CustomTransaction; type Receipt = OpReceipt; type Evm = E; @@ -78,6 +213,12 @@ pub struct CustomBlockAssembler { inner: OpBlockAssembler, } +impl CustomBlockAssembler { + pub fn new(inner: OpBlockAssembler) -> Self { + Self { inner } + } +} + impl BlockAssembler for CustomBlockAssembler where F: for<'a> BlockExecutorFactory< @@ -86,14 +227,25 @@ where Receipt: Receipt + DepositReceipt, >, { - // TODO: use custom block here - type Block = Block; + type Block = Block; fn assemble_block( &self, - input: BlockAssemblerInput<'_, '_, F>, + mut input: BlockAssemblerInput<'_, '_, F, CustomHeader>, ) -> Result { - let block = self.inner.assemble_block(input)?; + let inner_input = BlockAssemblerInput { + evm_env: input.evm_env, + execution_ctx: input.execution_ctx, + parent: &input.parent.inner, + transactions: input.transactions, + output: input.output, + bundle_state: input.bundle_state, + state_provider: input.state_provider, + state_root: input.state_root, + }; + let block = self.inner.assemble_block(inner_input)?; + let block = block.map_transactions(tx::from); + let block = block.map_header(CustomHeader::from); Ok(block) } @@ -105,6 +257,12 @@ pub struct CustomEvmConfig { block_assembler: CustomBlockAssembler, } +impl CustomEvmConfig { + pub fn new(inner: OpEvmConfig, block_assembler: CustomBlockAssembler) -> Self { + Self { inner, block_assembler } + } +} + impl BlockExecutorFactory for CustomEvmConfig { type EvmFactory = OpEvmFactory; type ExecutionCtx<'a> = OpBlockExecutionCtx; @@ -136,7 +294,7 @@ impl BlockExecutorFactory for CustomEvmConfig { } impl ConfigureEvm for CustomEvmConfig { - type Primitives = OpPrimitives; + type Primitives = CustomNodePrimitives; type Error = ::Error; type NextBlockEnvCtx = ::NextBlockEnvCtx; type BlockExecutorFactory = Self; @@ -164,7 +322,7 @@ impl ConfigureEvm for CustomEvmConfig { fn context_for_block( &self, - block: &SealedBlock>, + block: &SealedBlock>, ) -> OpBlockExecutionCtx { self.inner.context_for_block(block) } diff --git a/examples/custom-node/src/executor.rs b/examples/custom-node/src/executor.rs new file mode 100644 index 00000000000..a44e5200e1c --- /dev/null +++ b/examples/custom-node/src/executor.rs @@ -0,0 +1,37 @@ +use crate::{ + chainspec::CustomChainSpec, + evm::{CustomBlockAssembler, CustomEvmConfig}, + primitives::CustomNodePrimitives, +}; +use reth_ethereum::node::api::{FullNodeTypes, NodeTypes}; +use reth_node_builder::{components::ExecutorBuilder, BuilderContext}; +use reth_optimism_evm::{OpBlockAssembler, OpEvmConfig, OpRethReceiptBuilder}; +use std::sync::Arc; + +type ChainSpec = CustomChainSpec; +type Primitives = CustomNodePrimitives; + +/// A custom executor builder +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] +pub struct CustomExecutorBuilder; + +impl ExecutorBuilder for CustomExecutorBuilder +where + Types: NodeTypes, + Node: FullNodeTypes, +{ + type EVM = CustomEvmConfig; + + async fn build_evm(self, ctx: &BuilderContext) -> eyre::Result { + let evm_config = CustomEvmConfig::new( + OpEvmConfig::new( + Arc::new(ctx.chain_spec().inner().clone()), + OpRethReceiptBuilder::default(), + ), + CustomBlockAssembler::new(OpBlockAssembler::new(ctx.chain_spec())), + ); + + Ok(evm_config) + } +} diff --git a/examples/custom-node/src/lib.rs b/examples/custom-node/src/lib.rs index e6a2eab8612..395ee96b40f 100644 --- a/examples/custom-node/src/lib.rs +++ b/examples/custom-node/src/lib.rs @@ -7,59 +7,17 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] -use chainspec::CustomChainSpec; -use consensus::CustomConsensusBuilder; -use engine::CustomPayloadTypes; -use pool::CustomPoolBuilder; -use primitives::CustomNodePrimitives; -use reth_ethereum::node::api::{FullNodeTypes, NodeTypes}; -use reth_node_builder::{components::ComponentsBuilder, Node, NodeComponentsBuilder}; -use reth_op::node::{node::OpStorage, OpNode}; +pub use node::*; pub mod chainspec; pub mod consensus; pub mod engine; pub mod engine_api; pub mod evm; +pub mod executor; pub mod network; +pub mod payload; pub mod pool; pub mod primitives; -#[derive(Debug, Clone)] -pub struct CustomNode {} - -impl NodeTypes for CustomNode { - type Primitives = CustomNodePrimitives; - type ChainSpec = CustomChainSpec; - type StateCommitment = ::StateCommitment; - type Storage = ::Storage; - type Payload = CustomPayloadTypes; -} - -impl Node for CustomNode -where - N: FullNodeTypes< - Types: NodeTypes< - Payload = CustomPayloadTypes, - ChainSpec = CustomChainSpec, - Primitives = CustomNodePrimitives, - Storage = OpStorage, - >, - >, - ComponentsBuilder: - NodeComponentsBuilder, -{ - type ComponentsBuilder = - ComponentsBuilder; - - type AddOns = (); - - fn components_builder(&self) -> Self::ComponentsBuilder { - ComponentsBuilder::default() - .node_types::() - .pool(CustomPoolBuilder::default()) - .consensus(CustomConsensusBuilder) - } - - fn add_ons(&self) -> Self::AddOns {} -} +mod node; diff --git a/examples/custom-node/src/node.rs b/examples/custom-node/src/node.rs new file mode 100644 index 00000000000..dbda291c995 --- /dev/null +++ b/examples/custom-node/src/node.rs @@ -0,0 +1,78 @@ +use crate::{ + chainspec::CustomChainSpec, consensus::CustomConsensusBuilder, engine::CustomPayloadTypes, + executor::CustomExecutorBuilder, payload::CustomTxPriority, pool::CustomPoolBuilder, + primitives::CustomNodePrimitives, +}; +use reth_chainspec::{ChainSpecProvider, EthChainSpec}; +use reth_ethereum::node::api::{FullNodeTypes, NodeTypes}; +use reth_node_builder::{ + components::{BasicPayloadServiceBuilder, ComponentsBuilder}, + Node, NodeAdapter, NodeComponentsBuilder, +}; +use reth_op::node::{ + args::RollupArgs, + node::{OpNetworkBuilder, OpPayloadBuilder, OpStorage}, + OpNode, +}; +use reth_optimism_node::node::OpAddOns; +use reth_optimism_rpc::eth::OpEthApiBuilder; + +#[derive(Debug, Clone)] +pub struct CustomNode {} + +impl NodeTypes for CustomNode { + type Primitives = CustomNodePrimitives; + type ChainSpec = CustomChainSpec; + type StateCommitment = ::StateCommitment; + type Storage = ::Storage; + type Payload = CustomPayloadTypes; +} + +impl Node for CustomNode +where + N: FullNodeTypes< + Types: NodeTypes< + Payload = CustomPayloadTypes, + ChainSpec = CustomChainSpec, + Primitives = CustomNodePrimitives, + Storage = OpStorage, + >, + >, +{ + type ComponentsBuilder = ComponentsBuilder< + N, + CustomPoolBuilder, + CustomExecutorBuilder, + BasicPayloadServiceBuilder, + OpNetworkBuilder, + CustomConsensusBuilder, + >; + + type AddOns = OpAddOns< + NodeAdapter>::Components>, + OpEthApiBuilder, + >; + + fn components_builder(&self) -> Self::ComponentsBuilder { + let RollupArgs { disable_txpool_gossip, compute_pending_block, discovery_v4, .. } = + RollupArgs::default(); + + let chain_id = self.chain_spec().chain().id(); + + ComponentsBuilder::default() + .node_types::() + .pool(CustomPoolBuilder::default()) + .executor(CustomExecutorBuilder::default()) + .payload(BasicPayloadServiceBuilder::new( + OpPayloadBuilder::new(compute_pending_block) + .with_transactions(CustomTxPriority::new(chain_id)), + )) + .network(OpNetworkBuilder { + disable_txpool_gossip, + disable_discovery_v4: !discovery_v4, + }) + .consensus(CustomConsensusBuilder) + } + + fn add_ons(&self) -> Self::AddOns {} +} diff --git a/examples/custom-node/src/payload.rs b/examples/custom-node/src/payload.rs new file mode 100644 index 00000000000..65b667cb895 --- /dev/null +++ b/examples/custom-node/src/payload.rs @@ -0,0 +1,65 @@ +use alloy_consensus::{transaction::Recovered, SignableTransaction, TxEip1559}; +use alloy_network::TxSignerSync; +use alloy_primitives::{Address, ChainId, TxKind}; +use reth_e2e_test_utils::wallet::Wallet; +use reth_optimism_node::txpool::OpPooledTransaction; +use reth_optimism_payload_builder::builder::OpPayloadTransactions; +use reth_payload_util::{ + BestPayloadTransactions, PayloadTransactions, PayloadTransactionsChain, + PayloadTransactionsFixed, +}; +use reth_transaction_pool::PoolTransaction; + +#[derive(Clone, Debug)] +pub(crate) struct CustomTxPriority { + chain_id: ChainId, +} + +impl CustomTxPriority { + pub(crate) fn new(chain_id: ChainId) -> Self { + Self { chain_id } + } +} + +impl OpPayloadTransactions for CustomTxPriority { + fn best_transactions( + &self, + pool: Pool, + attr: reth_transaction_pool::BestTransactionsAttributes, + ) -> impl PayloadTransactions + where + Pool: reth_transaction_pool::TransactionPool, + { + // Block composition: + // 1. Best transactions from the pool (up to 250k gas) + // 2. End-of-block transaction created by the node (up to 100k gas) + + // End of block transaction should send a 0-value transfer to a random address. + let sender = Wallet::default().inner; + let mut end_of_block_tx = TxEip1559 { + chain_id: self.chain_id, + nonce: 1, // it will be 2nd tx after L1 block info tx that uses the same sender + gas_limit: 21000, + max_fee_per_gas: 20e9 as u128, + to: TxKind::Call(Address::random()), + value: 0.try_into().unwrap(), + ..Default::default() + }; + let signature = sender.sign_transaction_sync(&mut end_of_block_tx).unwrap(); + let end_of_block_tx = OpPooledTransaction::from_pooled(Recovered::new_unchecked( + op_alloy_consensus::OpPooledTransaction::Eip1559( + end_of_block_tx.into_signed(signature), + ), + sender.address(), + )); + + PayloadTransactionsChain::new( + BestPayloadTransactions::new(pool.best_transactions_with_attributes(attr)), + // Allow 250k gas for the transactions from the pool + Some(250_000), + PayloadTransactionsFixed::single(end_of_block_tx), + // Allow 100k gas for the end-of-block transaction + Some(100_000), + ) + } +} diff --git a/examples/custom-node/src/primitives/block.rs b/examples/custom-node/src/primitives/block.rs index 3de2831c410..d8db04e245c 100644 --- a/examples/custom-node/src/primitives/block.rs +++ b/examples/custom-node/src/primitives/block.rs @@ -1,9 +1,7 @@ -use crate::primitives::{CustomHeader, CustomTransactionEnvelope, ExtendedOpTxEnvelope}; +use crate::primitives::{CustomHeader, CustomTransaction}; /// The Block type of this node -pub type Block = - alloy_consensus::Block, CustomHeader>; +pub type Block = alloy_consensus::Block; /// The body type of this node -pub type BlockBody = - alloy_consensus::BlockBody, CustomHeader>; +pub type BlockBody = alloy_consensus::BlockBody; diff --git a/examples/custom-node/src/primitives/header.rs b/examples/custom-node/src/primitives/header.rs index 7bdb4a8d73c..34eb304188a 100644 --- a/examples/custom-node/src/primitives/header.rs +++ b/examples/custom-node/src/primitives/header.rs @@ -36,6 +36,12 @@ pub struct CustomHeader { pub extension: u64, } +impl From
for CustomHeader { + fn from(value: Header) -> Self { + Self { inner: value, extension: 0 } + } +} + impl CustomHeader {} impl AsRef for CustomHeader { diff --git a/examples/custom-node/src/primitives/mod.rs b/examples/custom-node/src/primitives/mod.rs index dd9a2228a23..ed56447fb5b 100644 --- a/examples/custom-node/src/primitives/mod.rs +++ b/examples/custom-node/src/primitives/mod.rs @@ -10,6 +10,7 @@ pub use tx::*; pub mod tx_type; pub use tx_type::*; pub mod tx_custom; + pub use tx_custom::*; use reth_ethereum::primitives::NodePrimitives; @@ -22,6 +23,6 @@ impl NodePrimitives for CustomNodePrimitives { type Block = Block; type BlockHeader = CustomHeader; type BlockBody = BlockBody; - type SignedTx = ExtendedOpTxEnvelope; + type SignedTx = CustomTransaction; type Receipt = OpReceipt; } diff --git a/examples/custom-node/src/primitives/tx.rs b/examples/custom-node/src/primitives/tx.rs index 82d0436f5ab..14ec34193a1 100644 --- a/examples/custom-node/src/primitives/tx.rs +++ b/examples/custom-node/src/primitives/tx.rs @@ -17,9 +17,16 @@ use reth_codecs::{ }; use reth_ethereum::primitives::{serde_bincode_compat::SerdeBincodeCompat, InMemorySize}; use reth_op::primitives::{Extended, SignedTransaction}; +use revm::context::TxEnv; use revm_primitives::{Address, Bytes}; use serde::{Deserialize, Serialize}; +pub type CustomTransaction = ExtendedOpTxEnvelope; + +pub(crate) fn from(value: OpTxEnvelope) -> CustomTransaction { + Extended::BuiltIn(value) +} + /// A [`SignedTransaction`] implementation that combines the [`OpTxEnvelope`] and another /// transaction type. pub type ExtendedOpTxEnvelope = Extended;