From 4890006220e7eb841ac0dd0d637f06e6ed05bc76 Mon Sep 17 00:00:00 2001 From: grantkee <49913008+grantkee@users.noreply.github.com> Date: Tue, 24 Oct 2023 05:30:59 -0500 Subject: [PATCH] Patch/Auto-mine (#5042) --- Cargo.lock | 6 + crates/consensus/auto-seal/Cargo.toml | 6 + crates/consensus/auto-seal/src/lib.rs | 3 + .../consensus/auto-seal/tests/it/auto_mine.rs | 120 ++++++++++++++++++ crates/consensus/auto-seal/tests/it/main.rs | 4 + crates/revm/src/processor.rs | 5 + 6 files changed, 144 insertions(+) create mode 100644 crates/consensus/auto-seal/tests/it/auto_mine.rs create mode 100644 crates/consensus/auto-seal/tests/it/main.rs diff --git a/Cargo.lock b/Cargo.lock index c8a87be03..49735224a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5683,7 +5683,11 @@ dependencies = [ name = "reth-auto-seal-consensus" version = "0.1.0-alpha.10" dependencies = [ + "clap", + "eyre", "futures-util", + "jsonrpsee", + "reth", "reth-beacon-consensus", "reth-interfaces", "reth-primitives", @@ -5691,6 +5695,8 @@ dependencies = [ "reth-revm", "reth-stages", "reth-transaction-pool", + "serde_json", + "tempfile", "tokio", "tokio-stream", "tracing", diff --git a/crates/consensus/auto-seal/Cargo.toml b/crates/consensus/auto-seal/Cargo.toml index 49a37d9e6..51c181d62 100644 --- a/crates/consensus/auto-seal/Cargo.toml +++ b/crates/consensus/auto-seal/Cargo.toml @@ -26,3 +26,9 @@ tracing.workspace = true [dev-dependencies] reth-interfaces = { workspace = true, features = ["test-utils"] } +reth = { workspace = true } +tempfile = { workspace = true } +clap = { workspace = true } +jsonrpsee = { workspace = true } +eyre = { workspace = true } +serde_json = { workspace = true } diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index 29074cc92..ff9b8fc6e 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -305,6 +305,9 @@ impl StorageInner { // TODO: there isn't really a parent beacon block root here, so not sure whether or not to // call the 4788 beacon contract + // set the first block to find the correct index in bundle state + executor.set_first_block(block.number); + let (receipts, gas_used) = executor.execute_transactions(block, U256::ZERO, Some(senders))?; diff --git a/crates/consensus/auto-seal/tests/it/auto_mine.rs b/crates/consensus/auto-seal/tests/it/auto_mine.rs new file mode 100644 index 000000000..bd24e4697 --- /dev/null +++ b/crates/consensus/auto-seal/tests/it/auto_mine.rs @@ -0,0 +1,120 @@ +//! auto-mine consensus integration test +use clap::Parser; +use jsonrpsee::{core::client::ClientT, http_client::HttpClientBuilder, rpc_params}; +use reth::{ + cli::{ + components::RethNodeComponents, + ext::{NoArgs, NoArgsCliExt, RethNodeCommandConfig}, + }, + node::NodeCommand, + runner::CliRunner, + tasks::TaskSpawner, +}; +use reth_primitives::{hex, revm_primitives::FixedBytes, ChainSpec, Genesis}; +use reth_provider::CanonStateSubscriptions; +use reth_transaction_pool::TransactionPool; +use std::{sync::Arc, time::Duration}; +use tokio::time::timeout; + +#[derive(Debug)] +struct AutoMineConfig; + +impl RethNodeCommandConfig for AutoMineConfig { + fn on_node_started(&mut self, components: &Reth) -> eyre::Result<()> { + let pool = components.pool(); + let mut canon_events = components.events().subscribe_to_canonical_state(); + + components.task_executor().spawn_critical_blocking("rpc request", Box::pin(async move { + // submit tx through rpc + let raw_tx = "0x02f876820a28808477359400847735940082520894ab0840c0e43688012c1adb0f5e3fc665188f83d28a029d394a5d630544000080c080a0a044076b7e67b5deecc63f61a8d7913fab86ca365b344b5759d1fe3563b4c39ea019eab979dd000da04dfc72bb0377c092d30fd9e1cab5ae487de49586cc8b0090"; + let client = HttpClientBuilder::default().build("http://127.0.0.1:8545").expect("http client should bind to default rpc port"); + let response: String = client.request("eth_sendRawTransaction", rpc_params![raw_tx]).await.expect("client request should be valid"); + let expected = "0xb1c6512f4fc202c04355fbda66755e0e344b152e633010e8fd75ecec09b63398"; + + assert_eq!(&response, expected); + + // more than enough time for the next block + let duration = Duration::from_secs(15); + + // wait for canon event or timeout + let update = timeout(duration, canon_events.recv()) + .await + .expect("canon state should change before timeout") + .expect("canon events stream is still open"); + let new_tip = update.tip(); + let expected_tx_root: FixedBytes<32> = hex!("c79b5383458e63fb20c6a49d9ec7917195a59003a2af4b28a01d7c6fbbcd7e35").into(); + assert_eq!(new_tip.transactions_root, expected_tx_root); + assert_eq!(new_tip.number, 1); + assert!(pool.pending_transactions().is_empty()); + })); + Ok(()) + } +} + +#[test] +pub fn test_auto_mine() { + // create temp path for test + let temp_path = tempfile::TempDir::new().expect("tempdir is okay").into_path(); + let datadir = temp_path.to_str().expect("temp path is okay"); + + let no_args = NoArgs::with(AutoMineConfig); + let chain = custom_chain(); + let mut command = NodeCommand::>::parse_from([ + "reth", + "--dev", + "--datadir", + datadir, + "--debug.max-block", + "1", + "--debug.terminate", + ]) + .with_ext::>(no_args); + + // use custom chain spec + command.chain = chain; + + let runner = CliRunner::default(); + let node_command = runner.run_command_until_exit(|ctx| command.execute(ctx)); + assert!(node_command.is_ok()) +} + +fn custom_chain() -> Arc { + let custom_genesis = r#" +{ + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x5343", + "gasLimit": "0x1388", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b": { + "balance": "0x4a47e3c12448f4ad000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "config": { + "ethash": {}, + "chainId": 2600, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "shanghaiTime": 0 + } +} +"#; + let genesis: Genesis = serde_json::from_str(custom_genesis).unwrap(); + Arc::new(genesis.into()) +} diff --git a/crates/consensus/auto-seal/tests/it/main.rs b/crates/consensus/auto-seal/tests/it/main.rs new file mode 100644 index 000000000..5d0704817 --- /dev/null +++ b/crates/consensus/auto-seal/tests/it/main.rs @@ -0,0 +1,4 @@ +//! auto-mine consensus tests +mod auto_mine; + +async fn main() {} diff --git a/crates/revm/src/processor.rs b/crates/revm/src/processor.rs index bc6cd89dd..de86e2e33 100644 --- a/crates/revm/src/processor.rs +++ b/crates/revm/src/processor.rs @@ -135,6 +135,11 @@ impl<'a> EVMProcessor<'a> { self.stack = stack; } + /// Configure the executor with the given block. + pub fn set_first_block(&mut self, num: BlockNumber) { + self.first_block = Some(num); + } + /// Returns a reference to the database pub fn db_mut(&mut self) -> &mut StateDBBox<'a, RethError> { // Option will be removed from EVM in the future.