use alloy_eips::{eip2930::AccessListItem, eip7702::Authorization, BlockId, BlockNumberOrTag}; use alloy_primitives::{bytes, Address, B256, U256}; use alloy_provider::{ network::{ Ethereum, EthereumWallet, NetworkWallet, TransactionBuilder, TransactionBuilder7702, }, Provider, ProviderBuilder, SendableTx, }; use alloy_rpc_types_engine::PayloadAttributes; use alloy_rpc_types_eth::TransactionRequest; use alloy_signer::SignerSync; use rand::{seq::IndexedRandom, Rng}; use reth_e2e_test_utils::{wallet::Wallet, NodeHelperType, TmpDB}; use reth_ethereum_engine_primitives::EthPayloadBuilderAttributes; use reth_ethereum_primitives::TxType; use reth_node_api::NodeTypesWithDBAdapter; use reth_node_ethereum::EthereumNode; use reth_provider::FullProvider; /// Helper function to create a new eth payload attributes pub(crate) fn eth_payload_attributes(timestamp: u64) -> EthPayloadBuilderAttributes { let attributes = PayloadAttributes { timestamp, prev_randao: B256::ZERO, suggested_fee_recipient: Address::ZERO, withdrawals: Some(vec![]), parent_beacon_block_root: Some(B256::ZERO), }; EthPayloadBuilderAttributes::new(B256::ZERO, attributes) } /// Advances node by producing blocks with random transactions. pub(crate) async fn advance_with_random_transactions( node: &mut NodeHelperType, num_blocks: usize, rng: &mut impl Rng, finalize: bool, ) -> eyre::Result<()> where Provider: FullProvider>, { let provider = ProviderBuilder::new().connect_http(node.rpc_url()); let signers = Wallet::new(1).with_chain_id(provider.get_chain_id().await?).wallet_gen(); // simple contract which writes to storage on any call let dummy_bytecode = bytes!( "6080604052348015600f57600080fd5b50602880601d6000396000f3fe4360a09081523360c0526040608081905260e08152902080805500fea164736f6c6343000810000a" ); let mut call_destinations = signers.iter().map(|s| s.address()).collect::>(); for _ in 0..num_blocks { let tx_count = rng.random_range(1..20); let mut pending = vec![]; for _ in 0..tx_count { let signer = signers.choose(rng).unwrap(); let tx_type = TxType::try_from(rng.random_range(0..=4) as u64).unwrap(); let nonce = provider .get_transaction_count(signer.address()) .block_id(BlockId::Number(BlockNumberOrTag::Pending)) .await?; let mut tx = TransactionRequest::default().with_from(signer.address()).with_nonce(nonce); let should_create = rng.random::() && tx_type != TxType::Eip4844 && tx_type != TxType::Eip7702; if should_create { tx = tx.into_create().with_input(dummy_bytecode.clone()); } else { tx = tx.with_to(*call_destinations.choose(rng).unwrap()).with_input( (0..rng.random_range(0..10000)).map(|_| rng.random()).collect::>(), ); } if matches!(tx_type, TxType::Legacy | TxType::Eip2930) { tx = tx.with_gas_price(provider.get_gas_price().await?); } if rng.random::() || tx_type == TxType::Eip2930 { tx = tx.with_access_list( vec![AccessListItem { address: *call_destinations.choose(rng).unwrap(), storage_keys: (0..rng.random_range(0..100)).map(|_| rng.random()).collect(), }] .into(), ); } if tx_type == TxType::Eip7702 { let signer = signers.choose(rng).unwrap(); let auth = Authorization { chain_id: U256::from(provider.get_chain_id().await?), address: *call_destinations.choose(rng).unwrap(), nonce: provider .get_transaction_count(signer.address()) .block_id(BlockId::Number(BlockNumberOrTag::Pending)) .await?, }; let sig = signer.sign_hash_sync(&auth.signature_hash())?; tx = tx.with_authorization_list(vec![auth.into_signed(sig)]) } let gas = provider .estimate_gas(tx.clone()) .block(BlockId::Number(BlockNumberOrTag::Pending)) .await .unwrap_or(1_000_000); tx.set_gas_limit(gas); let SendableTx::Builder(tx) = provider.fill(tx).await? else { unreachable!() }; let tx = NetworkWallet::::sign_request(&EthereumWallet::new(signer.clone()), tx) .await?; if let Ok(res) = provider.send_tx_envelope(tx).await { pending.push(res); } } let payload = node.build_and_submit_payload().await?; if finalize { node.update_forkchoice(payload.block().hash(), payload.block().hash()).await?; } else { let last_safe = provider.get_block_by_number(BlockNumberOrTag::Safe).await?.unwrap().header.hash; node.update_forkchoice(last_safe, payload.block().hash()).await?; } for pending in pending { let receipt = pending.get_receipt().await?; if let Some(address) = receipt.contract_address { call_destinations.push(address); } } } Ok(()) }