diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 67874e9e..5c37a525 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: egress-policy: audit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@4305c38b25d97ef35a8ad1f985ccf2d2242004f2 # stable + - uses: dtolnay/rust-toolchain@nightly with: components: rustfmt - run: cargo fmt --all -- --check diff --git a/crates/flashblocks-rpc/src/pending_blocks.rs b/crates/flashblocks-rpc/src/pending_blocks.rs index c9958460..17277650 100644 --- a/crates/flashblocks-rpc/src/pending_blocks.rs +++ b/crates/flashblocks-rpc/src/pending_blocks.rs @@ -1,11 +1,11 @@ use alloy_consensus::{Header, Sealed}; use alloy_eips::BlockNumberOrTag; use alloy_primitives::{ - Address, B256, BlockNumber, TxHash, U256, map::foldhash::{HashMap, HashMapExt}, + Address, BlockNumber, TxHash, B256, U256, }; use alloy_provider::network::TransactionResponse; -use alloy_rpc_types::{BlockTransactions, state::StateOverride}; +use alloy_rpc_types::{state::StateOverride, BlockTransactions}; use alloy_rpc_types_eth::{Filter, Header as RPCHeader, Log}; use eyre::eyre; use op_alloy_network::Optimism; @@ -60,8 +60,7 @@ impl PendingBlocksBuilder { #[inline] pub(crate) fn with_transaction(&mut self, transaction: Transaction) -> &Self { - self.transactions_by_hash - .insert(transaction.tx_hash(), transaction.clone()); + self.transactions_by_hash.insert(transaction.tx_hash(), transaction.clone()); self.transactions.push(transaction); self } @@ -83,9 +82,7 @@ impl PendingBlocksBuilder { let zero = U256::from(0); let current_count = self.transaction_count.get(&sender).unwrap_or(&zero); - _ = self - .transaction_count - .insert(sender, *current_count + U256::from(1)); + _ = self.transaction_count.insert(sender, *current_count + U256::from(1)); self } @@ -213,10 +210,7 @@ impl PendingBlocks { } pub fn get_transaction_count(&self, address: Address) -> U256 { - self.transaction_count - .get(&address) - .cloned() - .unwrap_or(U256::from(0)) + self.transaction_count.get(&address).cloned().unwrap_or(U256::from(0)) } pub fn get_balance(&self, address: Address) -> Option { diff --git a/crates/flashblocks-rpc/src/rpc.rs b/crates/flashblocks-rpc/src/rpc.rs index 7a922b58..cfd228f7 100644 --- a/crates/flashblocks-rpc/src/rpc.rs +++ b/crates/flashblocks-rpc/src/rpc.rs @@ -1,39 +1,41 @@ -use std::sync::Arc; -use std::time::Duration; +use std::{sync::Arc, time::Duration}; -use crate::metrics::Metrics; -use crate::pending_blocks::PendingBlocks; use alloy_eips::{BlockId, BlockNumberOrTag}; -use alloy_primitives::map::foldhash::{HashSet, HashSetExt}; -use alloy_primitives::{Address, TxHash, U256}; -use alloy_rpc_types::BlockOverrides; -use alloy_rpc_types::simulate::{SimBlock, SimulatePayload, SimulatedBlock}; -use alloy_rpc_types::state::{EvmOverrides, StateOverride, StateOverridesBuilder}; +use alloy_primitives::{ + map::foldhash::{HashSet, HashSetExt}, + Address, TxHash, U256, +}; +use alloy_rpc_types::{ + simulate::{SimBlock, SimulatePayload, SimulatedBlock}, + state::{EvmOverrides, StateOverride, StateOverridesBuilder}, + BlockOverrides, +}; use alloy_rpc_types_eth::{Filter, Log}; use arc_swap::Guard; use jsonrpsee::{ - core::{RpcResult, async_trait}, + core::{async_trait, RpcResult}, proc_macros::rpc, }; -use jsonrpsee_types::ErrorObjectOwned; -use jsonrpsee_types::error::INVALID_PARAMS_CODE; +use jsonrpsee_types::{error::INVALID_PARAMS_CODE, ErrorObjectOwned}; use op_alloy_network::Optimism; use op_alloy_rpc_types::OpTransactionRequest; -use reth::providers::CanonStateSubscriptions; -use reth::rpc::eth::EthFilter; -use reth::rpc::server_types::eth::EthApiError; -use reth_rpc_eth_api::helpers::EthState; -use reth_rpc_eth_api::helpers::EthTransactions; -use reth_rpc_eth_api::helpers::{EthBlocks, EthCall}; -use reth_rpc_eth_api::{EthApiTypes, EthFilterApiServer, RpcBlock, helpers::FullEthApi}; -use reth_rpc_eth_api::{RpcReceipt, RpcTransaction}; -use tokio::sync::broadcast; -use tokio::sync::broadcast::error::RecvError; -use tokio::time; -use tokio_stream::StreamExt; -use tokio_stream::wrappers::BroadcastStream; +use reth::{ + providers::CanonStateSubscriptions, + rpc::{eth::EthFilter, server_types::eth::EthApiError}, +}; +use reth_rpc_eth_api::{ + helpers::{EthBlocks, EthCall, EthState, EthTransactions, FullEthApi}, + EthApiTypes, EthFilterApiServer, RpcBlock, RpcReceipt, RpcTransaction, +}; +use tokio::{ + sync::{broadcast, broadcast::error::RecvError}, + time, +}; +use tokio_stream::{wrappers::BroadcastStream, StreamExt}; use tracing::{debug, trace, warn}; +use crate::{metrics::Metrics, pending_blocks::PendingBlocks}; + /// Max configured timeout for `eth_sendRawTransactionSync` in milliseconds. pub const MAX_TIMEOUT_SEND_RAW_TX_SYNC_MS: u64 = 6_000; @@ -89,7 +91,7 @@ pub trait EthApiOverride { #[method(name = "getBalance")] async fn get_balance(&self, address: Address, block_number: Option) - -> RpcResult; + -> RpcResult; #[method(name = "getTransactionCount")] async fn get_transaction_count( @@ -149,12 +151,7 @@ pub struct EthApiExt { impl EthApiExt { pub fn new(eth_api: Eth, eth_filter: EthFilter, flashblocks_state: Arc) -> Self { - Self { - eth_api, - eth_filter, - flashblocks_state, - metrics: Metrics::default(), - } + Self { eth_api, eth_filter, flashblocks_state, metrics: Metrics::default() } } } @@ -180,9 +177,7 @@ where let pending_blocks = self.flashblocks_state.get_pending_blocks(); Ok(pending_blocks.get_block(full)) } else { - EthBlocks::rpc_block(&self.eth_api, number.into(), full) - .await - .map_err(Into::into) + EthBlocks::rpc_block(&self.eth_api, number.into(), full).await.map_err(Into::into) } } @@ -201,9 +196,7 @@ where return Ok(Some(fb_receipt)); } - EthTransactions::transaction_receipt(&self.eth_api, tx_hash) - .await - .map_err(Into::into) + EthTransactions::transaction_receipt(&self.eth_api, tx_hash).await.map_err(Into::into) } async fn get_balance( @@ -224,9 +217,7 @@ where } } - EthState::balance(&self.eth_api, address, block_number) - .await - .map_err(Into::into) + EthState::balance(&self.eth_api, address, block_number).await.map_err(Into::into) } async fn get_transaction_count( @@ -254,9 +245,7 @@ where return Ok(canon_count + fb_count); } - EthState::transaction_count(&self.eth_api, address, block_number) - .await - .map_err(Into::into) + EthState::transaction_count(&self.eth_api, address, block_number).await.map_err(Into::into) } async fn transaction_by_hash( @@ -447,21 +436,13 @@ where state_overrides_builder.extend(sim_block.state_overrides.unwrap_or_default()); let final_overrides = state_overrides_builder.build(); - let block_state_call = SimBlock { - state_overrides: Some(final_overrides), - ..sim_block - }; + let block_state_call = SimBlock { state_overrides: Some(final_overrides), ..sim_block }; block_state_calls.push(block_state_call); } - let payload = SimulatePayload { - block_state_calls, - ..opts - }; + let payload = SimulatePayload { block_state_calls, ..opts }; - EthCall::simulate_v1(&self.eth_api, payload, Some(block_id)) - .await - .map_err(Into::into) + EthCall::simulate_v1(&self.eth_api, payload, Some(block_id)).await.map_err(Into::into) } async fn get_logs(&self, filter: Filter) -> RpcResult> { @@ -472,10 +453,9 @@ where // Check if this is a mixed query (toBlock is pending) let (from_block, to_block) = match &filter.block_option { - alloy_rpc_types_eth::FilterBlockOption::Range { - from_block, - to_block, - } => (*from_block, *to_block), + alloy_rpc_types_eth::FilterBlockOption::Range { from_block, to_block } => { + (*from_block, *to_block) + } _ => { // Block hash queries or other formats - delegate to eth API return self.eth_filter.logs(filter).await; diff --git a/crates/flashblocks-rpc/src/state.rs b/crates/flashblocks-rpc/src/state.rs index 281ec86b..08d2a774 100644 --- a/crates/flashblocks-rpc/src/state.rs +++ b/crates/flashblocks-rpc/src/state.rs @@ -1,43 +1,53 @@ -use crate::metrics::Metrics; -use crate::pending_blocks::{PendingBlocks, PendingBlocksBuilder}; -use crate::rpc::{FlashblocksAPI, PendingBlocksAPI}; -use crate::subscription::{Flashblock, FlashblocksReceiver}; -use alloy_consensus::transaction::{Recovered, SignerRecoverable, TransactionMeta}; -use alloy_consensus::{Header, TxReceipt}; +use std::{ + collections::{BTreeMap, HashSet}, + sync::Arc, + time::Instant, +}; + +use alloy_consensus::{ + transaction::{Recovered, SignerRecoverable, TransactionMeta}, + Header, TxReceipt, +}; use alloy_eips::BlockNumberOrTag; -use alloy_primitives::map::foldhash::HashMap; -use alloy_primitives::{Address, B256, BlockNumber, Bytes, Sealable, U256}; +use alloy_primitives::{map::foldhash::HashMap, Address, BlockNumber, Bytes, Sealable, B256, U256}; use alloy_rpc_types::{TransactionTrait, Withdrawal}; use alloy_rpc_types_engine::{ExecutionPayloadV1, ExecutionPayloadV2, ExecutionPayloadV3}; -use alloy_rpc_types_eth::state::StateOverride; -use alloy_rpc_types_eth::{Filter, Log}; +use alloy_rpc_types_eth::{state::StateOverride, Filter, Log}; use arc_swap::{ArcSwapOption, Guard}; use eyre::eyre; use op_alloy_consensus::OpTxEnvelope; use op_alloy_network::{Optimism, TransactionResponse}; use op_alloy_rpc_types::Transaction; -use reth::chainspec::{ChainSpecProvider, EthChainSpec}; -use reth::providers::{BlockReaderIdExt, StateProviderFactory}; -use reth::revm::context::result::ResultAndState; -use reth::revm::database::StateProviderDatabase; -use reth::revm::db::CacheDB; -use reth::revm::{DatabaseCommit, State}; +use reth::{ + chainspec::{ChainSpecProvider, EthChainSpec}, + providers::{BlockReaderIdExt, StateProviderFactory}, + revm::{ + context::result::ResultAndState, database::StateProviderDatabase, db::CacheDB, + DatabaseCommit, State, + }, +}; use reth_evm::{ConfigureEvm, Evm}; use reth_optimism_chainspec::OpHardforks; use reth_optimism_evm::{OpEvmConfig, OpNextBlockEnvAttributes}; use reth_optimism_primitives::{DepositReceipt, OpBlock, OpPrimitives}; use reth_optimism_rpc::OpReceiptBuilder; use reth_primitives::RecoveredBlock; -use reth_rpc_convert::{RpcTransaction, transaction::ConvertReceiptInput}; +use reth_rpc_convert::{transaction::ConvertReceiptInput, RpcTransaction}; use reth_rpc_eth_api::{RpcBlock, RpcReceipt}; -use std::collections::{BTreeMap, HashSet}; -use std::sync::Arc; -use std::time::Instant; -use tokio::sync::Mutex; -use tokio::sync::broadcast::{self, Sender}; -use tokio::sync::mpsc::{self, UnboundedReceiver}; +use tokio::sync::{ + broadcast::{self, Sender}, + mpsc::{self, UnboundedReceiver}, + Mutex, +}; use tracing::{debug, error, info, warn}; +use crate::{ + metrics::Metrics, + pending_blocks::{PendingBlocks, PendingBlocksBuilder}, + rpc::{FlashblocksAPI, PendingBlocksAPI}, + subscription::{Flashblock, FlashblocksReceiver}, +}; + // Buffer 4s of flashblocks for flashblock_sender const BUFFER_SIZE: usize = 20; @@ -73,12 +83,7 @@ where flashblock_sender.clone(), ); - Self { - pending_blocks, - queue: tx, - flashblock_sender, - state_processor, - } + Self { pending_blocks, queue: tx, flashblock_sender, state_processor } } pub fn start(&self) { @@ -132,15 +137,11 @@ impl FlashblocksAPI for FlashblocksState { impl PendingBlocksAPI for Guard>> { fn get_canonical_block_number(&self) -> BlockNumberOrTag { - self.as_ref() - .map(|pb| pb.canonical_block_number()) - .unwrap_or(BlockNumberOrTag::Latest) + self.as_ref().map(|pb| pb.canonical_block_number()).unwrap_or(BlockNumberOrTag::Latest) } fn get_transaction_count(&self, address: Address) -> U256 { - self.as_ref() - .map(|pb| pb.get_transaction_count(address)) - .unwrap_or_else(|| U256::from(0)) + self.as_ref().map(|pb| pb.get_transaction_count(address)).unwrap_or_else(|| U256::from(0)) } fn get_block(&self, full: bool) -> Option> { @@ -158,8 +159,7 @@ impl PendingBlocksAPI for Guard>> { &self, tx_hash: alloy_primitives::TxHash, ) -> Option> { - self.as_ref() - .and_then(|pb| pb.get_transaction_by_hash(tx_hash)) + self.as_ref().and_then(|pb| pb.get_transaction_by_hash(tx_hash)) } fn get_balance(&self, address: Address) -> Option { @@ -167,15 +167,11 @@ impl PendingBlocksAPI for Guard>> { } fn get_state_overrides(&self) -> Option { - self.as_ref() - .map(|pb| pb.get_state_overrides()) - .unwrap_or_default() + self.as_ref().map(|pb| pb.get_state_overrides()).unwrap_or_default() } fn get_pending_logs(&self, filter: &Filter) -> Vec { - self.as_ref() - .map(|pb| pb.get_pending_logs(filter)) - .unwrap_or_default() + self.as_ref().map(|pb| pb.get_pending_logs(filter)).unwrap_or_default() } } @@ -202,13 +198,7 @@ where rx: Arc>>, sender: Sender>, ) -> Self { - Self { - metrics: Metrics::default(), - pending_blocks, - client, - rx, - sender, - } + Self { metrics: Metrics::default(), pending_blocks, client, rx, sender } } async fn start(&self) { @@ -216,10 +206,7 @@ where let prev_pending_blocks = self.pending_blocks.load_full(); match update { StateUpdate::Canonical(block) => { - debug!( - message = "processing canonical block", - block_number = block.number - ); + debug!(message = "processing canonical block", block_number = block.number); match self.process_canonical_block(prev_pending_blocks, &block) { Ok(new_pending_blocks) => { self.pending_blocks.swap(new_pending_blocks); @@ -243,9 +230,7 @@ where } self.pending_blocks.swap(new_pending_blocks); - self.metrics - .block_processing_duration - .record(start_time.elapsed()); + self.metrics.block_processing_duration.record(start_time.elapsed()); } Err(e) => { error!(message = "could not process Flashblock", error = %e); @@ -269,9 +254,7 @@ where .iter() .filter(|fb| fb.metadata.block_number == block.number) .count(); - self.metrics - .flashblocks_in_block - .record(num_flashblocks_for_canon as f64); + self.metrics.flashblocks_in_block.record(num_flashblocks_for_canon as f64); if pending_blocks.latest_block_number() <= block.number { self.metrics.pending_clear_catchup.increment(1); @@ -401,21 +384,14 @@ where let evm_config = OpEvmConfig::optimism(self.client.chain_spec()); - let state_provider = self - .client - .state_by_block_number_or_tag(BlockNumberOrTag::Number(canonical_block))?; + let state_provider = + self.client.state_by_block_number_or_tag(BlockNumberOrTag::Number(canonical_block))?; let state_provider_db = StateProviderDatabase::new(state_provider); - let state = State::builder() - .with_database(state_provider_db) - .with_bundle_update() - .build(); + let state = State::builder().with_database(state_provider_db).with_bundle_update().build(); let mut pending_blocks_builder = PendingBlocksBuilder::new(); let mut db = match &prev_pending_blocks { - Some(pending_blocks) => CacheDB { - cache: pending_blocks.get_db_cache(), - db: state, - }, + Some(pending_blocks) => CacheDB { cache: pending_blocks.get_db_cache(), db: state }, None => CacheDB::new(state), }; let mut state_overrides = match &prev_pending_blocks { @@ -463,10 +439,7 @@ where }); pending_blocks_builder.with_flashblocks( - flashblocks - .iter() - .map(|&x| x.clone()) - .collect::>(), + flashblocks.iter().map(|&x| x.clone()).collect::>(), ); let execution_payload: ExecutionPayloadV3 = ExecutionPayloadV3 { @@ -534,10 +507,7 @@ where .as_deposit_receipt() .ok_or(eyre!("deposit transaction, non deposit receipt"))?; - ( - deposit_receipt.deposit_receipt_version, - deposit_receipt.deposit_nonce, - ) + (deposit_receipt.deposit_receipt_version, deposit_receipt.deposit_nonce) } else { (None, None) }; @@ -548,9 +518,7 @@ where block .base_fee_per_gas .map(|base_fee| { - transaction - .effective_tip_per_gas(base_fee) - .unwrap_or_default() + transaction.effective_tip_per_gas(base_fee).unwrap_or_default() + base_fee as u128 }) .unwrap_or_else(|| transaction.max_fee_per_gas()) @@ -629,9 +597,8 @@ where existing_override.code = acc.info.code.clone().map(|code| code.bytes()); - let existing = existing_override - .state_diff - .get_or_insert(Default::default()); + let existing = + existing_override.state_diff.get_or_insert(Default::default()); let changed_slots = acc.storage.iter().map(|(&key, slot)| { (B256::from(key), B256::from(slot.present_value)) }); diff --git a/crates/flashblocks-rpc/src/subscription.rs b/crates/flashblocks-rpc/src/subscription.rs index d86bb1bb..22befb7d 100644 --- a/crates/flashblocks-rpc/src/subscription.rs +++ b/crates/flashblocks-rpc/src/subscription.rs @@ -1,7 +1,6 @@ use std::{io::Read, sync::Arc, time::Duration}; -use alloy_primitives::map::foldhash::HashMap; -use alloy_primitives::{Address, B256, U256}; +use alloy_primitives::{map::foldhash::HashMap, Address, B256, U256}; use alloy_rpc_types_engine::PayloadId; use futures_util::{SinkExt as _, StreamExt}; use reth_optimism_primitives::OpReceipt; @@ -9,8 +8,7 @@ use rollup_boost::{ ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1, FlashblocksPayloadV1, }; use serde::{Deserialize, Serialize}; -use tokio::sync::mpsc; -use tokio::time::interval; +use tokio::{sync::mpsc, time::interval}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use tracing::{error, info, trace, warn}; use url::Url; @@ -60,11 +58,7 @@ where Receiver: FlashblocksReceiver + Send + Sync + 'static, { pub fn new(flashblocks_state: Arc, ws_url: Url) -> Self { - Self { - ws_url, - flashblocks_state, - metrics: Metrics::default(), - } + Self { ws_url, flashblocks_state, metrics: Metrics::default() } } pub fn start(&mut self) { diff --git a/crates/flashblocks-rpc/src/tests/mod.rs b/crates/flashblocks-rpc/src/tests/mod.rs index 59995edb..e1477cdc 100644 --- a/crates/flashblocks-rpc/src/tests/mod.rs +++ b/crates/flashblocks-rpc/src/tests/mod.rs @@ -1,4 +1,4 @@ -use alloy_primitives::{B256, Bytes, b256, bytes}; +use alloy_primitives::{b256, bytes, Bytes, B256}; mod rpc; mod state; diff --git a/crates/flashblocks-rpc/src/tests/rpc.rs b/crates/flashblocks-rpc/src/tests/rpc.rs index 2230d7c6..b8bbdfe0 100644 --- a/crates/flashblocks-rpc/src/tests/rpc.rs +++ b/crates/flashblocks-rpc/src/tests/rpc.rs @@ -1,43 +1,44 @@ #[cfg(test)] mod tests { - use crate::rpc::{EthApiExt, EthApiOverrideServer}; - use crate::state::FlashblocksState; - use crate::subscription::{Flashblock, FlashblocksReceiver, Metadata}; - use crate::tests::{BLOCK_INFO_TXN, BLOCK_INFO_TXN_HASH}; + use std::{any::Any, net::SocketAddr, str::FromStr, sync::Arc}; + use alloy_consensus::Receipt; use alloy_eips::BlockNumberOrTag; use alloy_genesis::Genesis; - use alloy_primitives::map::HashMap; - use alloy_primitives::{Address, B256, Bytes, LogData, TxHash, U256, address, b256, bytes}; - use alloy_provider::Provider; - use alloy_provider::RootProvider; + use alloy_primitives::{ + address, b256, bytes, map::HashMap, Address, Bytes, LogData, TxHash, B256, U256, + }; + use alloy_provider::{Provider, RootProvider}; use alloy_rpc_client::RpcClient; use alloy_rpc_types::simulate::{SimBlock, SimulatePayload}; use alloy_rpc_types_engine::PayloadId; - use alloy_rpc_types_eth::TransactionInput; - use alloy_rpc_types_eth::error::EthRpcErrorCode; + use alloy_rpc_types_eth::{error::EthRpcErrorCode, TransactionInput}; use op_alloy_consensus::OpDepositReceipt; use op_alloy_network::{Optimism, ReceiptResponse, TransactionResponse}; use op_alloy_rpc_types::OpTransactionRequest; - use reth::args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}; - use reth::builder::{Node, NodeBuilder, NodeConfig, NodeHandle}; - use reth::chainspec::Chain; - use reth::core::exit::NodeExitFuture; - use reth::tasks::TaskManager; + use reth::{ + args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, + builder::{Node, NodeBuilder, NodeConfig, NodeHandle}, + chainspec::Chain, + core::exit::NodeExitFuture, + tasks::TaskManager, + }; use reth_optimism_chainspec::OpChainSpecBuilder; - use reth_optimism_node::OpNode; - use reth_optimism_node::args::RollupArgs; + use reth_optimism_node::{args::RollupArgs, OpNode}; use reth_optimism_primitives::OpReceipt; use reth_provider::providers::BlockchainProvider; use reth_rpc_eth_api::RpcReceipt; use rollup_boost::{ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1}; use serde_json; - use std::any::Any; - use std::net::SocketAddr; - use std::str::FromStr; - use std::sync::Arc; use tokio::sync::{mpsc, oneshot}; + use crate::{ + rpc::{EthApiExt, EthApiOverrideServer}, + state::FlashblocksState, + subscription::{Flashblock, FlashblocksReceiver, Metadata}, + tests::{BLOCK_INFO_TXN, BLOCK_INFO_TXN_HASH}, + }; + pub struct NodeContext { sender: mpsc::Sender<(Flashblock, oneshot::Sender<()>)>, http_api_addr: SocketAddr, @@ -102,10 +103,7 @@ mod tests { ); let network_config = NetworkArgs { - discovery: DiscoveryArgs { - disable_discovery: true, - ..DiscoveryArgs::default() - }, + discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() }, ..NetworkArgs::default() }; @@ -120,10 +118,7 @@ mod tests { // Start websocket server to simulate the builder and send payloads back to the node let (sender, mut receiver) = mpsc::channel::<(Flashblock, oneshot::Sender<()>)>(100); - let NodeHandle { - node, - node_exit_future, - } = NodeBuilder::new(node_config.clone()) + let NodeHandle { node, node_exit_future } = NodeBuilder::new(node_config.clone()) .testing_node(exec.clone()) .with_types_and_provider::>() .with_components(node.components_builder()) @@ -389,9 +384,8 @@ mod tests { assert_eq!(latest_block.number(), 0); // Querying pending block when it does not exist yet - let pending_block = provider - .get_block_by_number(alloy_eips::BlockNumberOrTag::Pending) - .await?; + let pending_block = + provider.get_block_by_number(alloy_eips::BlockNumberOrTag::Pending).await?; assert_eq!(pending_block.is_none(), true); let base_payload = create_first_payload(); @@ -443,32 +437,16 @@ mod tests { let node = setup_node().await?; let provider = node.provider().await?; - assert!( - provider - .get_transaction_by_hash(DEPOSIT_TX_HASH) - .await? - .is_none() - ); - assert!( - provider - .get_transaction_by_hash(TRANSFER_ETH_HASH) - .await? - .is_none() - ); + assert!(provider.get_transaction_by_hash(DEPOSIT_TX_HASH).await?.is_none()); + assert!(provider.get_transaction_by_hash(TRANSFER_ETH_HASH).await?.is_none()); node.send_test_payloads().await?; - let tx1 = provider - .get_transaction_by_hash(DEPOSIT_TX_HASH) - .await? - .expect("tx1 expected"); + let tx1 = provider.get_transaction_by_hash(DEPOSIT_TX_HASH).await?.expect("tx1 expected"); assert_eq!(tx1.tx_hash(), DEPOSIT_TX_HASH); assert_eq!(tx1.from(), DEPOSIT_SENDER); - let tx2 = provider - .get_transaction_by_hash(TRANSFER_ETH_HASH) - .await? - .expect("tx2 expected"); + let tx2 = provider.get_transaction_by_hash(TRANSFER_ETH_HASH).await?.expect("tx2 expected"); assert_eq!(tx2.tx_hash(), TRANSFER_ETH_HASH); assert_eq!(tx2.from(), TX_SENDER); @@ -488,16 +466,12 @@ mod tests { node.send_test_payloads().await?; - let receipt = provider - .get_transaction_receipt(DEPOSIT_TX_HASH) - .await? - .expect("receipt expected"); + let receipt = + provider.get_transaction_receipt(DEPOSIT_TX_HASH).await?.expect("receipt expected"); assert_eq!(receipt.gas_used(), 21000); - let receipt = provider - .get_transaction_receipt(TRANSFER_ETH_HASH) - .await? - .expect("receipt expected"); + let receipt = + provider.get_transaction_receipt(TRANSFER_ETH_HASH).await?.expect("receipt expected"); assert_eq!(receipt.gas_used(), 24000); // 45000 - 21000 // TODO: Add a new payload and validate that the receipts from the previous payload @@ -513,18 +487,12 @@ mod tests { let provider = node.provider().await?; assert_eq!(provider.get_transaction_count(DEPOSIT_SENDER).await?, 0); - assert_eq!( - provider.get_transaction_count(TX_SENDER).pending().await?, - 0 - ); + assert_eq!(provider.get_transaction_count(TX_SENDER).pending().await?, 0); node.send_test_payloads().await?; assert_eq!(provider.get_transaction_count(DEPOSIT_SENDER).await?, 0); - assert_eq!( - provider.get_transaction_count(TX_SENDER).pending().await?, - 4 - ); + assert_eq!(provider.get_transaction_count(TX_SENDER).pending().await?, 4); Ok(()) } @@ -546,10 +514,8 @@ mod tests { .value(U256::from(9999999999849942300000u128)) .input(TransactionInput::new(bytes!("0x"))); - let res = provider - .call(send_eth_call.clone()) - .block(BlockNumberOrTag::Pending.into()) - .await; + let res = + provider.call(send_eth_call.clone()).block(BlockNumberOrTag::Pending.into()).await; assert!(res.is_ok()); @@ -557,19 +523,16 @@ mod tests { // We included a heavy spending transaction and now don't have enough funds for this request, so // this eth_call with fail - let res = provider - .call(send_eth_call.nonce(4)) - .block(BlockNumberOrTag::Pending.into()) - .await; + let res = + provider.call(send_eth_call.nonce(4)).block(BlockNumberOrTag::Pending.into()).await; assert!(res.is_err()); - assert!( - res.unwrap_err() - .as_error_resp() - .unwrap() - .message - .contains("insufficient funds for gas") - ); + assert!(res + .unwrap_err() + .as_error_resp() + .unwrap() + .message + .contains("insufficient funds for gas")); // read count1 from counter contract let eth_call_count1 = OpTransactionRequest::default() @@ -640,13 +603,12 @@ mod tests { .await; assert!(res.is_err()); - assert!( - res.unwrap_err() - .as_error_resp() - .unwrap() - .message - .contains("insufficient funds for gas") - ); + assert!(res + .unwrap_err() + .as_error_resp() + .unwrap() + .message + .contains("insufficient funds for gas")); Ok(()) } @@ -695,10 +657,8 @@ mod tests { validation: true, return_full_transactions: true, }; - let simulate_res = provider - .simulate(&simulate_call) - .block_id(BlockNumberOrTag::Pending.into()) - .await; + let simulate_res = + provider.simulate(&simulate_call).block_id(BlockNumberOrTag::Pending.into()).await; assert!(simulate_res.is_ok()); let block = simulate_res.unwrap(); assert_eq!(block.len(), 1); @@ -724,13 +684,11 @@ mod tests { node.send_payload(create_first_payload()).await?; // run the Tx sync and, in parallel, deliver the payload that contains the Tx - let (receipt_result, payload_result) = tokio::join!( - node.send_raw_transaction_sync(TRANSFER_ETH_TX, None), - async { + let (receipt_result, payload_result) = + tokio::join!(node.send_raw_transaction_sync(TRANSFER_ETH_TX, None), async { tokio::time::sleep(std::time::Duration::from_millis(100)).await; node.send_payload(create_second_payload()).await - } - ); + }); payload_result?; let receipt = receipt_result?; @@ -745,18 +703,14 @@ mod tests { let node = setup_node().await.unwrap(); // fail request immediately by passing a timeout of 0 ms - let receipt_result = node - .send_raw_transaction_sync(TRANSFER_ETH_TX, Some(0)) - .await; + let receipt_result = node.send_raw_transaction_sync(TRANSFER_ETH_TX, Some(0)).await; let error_code = EthRpcErrorCode::TransactionConfirmationTimeout.code(); - assert!( - receipt_result - .err() - .unwrap() - .to_string() - .contains(format!("{}", error_code).as_str()) - ); + assert!(receipt_result + .err() + .unwrap() + .to_string() + .contains(format!("{}", error_code).as_str())); } #[tokio::test] @@ -898,10 +852,7 @@ mod tests { // Should now include pending logs (2 logs from our test setup) assert_eq!(logs.len(), 2); - assert!( - logs.iter() - .all(|log| log.transaction_hash == Some(INCREMENT_HASH)) - ); + assert!(logs.iter().all(|log| log.transaction_hash == Some(INCREMENT_HASH))); // Test fromBlock: latest, toBlock: pending let logs = provider @@ -914,10 +865,7 @@ mod tests { // Should include pending logs (historical part is empty in our test setup) assert_eq!(logs.len(), 2); - assert!( - logs.iter() - .all(|log| log.transaction_hash == Some(INCREMENT_HASH)) - ); + assert!(logs.iter().all(|log| log.transaction_hash == Some(INCREMENT_HASH))); // Test fromBlock: earliest, toBlock: pending let logs = provider @@ -930,10 +878,7 @@ mod tests { // Should include pending logs (historical part is empty in our test setup) assert_eq!(logs.len(), 2); - assert!( - logs.iter() - .all(|log| log.transaction_hash == Some(INCREMENT_HASH)) - ); + assert!(logs.iter().all(|log| log.transaction_hash == Some(INCREMENT_HASH))); Ok(()) } diff --git a/crates/flashblocks-rpc/src/tests/state.rs b/crates/flashblocks-rpc/src/tests/state.rs index e8580f5c..4244e2db 100644 --- a/crates/flashblocks-rpc/src/tests/state.rs +++ b/crates/flashblocks-rpc/src/tests/state.rs @@ -1,42 +1,43 @@ #[cfg(test)] mod tests { - use crate::rpc::{FlashblocksAPI, PendingBlocksAPI}; - use crate::state::FlashblocksState; - use crate::subscription::{Flashblock, FlashblocksReceiver, Metadata}; - use crate::tests::utils::create_test_provider_factory; - use crate::tests::{BLOCK_INFO_TXN, BLOCK_INFO_TXN_HASH}; - use alloy_consensus::crypto::secp256k1::public_key_to_address; - use alloy_consensus::{BlockHeader, Receipt}; - use alloy_consensus::{Header, Transaction}; + use std::{sync::Arc, time::Duration}; + + use alloy_consensus::{ + crypto::secp256k1::public_key_to_address, BlockHeader, Header, Receipt, Transaction, + }; use alloy_eips::{BlockHashOrNumber, Decodable2718, Encodable2718}; use alloy_genesis::GenesisAccount; - use alloy_primitives::map::foldhash::HashMap; - use alloy_primitives::{Address, B256, BlockNumber, Bytes, U256}; + use alloy_primitives::{map::foldhash::HashMap, Address, BlockNumber, Bytes, B256, U256}; use alloy_provider::network::BlockResponse; use alloy_rpc_types_engine::PayloadId; use op_alloy_consensus::OpDepositReceipt; - use reth::builder::NodeTypesWithDBAdapter; - use reth::chainspec::EthChainSpec; - use reth::providers::{AccountReader, BlockNumReader, BlockReader}; - use reth::revm::database::StateProviderDatabase; - use reth::transaction_pool::test_utils::TransactionBuilder; - use reth_db::{DatabaseEnv, test_utils::TempDatabase}; - use reth_evm::ConfigureEvm; - use reth_evm::execute::Executor; - use reth_optimism_chainspec::{BASE_MAINNET, OpChainSpecBuilder}; + use reth::{ + builder::NodeTypesWithDBAdapter, + chainspec::EthChainSpec, + providers::{AccountReader, BlockNumReader, BlockReader}, + revm::database::StateProviderDatabase, + transaction_pool::test_utils::TransactionBuilder, + }; + use reth_db::{test_utils::TempDatabase, DatabaseEnv}; + use reth_evm::{execute::Executor, ConfigureEvm}; + use reth_optimism_chainspec::{OpChainSpecBuilder, BASE_MAINNET}; use reth_optimism_evm::OpEvmConfig; use reth_optimism_node::OpNode; use reth_optimism_primitives::{OpBlock, OpBlockBody, OpReceipt, OpTransactionSigned}; use reth_primitives_traits::{Account, Block, RecoveredBlock, SealedHeader}; - use reth_provider::providers::BlockchainProvider; use reth_provider::{ - BlockWriter, ChainSpecProvider, ExecutionOutcome, LatestStateProviderRef, ProviderFactory, - StateProviderFactory, + providers::BlockchainProvider, BlockWriter, ChainSpecProvider, ExecutionOutcome, + LatestStateProviderRef, ProviderFactory, StateProviderFactory, }; use rollup_boost::{ExecutionPayloadBaseV1, ExecutionPayloadFlashblockDeltaV1}; - use std::sync::Arc; - use std::time::Duration; use tokio::time::sleep; + + use crate::{ + rpc::{FlashblocksAPI, PendingBlocksAPI}, + state::FlashblocksState, + subscription::{Flashblock, FlashblocksReceiver, Metadata}, + tests::{utils::create_test_provider_factory, BLOCK_INFO_TXN, BLOCK_INFO_TXN_HASH}, + }; // The amount of time to wait (in milliseconds) after sending a new flashblock or canonical block // so it can be processed by the state processor const SLEEP_TIME: u64 = 10; @@ -71,10 +72,8 @@ mod tests { } fn current_canonical_block(&self) -> RecoveredBlock { - let latest_block_num = self - .provider - .last_block_number() - .expect("should be a latest block"); + let latest_block_num = + self.provider.last_block_number().expect("should be a latest block"); self.provider .block(BlockHashOrNumber::Number(latest_block_num)) @@ -180,11 +179,7 @@ mod tests { gas_limit: current_tip.header().gas_limit(), ..Header::default() }), - OpBlockBody { - transactions, - ommers: vec![], - withdrawals: None, - }, + OpBlockBody { transactions, ommers: vec![], withdrawals: None }, ) .try_recover() .expect("able to recover block"); @@ -193,9 +188,7 @@ mod tests { // Execute the block to produce a block execution output let mut block_execution_output = OpEvmConfig::optimism(self.provider.chain_spec()) - .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new( - &provider, - ))) + .batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider))) .execute(&block) .unwrap(); @@ -223,9 +216,7 @@ mod tests { } async fn new_canonical_block(&mut self, user_transactions: Vec) { - let block = self - .new_canonical_block_without_processing(user_transactions) - .await; + let block = self.new_canonical_block_without_processing(user_transactions).await; self.flashblocks.on_canonical_block_received(&block); sleep(Duration::from_millis(SLEEP_TIME)).await; } @@ -241,30 +232,16 @@ mod tests { let charlie = public_key_to_address(charli_signer.public_key()); let items = vec![ - ( - alice, - GenesisAccount::default().with_balance(U256::from(100_000_000)), - ), - ( - bob, - GenesisAccount::default().with_balance(U256::from(100_000_000)), - ), - ( - charlie, - GenesisAccount::default().with_balance(U256::from(100_000_000)), - ), + (alice, GenesisAccount::default().with_balance(U256::from(100_000_000))), + (bob, GenesisAccount::default().with_balance(U256::from(100_000_000))), + (charlie, GenesisAccount::default().with_balance(U256::from(100_000_000))), ]; - let genesis = BASE_MAINNET - .genesis - .clone() - .extend_accounts(items) - .with_gas_limit(100_000_000); + let genesis = + BASE_MAINNET.genesis.clone().extend_accounts(items).with_gas_limit(100_000_000); - let chain_spec = OpChainSpecBuilder::base_mainnet() - .genesis(genesis) - .isthmus_activated() - .build(); + let chain_spec = + OpChainSpecBuilder::base_mainnet().genesis(genesis).isthmus_activated().build(); let factory = create_test_provider_factory::(Arc::new(chain_spec)); assert!(reth_db_common::init::init_genesis(&factory).is_ok()); @@ -381,10 +358,8 @@ mod tests { pub fn build(&self) -> Flashblock { let current_block = self.harness.current_canonical_block(); - let canonical_block_num = self - .canonical_block_number - .unwrap_or_else(|| current_block.number) - + 1; + let canonical_block_num = + self.canonical_block_number.unwrap_or_else(|| current_block.number) + 1; let base = if self.index == 0 { Some(ExecutionPayloadBaseV1 { @@ -430,8 +405,7 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; assert_eq!( test.flashblocks .get_pending_blocks() @@ -442,20 +416,13 @@ mod tests { 1 ); - assert!( - test.flashblocks - .get_pending_blocks() - .get_state_overrides() - .is_some() - ); - assert!( - !test - .flashblocks - .get_pending_blocks() - .get_state_overrides() - .unwrap() - .contains_key(&test.address(User::Alice)) - ); + assert!(test.flashblocks.get_pending_blocks().get_state_overrides().is_some()); + assert!(!test + .flashblocks + .get_pending_blocks() + .get_state_overrides() + .unwrap() + .contains_key(&test.address(User::Alice))); test.send_flashblock( FlashblockBuilder::new(&test, 1) @@ -489,8 +456,7 @@ mod tests { U256::from(100_100_000) ); - test.send_flashblock(FlashblockBuilder::new(&test, 2).build()) - .await; + test.send_flashblock(FlashblockBuilder::new(&test, 2).build()).await; let overrides = test .flashblocks @@ -527,20 +493,13 @@ mod tests { 1 ); - assert!( - test.flashblocks - .get_pending_blocks() - .get_state_overrides() - .is_some() - ); - assert!( - !test - .flashblocks - .get_pending_blocks() - .get_state_overrides() - .unwrap() - .contains_key(&test.address(User::Alice)) - ); + assert!(test.flashblocks.get_pending_blocks().get_state_overrides().is_some()); + assert!(!test + .flashblocks + .get_pending_blocks() + .get_state_overrides() + .unwrap() + .contains_key(&test.address(User::Alice))); test.send_flashblock( FlashblockBuilder::new(&test, 1) @@ -600,19 +559,13 @@ mod tests { initial_block_number + 1 ); - assert!( - test.flashblocks - .get_pending_blocks() - .get_state_overrides() - .is_some() - ); - assert!( - test.flashblocks - .get_pending_blocks() - .get_state_overrides() - .unwrap() - .contains_key(&test.address(User::Alice)) - ); + assert!(test.flashblocks.get_pending_blocks().get_state_overrides().is_some()); + assert!(test + .flashblocks + .get_pending_blocks() + .get_state_overrides() + .unwrap() + .contains_key(&test.address(User::Alice))); test.send_flashblock( FlashblockBuilder::new(&test, 1) @@ -648,8 +601,7 @@ mod tests { reth_tracing::init_test_tracing(); let mut test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; assert_eq!( test.flashblocks .get_pending_blocks() @@ -659,20 +611,13 @@ mod tests { .len(), 1 ); - assert!( - test.flashblocks - .get_pending_blocks() - .get_state_overrides() - .is_some() - ); - assert!( - !test - .flashblocks - .get_pending_blocks() - .get_state_overrides() - .unwrap() - .contains_key(&test.address(User::Alice)) - ); + assert!(test.flashblocks.get_pending_blocks().get_state_overrides().is_some()); + assert!(!test + .flashblocks + .get_pending_blocks() + .get_state_overrides() + .unwrap() + .contains_key(&test.address(User::Alice))); test.send_flashblock( FlashblockBuilder::new(&test, 1) @@ -706,9 +651,7 @@ mod tests { ); test.send_flashblock( - FlashblockBuilder::new_base(&test) - .with_canonical_block_number(1) - .build(), + FlashblockBuilder::new_base(&test).with_canonical_block_number(1).build(), ) .await; test.send_flashblock( @@ -783,8 +726,7 @@ mod tests { reth_tracing::init_test_tracing(); let mut test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; test.send_flashblock( FlashblockBuilder::new(&test, 1) .with_transactions(vec![test.build_transaction_to_send_eth( @@ -796,35 +738,27 @@ mod tests { ) .await; - let pending_nonce = test - .provider - .basic_account(&test.address(User::Alice)) - .unwrap() - .unwrap() - .nonce - + test - .flashblocks - .get_pending_blocks() - .get_transaction_count(test.address(User::Alice)) - .to::(); + let pending_nonce = + test.provider.basic_account(&test.address(User::Alice)).unwrap().unwrap().nonce + + test + .flashblocks + .get_pending_blocks() + .get_transaction_count(test.address(User::Alice)) + .to::(); assert_eq!(pending_nonce, 1); test.new_canonical_block_without_processing(vec![ - test.build_transaction_to_send_eth_with_nonce(User::Alice, User::Bob, 100, 0), + test.build_transaction_to_send_eth_with_nonce(User::Alice, User::Bob, 100, 0) ]) .await; - let pending_nonce = test - .provider - .basic_account(&test.address(User::Alice)) - .unwrap() - .unwrap() - .nonce - + test - .flashblocks - .get_pending_blocks() - .get_transaction_count(test.address(User::Alice)) - .to::(); + let pending_nonce = + test.provider.basic_account(&test.address(User::Alice)).unwrap().unwrap().nonce + + test + .flashblocks + .get_pending_blocks() + .get_transaction_count(test.address(User::Alice)) + .to::(); // This is 2, because canon block has reached the underlying chain // but the StateProcessor hasn't processed it @@ -835,18 +769,10 @@ mod tests { // use the pending canon block instead of the latest block when fetching // onchain nonce count to compute // pending_nonce = onchain_nonce + pending_txn_count - let canon_block = test - .flashblocks - .get_pending_blocks() - .get_canonical_block_number(); - let canon_state_provider = test - .provider - .state_by_block_number_or_tag(canon_block) - .unwrap(); - let canon_nonce = canon_state_provider - .account_nonce(&test.address(User::Alice)) - .unwrap() - .unwrap(); + let canon_block = test.flashblocks.get_pending_blocks().get_canonical_block_number(); + let canon_state_provider = test.provider.state_by_block_number_or_tag(canon_block).unwrap(); + let canon_nonce = + canon_state_provider.account_nonce(&test.address(User::Alice)).unwrap().unwrap(); let pending_nonce = canon_nonce + test .flashblocks @@ -861,8 +787,7 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; let current_block = test.flashblocks.get_pending_blocks().get_block(true); @@ -889,22 +814,16 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; - let current_block = test - .flashblocks - .get_pending_blocks() - .get_block(true) - .expect("should be a block"); + let current_block = + test.flashblocks.get_pending_blocks().get_block(true).expect("should be a block"); assert_eq!(current_block.header().number, 1); assert_eq!(current_block.transactions.len(), 1); test.send_flashblock( - FlashblockBuilder::new(&test, 1) - .with_canonical_block_number(100) - .build(), + FlashblockBuilder::new(&test, 1).with_canonical_block_number(100).build(), ) .await; @@ -917,30 +836,21 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; - let current_block = test - .flashblocks - .get_pending_blocks() - .get_block(true) - .expect("should be a block"); + let current_block = + test.flashblocks.get_pending_blocks().get_block(true).expect("should be a block"); assert_eq!(current_block.header().number, 1); assert_eq!(current_block.transactions.len(), 1); test.send_flashblock( - FlashblockBuilder::new_base(&test) - .with_canonical_block_number(1) - .build(), + FlashblockBuilder::new_base(&test).with_canonical_block_number(1).build(), ) .await; - let current_block = test - .flashblocks - .get_pending_blocks() - .get_block(true) - .expect("should be a block"); + let current_block = + test.flashblocks.get_pending_blocks().get_block(true).expect("should be a block"); assert_eq!(current_block.header().number, 2); assert_eq!(current_block.transactions.len(), 1); @@ -951,15 +861,9 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - assert!( - test.flashblocks - .get_pending_blocks() - .get_block(true) - .is_none() - ); + assert!(test.flashblocks.get_pending_blocks().get_block(true).is_none()); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; // Just the block info transaction assert_eq!( @@ -991,8 +895,7 @@ mod tests { reth_tracing::init_test_tracing(); let test = TestHarness::new(); - test.send_flashblock(FlashblockBuilder::new_base(&test).build()) - .await; + test.send_flashblock(FlashblockBuilder::new_base(&test).build()).await; let fb = FlashblockBuilder::new(&test, 1) .with_transactions(vec![test.build_transaction_to_send_eth( @@ -1019,12 +922,7 @@ mod tests { let genesis_block = test.current_canonical_block(); assert_eq!(genesis_block.number, 0); assert_eq!(genesis_block.transaction_count(), 0); - assert!( - test.flashblocks - .get_pending_blocks() - .get_block(true) - .is_none() - ); + assert!(test.flashblocks.get_pending_blocks().get_block(true).is_none()); test.new_canonical_block(vec![test.build_transaction_to_send_eth( User::Alice, @@ -1036,12 +934,7 @@ mod tests { let block_one = test.current_canonical_block(); assert_eq!(block_one.number, 1); assert_eq!(block_one.transaction_count(), 2); - assert!( - test.flashblocks - .get_pending_blocks() - .get_block(true) - .is_none() - ); + assert!(test.flashblocks.get_pending_blocks().get_block(true).is_none()); test.new_canonical_block(vec![ test.build_transaction_to_send_eth(User::Bob, User::Charlie, 100), @@ -1052,11 +945,6 @@ mod tests { let block_two = test.current_canonical_block(); assert_eq!(block_two.number, 2); assert_eq!(block_two.transaction_count(), 3); - assert!( - test.flashblocks - .get_pending_blocks() - .get_block(true) - .is_none() - ); + assert!(test.flashblocks.get_pending_blocks().get_block(true).is_none()); } } diff --git a/crates/flashblocks-rpc/src/tests/utils.rs b/crates/flashblocks-rpc/src/tests/utils.rs index 287db423..cca64278 100644 --- a/crates/flashblocks-rpc/src/tests/utils.rs +++ b/crates/flashblocks-rpc/src/tests/utils.rs @@ -2,12 +2,12 @@ use std::sync::Arc; use reth::api::{NodeTypes, NodeTypesWithDBAdapter}; use reth_db::{ - ClientVersion, DatabaseEnv, init_db, - mdbx::{DatabaseArguments, KILOBYTE, MEGABYTE, MaxReadTransactionDuration}, - test_utils::{ERROR_DB_CREATION, TempDatabase, create_test_static_files_dir, tempdir_path}, + init_db, + mdbx::{DatabaseArguments, MaxReadTransactionDuration, KILOBYTE, MEGABYTE}, + test_utils::{create_test_static_files_dir, tempdir_path, TempDatabase, ERROR_DB_CREATION}, + ClientVersion, DatabaseEnv, }; - -use reth_provider::{ProviderFactory, providers::StaticFileProvider}; +use reth_provider::{providers::StaticFileProvider, ProviderFactory}; pub fn create_test_provider_factory( chain_spec: Arc, diff --git a/crates/metering/src/meter.rs b/crates/metering/src/meter.rs index d8882ee6..c9236201 100644 --- a/crates/metering/src/meter.rs +++ b/crates/metering/src/meter.rs @@ -1,14 +1,13 @@ -use alloy_consensus::{BlockHeader, Transaction as _, transaction::SignerRecoverable}; +use std::{sync::Arc, time::Instant}; + +use alloy_consensus::{transaction::SignerRecoverable, BlockHeader, Transaction as _}; use alloy_primitives::{B256, U256}; -use eyre::{Result as EyreResult, eyre}; +use eyre::{eyre, Result as EyreResult}; use reth::revm::db::State; -use reth_evm::ConfigureEvm; -use reth_evm::execute::BlockBuilder; +use reth_evm::{execute::BlockBuilder, ConfigureEvm}; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_evm::{OpEvmConfig, OpNextBlockEnvAttributes}; use reth_primitives_traits::SealedHeader; -use std::sync::Arc; -use std::time::Instant; use tips_core::types::{BundleExtensions, BundleTxs, ParsedBundle}; use crate::TransactionResult; @@ -40,16 +39,11 @@ where // Create state database let state_db = reth::revm::database::StateProviderDatabase::new(state_provider); - let mut db = State::builder() - .with_database(state_db) - .with_bundle_update() - .build(); + let mut db = State::builder().with_database(state_db).with_bundle_update().build(); // Set up next block attributes // Use bundle.min_timestamp if provided, otherwise use header timestamp + BLOCK_TIME - let timestamp = bundle - .min_timestamp - .unwrap_or_else(|| header.timestamp() + BLOCK_TIME); + let timestamp = bundle.min_timestamp.unwrap_or_else(|| header.timestamp() + BLOCK_TIME); let attributes = OpNextBlockEnvAttributes { timestamp, suggested_fee_recipient: header.beneficiary(), @@ -105,11 +99,5 @@ where } let total_execution_time = execution_start.elapsed().as_micros(); - Ok(( - results, - total_gas_used, - total_gas_fees, - bundle_hash, - total_execution_time, - )) + Ok((results, total_gas_used, total_gas_fees, bundle_hash, total_execution_time)) } diff --git a/crates/metering/src/rpc.rs b/crates/metering/src/rpc.rs index 98059fd3..31bd2616 100644 --- a/crates/metering/src/rpc.rs +++ b/crates/metering/src/rpc.rs @@ -2,7 +2,7 @@ use alloy_consensus::Header; use alloy_eips::BlockNumberOrTag; use alloy_primitives::U256; use jsonrpsee::{ - core::{RpcResult, async_trait}, + core::{async_trait, RpcResult}, proc_macros::rpc, }; use reth::providers::BlockReaderIdExt; @@ -85,17 +85,14 @@ where })?; // Get state provider for the block - let state_provider = self - .provider - .state_by_block_hash(header.hash()) - .map_err(|e| { - error!(error = %e, "Failed to get state provider"); - jsonrpsee::types::ErrorObjectOwned::owned( - jsonrpsee::types::ErrorCode::InternalError.code(), - format!("Failed to get state provider: {}", e), - None::<()>, - ) - })?; + let state_provider = self.provider.state_by_block_hash(header.hash()).map_err(|e| { + error!(error = %e, "Failed to get state provider"); + jsonrpsee::types::ErrorObjectOwned::owned( + jsonrpsee::types::ErrorCode::InternalError.code(), + format!("Failed to get state provider: {}", e), + None::<()>, + ) + })?; // Meter bundle using utility function let (results, total_gas_used, total_gas_fees, bundle_hash, total_execution_time) = diff --git a/crates/metering/src/tests/meter.rs b/crates/metering/src/tests/meter.rs index 0b10f44f..d861eb40 100644 --- a/crates/metering/src/tests/meter.rs +++ b/crates/metering/src/tests/meter.rs @@ -3,18 +3,17 @@ use std::sync::Arc; use alloy_consensus::crypto::secp256k1::public_key_to_address; use alloy_eips::Encodable2718; use alloy_genesis::GenesisAccount; -use alloy_primitives::{Address, B256, Bytes, U256, keccak256}; +use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; use eyre::Context; use op_alloy_consensus::OpTxEnvelope; -use rand::{SeedableRng, rngs::StdRng}; -use reth::api::NodeTypesWithDBAdapter; -use reth::chainspec::EthChainSpec; -use reth_db::{DatabaseEnv, test_utils::TempDatabase}; -use reth_optimism_chainspec::{BASE_MAINNET, OpChainSpec, OpChainSpecBuilder}; +use rand::{rngs::StdRng, SeedableRng}; +use reth::{api::NodeTypesWithDBAdapter, chainspec::EthChainSpec}; +use reth_db::{test_utils::TempDatabase, DatabaseEnv}; +use reth_optimism_chainspec::{OpChainSpec, OpChainSpecBuilder, BASE_MAINNET}; use reth_optimism_node::OpNode; use reth_optimism_primitives::OpTransactionSigned; use reth_primitives_traits::SealedHeader; -use reth_provider::{HeaderProvider, StateProviderFactory, providers::BlockchainProvider}; +use reth_provider::{providers::BlockchainProvider, HeaderProvider, StateProviderFactory}; use reth_testing_utils::generators::generate_keys; use reth_transaction_pool::test_utils::TransactionBuilder; use tips_core::types::{Bundle, ParsedBundle}; @@ -77,23 +76,13 @@ fn create_chain_spec( .genesis .clone() .extend_accounts(vec![ - ( - alice_address, - GenesisAccount::default().with_balance(U256::from(1_000_000_000_u64)), - ), - ( - bob_address, - GenesisAccount::default().with_balance(U256::from(1_000_000_000_u64)), - ), + (alice_address, GenesisAccount::default().with_balance(U256::from(1_000_000_000_u64))), + (bob_address, GenesisAccount::default().with_balance(U256::from(1_000_000_000_u64))), ]) .with_gas_limit(100_000_000); - let spec = Arc::new( - OpChainSpecBuilder::base_mainnet() - .genesis(genesis) - .isthmus_activated() - .build(), - ); + let spec = + Arc::new(OpChainSpecBuilder::base_mainnet().genesis(genesis).isthmus_activated().build()); (spec, addresses, private_keys) } @@ -110,13 +99,7 @@ fn setup_harness() -> eyre::Result { .context("fetching genesis header")? .expect("genesis header exists"); - Ok(TestHarness { - provider, - header, - chain_spec, - user_to_address, - user_to_private_key, - }) + Ok(TestHarness { provider, header, chain_spec, user_to_address, user_to_private_key }) } fn envelope_from_signed(tx: &OpTransactionSigned) -> eyre::Result { @@ -124,10 +107,7 @@ fn envelope_from_signed(tx: &OpTransactionSigned) -> eyre::Result } fn create_parsed_bundle(envelopes: Vec) -> eyre::Result { - let txs: Vec = envelopes - .iter() - .map(|env| Bytes::from(env.encoded_2718())) - .collect(); + let txs: Vec = envelopes.iter().map(|env| Bytes::from(env.encoded_2718())).collect(); let bundle = Bundle { txs, @@ -156,12 +136,7 @@ fn meter_bundle_empty_transactions() -> eyre::Result<()> { let parsed_bundle = create_parsed_bundle(Vec::new())?; let (results, total_gas_used, total_gas_fees, bundle_hash, total_execution_time) = - meter_bundle( - state_provider, - harness.chain_spec.clone(), - parsed_bundle, - &harness.header, - )?; + meter_bundle(state_provider, harness.chain_spec.clone(), parsed_bundle, &harness.header)?; assert!(results.is_empty()); assert_eq!(total_gas_used, 0); @@ -203,12 +178,7 @@ fn meter_bundle_single_transaction() -> eyre::Result<()> { let parsed_bundle = create_parsed_bundle(vec![envelope.clone()])?; let (results, total_gas_used, total_gas_fees, bundle_hash, total_execution_time) = - meter_bundle( - state_provider, - harness.chain_spec.clone(), - parsed_bundle, - &harness.header, - )?; + meter_bundle(state_provider, harness.chain_spec.clone(), parsed_bundle, &harness.header)?; assert_eq!(results.len(), 1); let result = &results[0]; @@ -219,10 +189,7 @@ fn meter_bundle_single_transaction() -> eyre::Result<()> { assert_eq!(result.tx_hash, tx_hash); assert_eq!(result.gas_price, U256::from(10).to_string()); assert_eq!(result.gas_used, 21_000); - assert_eq!( - result.coinbase_diff, - (U256::from(21_000) * U256::from(10)).to_string(), - ); + assert_eq!(result.coinbase_diff, (U256::from(21_000) * U256::from(10)).to_string(),); assert_eq!(total_gas_used, 21_000); assert_eq!(total_gas_fees, U256::from(21_000) * U256::from(10)); @@ -231,10 +198,7 @@ fn meter_bundle_single_transaction() -> eyre::Result<()> { concatenated.extend_from_slice(tx_hash.as_slice()); assert_eq!(bundle_hash, keccak256(concatenated)); - assert!( - result.execution_time_us > 0, - "execution_time_us should be greater than zero" - ); + assert!(result.execution_time_us > 0, "execution_time_us should be greater than zero"); Ok(()) } @@ -259,10 +223,7 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { .into_eip1559(); let tx_1 = OpTransactionSigned::Eip1559( - signed_tx_1 - .as_eip1559() - .expect("eip1559 transaction") - .clone(), + signed_tx_1.as_eip1559().expect("eip1559 transaction").clone(), ); // Create second transaction @@ -278,10 +239,7 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { .into_eip1559(); let tx_2 = OpTransactionSigned::Eip1559( - signed_tx_2 - .as_eip1559() - .expect("eip1559 transaction") - .clone(), + signed_tx_2.as_eip1559().expect("eip1559 transaction").clone(), ); let envelope_1 = envelope_from_signed(&tx_1)?; @@ -297,12 +255,7 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { let parsed_bundle = create_parsed_bundle(vec![envelope_1.clone(), envelope_2.clone()])?; let (results, total_gas_used, total_gas_fees, bundle_hash, total_execution_time) = - meter_bundle( - state_provider, - harness.chain_spec.clone(), - parsed_bundle, - &harness.header, - )?; + meter_bundle(state_provider, harness.chain_spec.clone(), parsed_bundle, &harness.header)?; assert_eq!(results.len(), 2); assert!(total_execution_time > 0); @@ -314,10 +267,7 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { assert_eq!(result_1.tx_hash, tx_hash_1); assert_eq!(result_1.gas_price, U256::from(10).to_string()); assert_eq!(result_1.gas_used, 21_000); - assert_eq!( - result_1.coinbase_diff, - (U256::from(21_000) * U256::from(10)).to_string(), - ); + assert_eq!(result_1.coinbase_diff, (U256::from(21_000) * U256::from(10)).to_string(),); // Check second transaction let result_2 = &results[1]; @@ -326,10 +276,7 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { assert_eq!(result_2.tx_hash, tx_hash_2); assert_eq!(result_2.gas_price, U256::from(15).to_string()); assert_eq!(result_2.gas_used, 21_000); - assert_eq!( - result_2.coinbase_diff, - (U256::from(21_000) * U256::from(15)).to_string(), - ); + assert_eq!(result_2.coinbase_diff, (U256::from(21_000) * U256::from(15)).to_string(),); // Check aggregated values assert_eq!(total_gas_used, 42_000); @@ -343,14 +290,8 @@ fn meter_bundle_multiple_transactions() -> eyre::Result<()> { concatenated.extend_from_slice(tx_hash_2.as_slice()); assert_eq!(bundle_hash, keccak256(concatenated)); - assert!( - result_1.execution_time_us > 0, - "execution_time_us should be greater than zero" - ); - assert!( - result_2.execution_time_us > 0, - "execution_time_us should be greater than zero" - ); + assert!(result_1.execution_time_us > 0, "execution_time_us should be greater than zero"); + assert!(result_2.execution_time_us > 0, "execution_time_us should be greater than zero"); Ok(()) } diff --git a/crates/metering/src/tests/rpc.rs b/crates/metering/src/tests/rpc.rs index 2f5778c8..5d630628 100644 --- a/crates/metering/src/tests/rpc.rs +++ b/crates/metering/src/tests/rpc.rs @@ -1,29 +1,29 @@ #[cfg(test)] mod tests { - use crate::rpc::{MeteringApiImpl, MeteringApiServer}; + use std::{any::Any, net::SocketAddr, sync::Arc}; + use alloy_eips::Encodable2718; use alloy_genesis::Genesis; - use alloy_primitives::bytes; - use alloy_primitives::{Bytes, U256, address, b256}; + use alloy_primitives::{address, b256, bytes, Bytes, U256}; use alloy_rpc_client::RpcClient; use op_alloy_consensus::OpTxEnvelope; - use reth::args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}; - use reth::builder::{Node, NodeBuilder, NodeConfig, NodeHandle}; - use reth::chainspec::Chain; - use reth::core::exit::NodeExitFuture; - use reth::tasks::TaskManager; + use reth::{ + args::{DiscoveryArgs, NetworkArgs, RpcServerArgs}, + builder::{Node, NodeBuilder, NodeConfig, NodeHandle}, + chainspec::Chain, + core::exit::NodeExitFuture, + tasks::TaskManager, + }; use reth_optimism_chainspec::OpChainSpecBuilder; - use reth_optimism_node::OpNode; - use reth_optimism_node::args::RollupArgs; + use reth_optimism_node::{args::RollupArgs, OpNode}; use reth_optimism_primitives::OpTransactionSigned; use reth_provider::providers::BlockchainProvider; use reth_transaction_pool::test_utils::TransactionBuilder; use serde_json; - use std::any::Any; - use std::net::SocketAddr; - use std::sync::Arc; use tips_core::types::Bundle; + use crate::rpc::{MeteringApiImpl, MeteringApiServer}; + pub struct NodeContext { http_api_addr: SocketAddr, _node_exit_future: NodeExitFuture, @@ -68,10 +68,7 @@ mod tests { ); let network_config = NetworkArgs { - discovery: DiscoveryArgs { - disable_discovery: true, - ..DiscoveryArgs::default() - }, + discovery: DiscoveryArgs { disable_discovery: true, ..DiscoveryArgs::default() }, ..NetworkArgs::default() }; @@ -82,10 +79,7 @@ mod tests { let node = OpNode::new(RollupArgs::default()); - let NodeHandle { - node, - node_exit_future, - } = NodeBuilder::new(node_config.clone()) + let NodeHandle { node, node_exit_future } = NodeBuilder::new(node_config.clone()) .testing_node(exec.clone()) .with_types_and_provider::>() .with_components(node.components_builder()) @@ -172,10 +166,7 @@ mod tests { let result = &response.results[0]; assert_eq!(result.from_address, sender_address); - assert_eq!( - result.to_address, - Some(address!("0x1111111111111111111111111111111111111111")) - ); + assert_eq!(result.to_address, Some(address!("0x1111111111111111111111111111111111111111"))); assert_eq!(result.gas_used, 21_000); assert_eq!(result.gas_price, "1000000000"); assert!(result.execution_time_us > 0); diff --git a/crates/metering/src/tests/utils.rs b/crates/metering/src/tests/utils.rs index 7bd29fef..d8181df4 100644 --- a/crates/metering/src/tests/utils.rs +++ b/crates/metering/src/tests/utils.rs @@ -2,11 +2,12 @@ use std::sync::Arc; use reth::api::{NodeTypes, NodeTypesWithDBAdapter}; use reth_db::{ - ClientVersion, DatabaseEnv, init_db, - mdbx::{DatabaseArguments, KILOBYTE, MEGABYTE, MaxReadTransactionDuration}, - test_utils::{ERROR_DB_CREATION, TempDatabase, create_test_static_files_dir, tempdir_path}, + init_db, + mdbx::{DatabaseArguments, MaxReadTransactionDuration, KILOBYTE, MEGABYTE}, + test_utils::{create_test_static_files_dir, tempdir_path, TempDatabase, ERROR_DB_CREATION}, + ClientVersion, DatabaseEnv, }; -use reth_provider::{ProviderFactory, providers::StaticFileProvider}; +use reth_provider::{providers::StaticFileProvider, ProviderFactory}; pub fn create_provider_factory( chain_spec: Arc, diff --git a/crates/node/src/main.rs b/crates/node/src/main.rs index b8dbb3ce..c598ae3f 100644 --- a/crates/node/src/main.rs +++ b/crates/node/src/main.rs @@ -1,26 +1,23 @@ -use base_reth_flashblocks_rpc::rpc::EthApiExt; -use futures_util::TryStreamExt; -use once_cell::sync::OnceCell; -use reth::version::{ - RethCliVersionConsts, default_reth_version_metadata, try_init_version_metadata, -}; -use reth_exex::ExExEvent; use std::sync::Arc; -use base_reth_flashblocks_rpc::rpc::EthApiOverrideServer; -use base_reth_flashblocks_rpc::state::FlashblocksState; -use base_reth_flashblocks_rpc::subscription::FlashblocksSubscriber; +use base_reth_flashblocks_rpc::{ + rpc::{EthApiExt, EthApiOverrideServer}, + state::FlashblocksState, + subscription::FlashblocksSubscriber, +}; use base_reth_metering::{MeteringApiImpl, MeteringApiServer}; use base_reth_transaction_tracing::transaction_tracing_exex; use clap::Parser; -use reth::builder::{Node, NodeHandle}; +use futures_util::TryStreamExt; +use once_cell::sync::OnceCell; use reth::{ - builder::{EngineNodeLauncher, TreeConfig}, + builder::{EngineNodeLauncher, Node, NodeHandle, TreeConfig}, providers::providers::BlockchainProvider, + version::{default_reth_version_metadata, try_init_version_metadata, RethCliVersionConsts}, }; -use reth_optimism_cli::{Cli, chainspec::OpChainSpecParser}; -use reth_optimism_node::OpNode; -use reth_optimism_node::args::RollupArgs; +use reth_exex::ExExEvent; +use reth_optimism_cli::{chainspec::OpChainSpecParser, Cli}; +use reth_optimism_node::{args::RollupArgs, OpNode}; use tracing::info; use url::Url; @@ -39,10 +36,7 @@ struct Args { pub websocket_url: Option, /// Enable transaction tracing ExEx for mempool-to-block timing analysis - #[arg( - long = "enable-transaction-tracing", - value_name = "ENABLE_TRANSACTION_TRACING" - )] + #[arg(long = "enable-transaction-tracing", value_name = "ENABLE_TRANSACTION_TRACING")] pub enable_transaction_tracing: bool, /// Enable `info` logs for transaction tracing @@ -78,11 +72,8 @@ fn main() { default_version_metadata.p2p_client_version, NODE_RETH_CLIENT_VERSION ) .into(), - extra_data: format!( - "{}/{}", - default_version_metadata.extra_data, NODE_RETH_CLIENT_VERSION - ) - .into(), + extra_data: format!("{}/{}", default_version_metadata.extra_data, NODE_RETH_CLIENT_VERSION) + .into(), ..default_version_metadata }) .expect("Unable to init version metadata"); @@ -98,10 +89,7 @@ fn main() { let fb_cell: Arc>>> = Arc::new(OnceCell::new()); - let NodeHandle { - node: _node, - node_exit_future, - } = builder + let NodeHandle { node: _node, node_exit_future } = builder .with_types_and_provider::>() .with_components(op_node.components()) .with_add_ons(op_node.add_ons()) @@ -110,10 +98,7 @@ fn main() { transaction_tracing_enabled, "transaction-tracing", move |ctx| async move { - Ok(transaction_tracing_exex( - ctx, - args.enable_transaction_tracing_logs, - )) + Ok(transaction_tracing_exex(ctx, args.enable_transaction_tracing_logs)) }, ) .install_exex_if(flashblocks_enabled, "flashblocks-canon", { diff --git a/crates/transaction-tracing/src/tracing.rs b/crates/transaction-tracing/src/tracing.rs index 220c8bc7..3d06c57d 100644 --- a/crates/transaction-tracing/src/tracing.rs +++ b/crates/transaction-tracing/src/tracing.rs @@ -1,15 +1,20 @@ +use std::{ + num::NonZeroUsize, + time::{Duration, Instant}, +}; + use alloy_primitives::TxHash; use chrono::Local; use eyre::Result; use futures::StreamExt; use lru::LruCache; -use reth::api::{BlockBody, FullNodeComponents}; -use reth::core::primitives::{AlloyBlockHeader, transaction::TxHashRef}; -use reth::transaction_pool::{FullTransactionEvent, TransactionPool}; +use reth::{ + api::{BlockBody, FullNodeComponents}, + core::primitives::{transaction::TxHashRef, AlloyBlockHeader}, + transaction_pool::{FullTransactionEvent, TransactionPool}, +}; use reth_exex::{ExExContext, ExExEvent, ExExNotification}; use reth_tracing::tracing::{debug, info}; -use std::num::NonZeroUsize; -use std::time::{Duration, Instant}; use crate::types::{EventLog, Pool, TxEvent}; @@ -151,11 +156,7 @@ impl Tracker { return false; } - self.log( - tx_hash, - event_log, - "Transaction removed from cache due to limit", - ); + self.log(tx_hash, event_log, "Transaction removed from cache due to limit"); record_histogram(event_log.mempool_time.elapsed(), TxEvent::Overflowed); true } diff --git a/crates/transaction-tracing/src/types.rs b/crates/transaction-tracing/src/types.rs index f80a6f4d..cbfa8370 100644 --- a/crates/transaction-tracing/src/types.rs +++ b/crates/transaction-tracing/src/types.rs @@ -1,6 +1,9 @@ +use std::{ + fmt::{self, Display}, + time::Instant, +}; + use chrono::{DateTime, Local}; -use std::fmt::{self, Display}; -use std::time::Instant; /// Types of transaction events to track #[derive(Debug, Clone, Copy, PartialEq)] @@ -47,11 +50,7 @@ pub struct EventLog { impl EventLog { pub fn new(t: DateTime, event: TxEvent) -> Self { - Self { - mempool_time: Instant::now(), - events: vec![(t, event)], - limit: 10, - } + Self { mempool_time: Instant::now(), events: vec![(t, event)], limit: 10 } } pub fn push(&mut self, t: DateTime, event: TxEvent) { diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..7b74d4d6 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,6 @@ +style_edition = "2021" +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +use_small_heuristics = "Max" +trailing_comma = "Vertical" +use_field_init_shorthand = true