diff --git a/crates/provider/src/ext/anvil.rs b/crates/provider/src/ext/anvil.rs index 546b01ca6ea..63a33949140 100644 --- a/crates/provider/src/ext/anvil.rs +++ b/crates/provider/src/ext/anvil.rs @@ -3,7 +3,7 @@ use crate::Provider; use alloy_network::Network; use alloy_primitives::{Address, Bytes, TxHash, B256, U256}; -use alloy_rpc_types_anvil::{Forking, Metadata, MineOptions, NodeInfo}; +use alloy_rpc_types_anvil::{Forking, Metadata, MineOptions, NodeInfo, ReorgOptions}; use alloy_rpc_types_eth::Block; use alloy_transport::{Transport, TransportResult}; @@ -138,6 +138,9 @@ pub trait AnvilApi: Send + Sync { /// Sets the backend rpc url. async fn anvil_set_rpc_url(&self, url: String) -> TransportResult<()>; + /// Reorg the chain + async fn anvil_reorg(&self, options: ReorgOptions) -> TransportResult<()>; + /// Execute a transaction regardless of signature status. async fn eth_send_unsigned_transaction( &self, @@ -302,6 +305,10 @@ where self.client().request("anvil_setRpcUrl", (url,)).await } + async fn anvil_reorg(&self, options: ReorgOptions) -> TransportResult<()> { + self.client().request("anvil_reorg", options).await + } + async fn eth_send_unsigned_transaction( &self, request: N::TransactionRequest, @@ -918,6 +925,22 @@ mod tests { provider.anvil_set_rpc_url(url.clone()).await.unwrap(); } + #[tokio::test] + async fn test_anvil_reorg() { + let provider = ProviderBuilder::new().on_anvil(); + + // Mine two blocks + provider.anvil_mine(Some(U256::from(2)), None).await.unwrap(); + + let reorged_block = provider.get_block_by_number(2.into(), false).await.unwrap().unwrap(); + provider.anvil_reorg(ReorgOptions { depth: 1, tx_block_pairs: Vec::new() }).await.unwrap(); + + let new_block = provider.get_block_by_number(2.into(), false).await.unwrap().unwrap(); + + assert_eq!(reorged_block.header.number, new_block.header.number); + assert_ne!(reorged_block.header.hash, new_block.header.hash); + } + #[tokio::test] async fn test_eth_send_unsigned_transaction() { let provider = ProviderBuilder::new().on_anvil(); diff --git a/crates/rpc-types-anvil/Cargo.toml b/crates/rpc-types-anvil/Cargo.toml index 3c3b194a45b..3e6b3eacf89 100644 --- a/crates/rpc-types-anvil/Cargo.toml +++ b/crates/rpc-types-anvil/Cargo.toml @@ -20,6 +20,7 @@ workspace = true [dependencies] alloy-primitives = { workspace = true, features = ["serde"] } +alloy-rpc-types-eth = { workspace = true, features = ["serde"] } alloy-serde.workspace = true serde.workspace = true diff --git a/crates/rpc-types-anvil/src/lib.rs b/crates/rpc-types-anvil/src/lib.rs index 87930cf9a9d..8bbd90dcbb9 100644 --- a/crates/rpc-types-anvil/src/lib.rs +++ b/crates/rpc-types-anvil/src/lib.rs @@ -6,7 +6,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -use alloy_primitives::{BlockHash, ChainId, TxHash, B256, U256}; +use alloy_primitives::{BlockHash, Bytes, ChainId, TxHash, B256, U256}; +use alloy_rpc_types_eth::TransactionRequest; use serde::{Deserialize, Deserializer, Serialize}; use std::collections::BTreeMap; @@ -164,6 +165,25 @@ impl Default for MineOptions { } } +/// Represents the options used in `anvil_reorg` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ReorgOptions { + /// The depth of the reorg + pub depth: u64, + /// List of transaction requests and blocks pairs to be mined into the new chain + pub tx_block_pairs: Vec<(TransactionData, u64)>, +} + +/// Type representing txs in `ReorgOptions` +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TransactionData { + /// Transaction request + JSON(TransactionRequest), + /// Raw transaction bytes + Raw(Bytes), +} + #[cfg(test)] mod tests { use super::*;