From 5af9d16ecb620192d4fe5ae61d33e429b7f5aff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ca=C3=ADque=20Porfirio?= <56317416+caiquejjx@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:11:18 -0300 Subject: [PATCH] feat: add mixed mining mode (#8280) * feat: add mixed mining mode * feat: add mixed mining usage * fix: ensure unique txs * chore: undo comment deletion * touchups --------- Co-authored-by: Matthias Seitz --- crates/anvil/src/cmd.rs | 4 ++++ crates/anvil/src/config.rs | 14 ++++++++++++++ crates/anvil/src/eth/miner.rs | 33 +++++++++++++++++++++++++++++++++ crates/anvil/src/lib.rs | 8 +++++++- 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/crates/anvil/src/cmd.rs b/crates/anvil/src/cmd.rs index f867030230a2..e12c6b13ad33 100644 --- a/crates/anvil/src/cmd.rs +++ b/crates/anvil/src/cmd.rs @@ -98,6 +98,9 @@ pub struct NodeArgs { #[arg(long, visible_alias = "no-mine", conflicts_with = "block_time")] pub no_mining: bool, + #[arg(long, visible_alias = "mixed-mining", requires = "block_time")] + pub mixed_mining: bool, + /// The hosts the server will listen on. #[arg( long, @@ -200,6 +203,7 @@ impl NodeArgs { .with_hardfork(self.hardfork) .with_blocktime(self.block_time) .with_no_mining(self.no_mining) + .with_mixed_mining(self.mixed_mining, self.block_time) .with_account_generator(self.account_generator()) .with_genesis_balance(genesis_balance) .with_genesis_timestamp(self.timestamp) diff --git a/crates/anvil/src/config.rs b/crates/anvil/src/config.rs index ef6b2503d79d..4ae1be0e97bf 100644 --- a/crates/anvil/src/config.rs +++ b/crates/anvil/src/config.rs @@ -113,6 +113,8 @@ pub struct NodeConfig { pub block_time: Option, /// Disable auto, interval mining mode uns use `MiningMode::None` instead pub no_mining: bool, + /// Enables auto and interval mining mode + pub mixed_mining: bool, /// port to use for the server pub port: u16, /// maximum number of transactions in a block @@ -395,6 +397,7 @@ impl Default for NodeConfig { genesis_balance: Unit::ETHER.wei().saturating_mul(U256::from(100u64)), block_time: None, no_mining: false, + mixed_mining: false, port: NODE_PORT, // TODO make this something dependent on block capacity max_transactions: 1_000, @@ -633,6 +636,17 @@ impl NodeConfig { self } + #[must_use] + pub fn with_mixed_mining>( + mut self, + mixed_mining: bool, + block_time: Option, + ) -> Self { + self.block_time = block_time.map(Into::into); + self.mixed_mining = mixed_mining; + self + } + /// If set to `true` auto mining will be disabled #[must_use] pub fn with_no_mining(mut self, no_mining: bool) -> Self { diff --git a/crates/anvil/src/eth/miner.rs b/crates/anvil/src/eth/miner.rs index ddd27185075a..defb6624a787 100644 --- a/crates/anvil/src/eth/miner.rs +++ b/crates/anvil/src/eth/miner.rs @@ -132,6 +132,9 @@ pub enum MiningMode { Auto(ReadyTransactionMiner), /// A miner that constructs a new block every `interval` tick FixedBlockTime(FixedBlockTimeMiner), + + /// A minner that uses both Auto and FixedBlockTime + Mixed(ReadyTransactionMiner, FixedBlockTimeMiner), } impl MiningMode { @@ -147,6 +150,13 @@ impl MiningMode { Self::FixedBlockTime(FixedBlockTimeMiner::new(duration)) } + pub fn mixed(max_transactions: usize, listener: Receiver, duration: Duration) -> Self { + Self::Mixed( + ReadyTransactionMiner { max_transactions, has_pending_txs: None, rx: listener.fuse() }, + FixedBlockTimeMiner::new(duration), + ) + } + /// polls the [Pool] and returns those transactions that should be put in a block, if any. pub fn poll( &mut self, @@ -157,6 +167,29 @@ impl MiningMode { Self::None => Poll::Pending, Self::Auto(miner) => miner.poll(pool, cx), Self::FixedBlockTime(miner) => miner.poll(pool, cx), + Self::Mixed(auto, fixed) => { + let auto_txs = auto.poll(pool, cx); + let fixed_txs = fixed.poll(pool, cx); + + match (auto_txs, fixed_txs) { + // Both auto and fixed transactions are ready, combine them + (Poll::Ready(mut auto_txs), Poll::Ready(fixed_txs)) => { + for tx in fixed_txs { + // filter unique transactions + if auto_txs.iter().any(|auto_tx| auto_tx.hash() == tx.hash()) { + continue; + } + auto_txs.push(tx); + } + Poll::Ready(auto_txs) + } + // Only auto transactions are ready, return them + (Poll::Ready(auto_txs), Poll::Pending) => Poll::Ready(auto_txs), + // Only fixed transactions are ready or both are pending, + // return fixed transactions or pending status + (Poll::Pending, fixed_txs) => fixed_txs, + } + } } } } diff --git a/crates/anvil/src/lib.rs b/crates/anvil/src/lib.rs index 56005dd603ec..dc7e0969f99c 100644 --- a/crates/anvil/src/lib.rs +++ b/crates/anvil/src/lib.rs @@ -142,13 +142,19 @@ pub async fn try_spawn(mut config: NodeConfig) -> io::Result<(EthApi, NodeHandle no_mining, transaction_order, genesis, + mixed_mining, .. } = config.clone(); let pool = Arc::new(Pool::default()); let mode = if let Some(block_time) = block_time { - MiningMode::interval(block_time) + if mixed_mining { + let listener = pool.add_ready_listener(); + MiningMode::mixed(max_transactions, listener, block_time) + } else { + MiningMode::interval(block_time) + } } else if no_mining { MiningMode::None } else {