From 4312ae21ffa5bf46b5203f6b9341803a96a513df Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Wed, 20 Nov 2024 23:17:45 +1100 Subject: [PATCH 1/9] make block sealing asynchronous and configurable --- src/config/cli.rs | 14 +++ src/config/mod.rs | 5 + src/main.rs | 36 +++++++- src/node/block_producer.rs | 54 +++++++++++ src/node/eth.rs | 184 ++++++------------------------------- src/node/impersonate.rs | 12 +++ src/node/in_memory.rs | 66 +++++++++++-- src/node/in_memory_ext.rs | 4 +- src/node/mod.rs | 7 ++ src/node/pool.rs | 62 +++++++++++++ src/node/sealer.rs | 80 ++++++++++++++++ src/node/time.rs | 2 +- src/node/zks.rs | 84 ++++++----------- 13 files changed, 384 insertions(+), 226 deletions(-) create mode 100644 src/node/block_producer.rs create mode 100644 src/node/pool.rs create mode 100644 src/node/sealer.rs diff --git a/src/config/cli.rs b/src/config/cli.rs index c3e194b9..bd78090a 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -1,4 +1,5 @@ use clap::{arg, command, Parser, Subcommand}; +use std::time::Duration; use zksync_types::H256; use crate::config::{ @@ -127,6 +128,11 @@ pub struct Cli { #[arg(long, help_heading = "Cache Options")] /// Cache directory location for disk cache (default: .cache). pub cache_dir: Option, + + #[arg(long, value_parser = duration_from_secs_f64, help_heading = "Block Sealing")] + /// Block time in seconds for interval sealing. + /// If unset, node seals a new block as soon as there is at least one transaction. + pub block_time: Option, } #[derive(Debug, Subcommand)] @@ -249,3 +255,11 @@ impl Cli { } } } + +fn duration_from_secs_f64(s: &str) -> Result { + let s = s.parse::().map_err(|e| e.to_string())?; + if s == 0.0 { + return Err("Duration must be greater than 0".to_string()); + } + Duration::try_from_secs_f64(s).map_err(|e| e.to_string()) +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 1bb6ae3a..e11f28cf 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -58,6 +58,8 @@ pub struct TestNodeConfig { pub log_file_path: String, /// Cache configuration for the test node pub cache_config: CacheConfig, + /// Maximum number of transactions per block + pub max_transactions: usize, } impl Default for TestNodeConfig { @@ -89,6 +91,9 @@ impl Default for TestNodeConfig { // Cache configuration default cache_config: Default::default(), + + // Block sealing configuration default + max_transactions: 1000, } } } diff --git a/src/main.rs b/src/main.rs index 2c9503ee..651588d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,8 @@ use crate::namespaces::{ EthTestNodeNamespaceT, EvmNamespaceT, HardhatNamespaceT, NetNamespaceT, Web3NamespaceT, ZksNamespaceT, }; +use crate::node::{BlockProducer, BlockSealer, ImpersonationManager, TimestampManager, TxPool}; +use crate::system_contracts::SystemContracts; #[allow(clippy::too_many_arguments)] async fn build_json_http< @@ -217,8 +219,17 @@ async fn main() -> anyhow::Result<()> { } } - let node: InMemoryNode = - InMemoryNode::new(fork_details, Some(observability), &config); + let time = TimestampManager::default(); + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation.clone()); + let node: InMemoryNode = InMemoryNode::new( + fork_details, + Some(observability), + &config, + time.clone(), + impersonation, + pool.clone(), + ); if let Some(bytecodes_dir) = opt.override_bytecodes_dir { override_bytecodes(&node, bytecodes_dir).unwrap(); @@ -254,15 +265,32 @@ async fn main() -> anyhow::Result<()> { let threads = build_json_http( SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), config.port), log_level_filter, - node, + node.clone(), ) .await; + let block_sealer = if let Some(block_time) = opt.block_time { + BlockSealer::fixed_time(config.max_transactions, block_time) + } else { + BlockSealer::immediate(config.max_transactions) + }; + let system_contracts = + SystemContracts::from_options(&config.system_contracts_options, config.use_evm_emulator); + let block_producer_handle = tokio::task::spawn(BlockProducer::new( + node, + pool, + block_sealer, + system_contracts, + )); + tracing::info!("========================================"); tracing::info!(" Node is ready at 127.0.0.1:{}", config.port); tracing::info!("========================================"); - future::select_all(vec![threads]).await.0.unwrap(); + future::select_all(vec![threads, block_producer_handle]) + .await + .0 + .unwrap(); Ok(()) } diff --git a/src/node/block_producer.rs b/src/node/block_producer.rs new file mode 100644 index 00000000..8f81a15e --- /dev/null +++ b/src/node/block_producer.rs @@ -0,0 +1,54 @@ +use crate::fork::ForkSource; +use crate::node::pool::{TxBatch, TxPool}; +use crate::node::sealer::BlockSealer; +use crate::node::InMemoryNode; +use crate::system_contracts::SystemContracts; +use std::fmt; +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; +use zksync_multivm::interface::TxExecutionMode; + +pub struct BlockProducer { + node: InMemoryNode, + pool: TxPool, + block_sealer: BlockSealer, + system_contracts: SystemContracts, +} + +impl BlockProducer { + pub fn new( + node: InMemoryNode, + pool: TxPool, + block_sealer: BlockSealer, + system_contracts: SystemContracts, + ) -> Self { + Self { + node, + pool, + block_sealer, + system_contracts, + } + } +} + +impl Future for BlockProducer { + type Output = (); + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let pin = self.get_mut(); + loop { + if let Poll::Ready(tx_batch) = pin.block_sealer.poll(&pin.pool, cx) { + let TxBatch { impersonating, txs } = tx_batch; + + let base_system_contracts = pin + .system_contracts + .contracts(TxExecutionMode::VerifyExecute, impersonating) + .clone(); + pin.node + .seal_block(txs, base_system_contracts) + .expect("block sealing failed"); + } + } + } +} diff --git a/src/node/eth.rs b/src/node/eth.rs index 65ef02e0..bda13562 100644 --- a/src/node/eth.rs +++ b/src/node/eth.rs @@ -101,13 +101,7 @@ impl InMemoryNo return Err(err.into()); }; - self.seal_block(vec![l2_tx], system_contracts) - .map_err(|err| { - Web3Error::SubmitTransactionError( - format!("Execution error: {err}"), - hash.as_bytes().to_vec(), - ) - })?; + self.pool.add_tx(l2_tx); Ok(hash) } @@ -183,13 +177,7 @@ impl InMemoryNo return Err(TransparentError(err).into()); } - self.seal_block(vec![l2_tx], system_contracts) - .map_err(|err| { - Web3Error::SubmitTransactionError( - format!("Execution error: {err}"), - hash.as_bytes().to_vec(), - ) - })?; + self.pool.add_tx(l2_tx); Ok(hash) } } @@ -1489,6 +1477,14 @@ mod tests { use zksync_types::{web3, Nonce}; use zksync_web3_decl::types::{SyncState, ValueOrArray}; + async fn test_node(url: &str) -> InMemoryNode { + InMemoryNode::::default_fork(Some( + ForkDetails::from_network(url, None, &CacheConfig::None) + .await + .unwrap(), + )) + } + #[tokio::test] async fn test_eth_syncing() { let node = InMemoryNode::::default(); @@ -1696,15 +1692,7 @@ mod tests { transaction_count: 0, }); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let inner = node.get_inner(); let inner = inner.read().unwrap(); @@ -1744,15 +1732,7 @@ mod tests { }), block_response, ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_block = node .get_block_by_hash(input_block_hash, false) @@ -1901,15 +1881,7 @@ mod tests { }), block_response, ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_block = node .get_block_by_number(BlockNumber::Number(U64::from(8)), false) @@ -1953,15 +1925,7 @@ mod tests { transaction_count: 0, }); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_block = node .get_block_by_number(BlockNumber::Latest, false) @@ -1993,15 +1957,7 @@ mod tests { .set_number(input_block_number) .build(), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_block = node .get_block_by_number(BlockNumber::Earliest, false) @@ -2024,15 +1980,7 @@ mod tests { hash: H256::repeat_byte(0xab), transaction_count: 0, }); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_block = node .get_block_by_number(block_number, false) @@ -2086,15 +2034,7 @@ mod tests { "result": format!("{:#x}", input_transaction_count), }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_transaction_count = node .get_block_transaction_count_by_hash(input_block_hash) @@ -2147,15 +2087,7 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_transaction_count = node .get_block_transaction_count_by_number(BlockNumber::Number(U64::from(1))) @@ -2193,15 +2125,7 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_transaction_count = node .get_block_transaction_count_by_number(BlockNumber::Earliest) @@ -2230,15 +2154,7 @@ mod tests { hash: H256::repeat_byte(0xab), }); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_transaction_count = node .get_block_transaction_count_by_number(block_number) @@ -2509,15 +2425,7 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_value = node .get_storage( @@ -2608,15 +2516,7 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; node.get_inner() .write() .map(|mut writer| { @@ -3225,15 +3125,7 @@ mod tests { .build(), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; // store the block info with just the tx hash invariant { @@ -3284,15 +3176,7 @@ mod tests { .build(), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_tx = node .get_transaction_by_block_hash_and_index(input_block_hash, U64::from(1)) @@ -3383,15 +3267,7 @@ mod tests { .build(), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; // store the block info with just the tx hash invariant { @@ -3449,15 +3325,7 @@ mod tests { .build(), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = test_node(&mock_server.url()).await; let actual_tx = node .get_transaction_by_block_number_and_index( diff --git a/src/node/impersonate.rs b/src/node/impersonate.rs index 4a99187e..e188987c 100644 --- a/src/node/impersonate.rs +++ b/src/node/impersonate.rs @@ -58,4 +58,16 @@ impl ImpersonationManager { .write() .expect("ImpersonationManager lock is poisoned") = accounts; } + + /// Inspects the entire account set on a user-provided function without dropping the lock. + pub fn inspect(&self, f: F) -> R + where + F: FnOnce(&HashSet
) -> R, + { + let guard = self + .state + .read() + .expect("ImpersonationManager lock is poisoned"); + f(&guard) + } } diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index 2a1e17f6..41754515 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -48,6 +48,7 @@ use zksync_web3_decl::error::Web3Error; use crate::node::impersonate::ImpersonationManager; use crate::node::time::TimestampManager; +use crate::node::TxPool; use crate::{ bootloader_debug::{BootloaderDebug, BootloaderDebugTracer}, config::{ @@ -242,6 +243,8 @@ impl InMemoryNodeInner { fork: Option, observability: Option, config: &TestNodeConfig, + time: TimestampManager, + impersonation: ImpersonationManager, ) -> Self { let mut updated_config = config.clone(); @@ -272,9 +275,10 @@ impl InMemoryNodeInner { f.estimate_gas_scale_factor, ) }; + time.set_last_timestamp_unchecked(f.block_timestamp); InMemoryNodeInner { - time: TimestampManager::new(f.block_timestamp), + time, current_batch: f.l1_block.0, current_miniblock: f.l2_miniblock, current_miniblock_hash: f.l2_miniblock_hash, @@ -307,9 +311,10 @@ impl InMemoryNodeInner { let mut blocks = HashMap::>::new(); blocks.insert(block_hash, create_genesis(NON_FORK_FIRST_BLOCK_TIMESTAMP)); let fee_input_provider = TestNodeFeeInputProvider::default(); + time.set_last_timestamp_unchecked(NON_FORK_FIRST_BLOCK_TIMESTAMP); InMemoryNodeInner { - time: TimestampManager::new(NON_FORK_FIRST_BLOCK_TIMESTAMP), + time, current_batch: 0, current_miniblock: 0, current_miniblock_hash: block_hash, @@ -330,7 +335,7 @@ impl InMemoryNodeInner { &config.system_contracts_options, config.use_evm_emulator, ), - impersonation: Default::default(), + impersonation, rich_accounts: HashSet::new(), previous_states: Default::default(), observability, @@ -890,6 +895,7 @@ pub struct InMemoryNode { pub(crate) system_contracts_options: system_contracts::Options, pub(crate) time: TimestampManager, pub(crate) impersonation: ImpersonationManager, + pub(crate) pool: TxPool, } fn contract_address_from_tx_result(execution_result: &VmExecutionResultAndLogs) -> Option { @@ -903,7 +909,15 @@ fn contract_address_from_tx_result(execution_result: &VmExecutionResultAndLogs) impl Default for InMemoryNode { fn default() -> Self { - InMemoryNode::new(None, None, &TestNodeConfig::default()) + let impersonation = ImpersonationManager::default(); + InMemoryNode::new( + None, + None, + &TestNodeConfig::default(), + TimestampManager::default(), + impersonation.clone(), + TxPool::new(impersonation), + ) } } @@ -912,20 +926,42 @@ impl InMemoryNode { fork: Option, observability: Option, config: &TestNodeConfig, + time: TimestampManager, + impersonation: ImpersonationManager, + pool: TxPool, ) -> Self { let system_contracts_options = config.system_contracts_options; - let inner = InMemoryNodeInner::new(fork, observability, config); - let time = inner.time.clone(); - let impersonation = inner.impersonation.clone(); + let inner = InMemoryNodeInner::new( + fork, + observability, + config, + time.clone(), + impersonation.clone(), + ); InMemoryNode { inner: Arc::new(RwLock::new(inner)), snapshots: Default::default(), system_contracts_options, time, impersonation, + pool, } } + // Common pattern in tests + // TODO: Refactor InMemoryNode with a builder pattern + pub fn default_fork(fork: Option) -> Self { + let impersonation = ImpersonationManager::default(); + Self::new( + fork, + None, + &Default::default(), + TimestampManager::default(), + impersonation.clone(), + TxPool::new(impersonation), + ) + } + pub fn get_inner(&self) -> Arc>> { self.inner.clone() } @@ -964,7 +1000,13 @@ impl InMemoryNode { .clone(); let config = self.get_config()?; - let inner = InMemoryNodeInner::new(fork, observability, &config); + let inner = InMemoryNodeInner::new( + fork, + observability, + &config, + TimestampManager::default(), + ImpersonationManager::default(), + ); let mut writer = self .snapshots @@ -1986,6 +2028,7 @@ mod tests { let mock_db = testing::ExternalStorage { raw_storage: external_storage.inner.read().unwrap().raw_storage.clone(), }; + let impersonation = ImpersonationManager::default(); let node: InMemoryNode = InMemoryNode::new( Some(ForkDetails { fork_source: Box::new(mock_db), @@ -2006,6 +2049,9 @@ mod tests { }), None, &Default::default(), + TimestampManager::default(), + impersonation.clone(), + TxPool::new(impersonation), ); let tx = testing::TransactionBuilder::new().build(); @@ -2019,6 +2065,7 @@ mod tests { #[tokio::test] async fn test_transact_returns_data_in_built_in_without_security_mode() { + let impersonation = ImpersonationManager::default(); let node = InMemoryNode::::new( None, None, @@ -2026,6 +2073,9 @@ mod tests { system_contracts_options: Options::BuiltInWithoutSecurity, ..Default::default() }, + TimestampManager::default(), + impersonation.clone(), + TxPool::new(impersonation), ); let private_key = K256PrivateKey::from_bytes(H256::repeat_byte(0xef)).unwrap(); diff --git a/src/node/in_memory_ext.rs b/src/node/in_memory_ext.rs index 03aec802..2c46bb59 100644 --- a/src/node/in_memory_ext.rs +++ b/src/node/in_memory_ext.rs @@ -371,7 +371,7 @@ mod tests { use crate::fork::ForkStorage; use crate::namespaces::EthNamespaceT; use crate::node::time::TimestampManager; - use crate::node::{InMemoryNodeInner, Snapshot}; + use crate::node::{InMemoryNodeInner, Snapshot, TxPool}; use crate::{http_fork_source::HttpForkSource, node::InMemoryNode}; use std::str::FromStr; use std::sync::{Arc, RwLock}; @@ -499,6 +499,7 @@ mod tests { }; let time = old_inner.time.clone(); let impersonation = old_inner.impersonation.clone(); + let pool = TxPool::new(impersonation.clone()); let node = InMemoryNode:: { inner: Arc::new(RwLock::new(old_inner)), @@ -506,6 +507,7 @@ mod tests { system_contracts_options: old_system_contracts_options, time, impersonation, + pool, }; let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap(); diff --git a/src/node/mod.rs b/src/node/mod.rs index 7cd35a24..71b1e63f 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -1,6 +1,7 @@ //! In-memory node, that supports forking other networks. mod anvil; +mod block_producer; mod call_error_tracer; mod config_api; mod debug; @@ -12,9 +13,15 @@ mod impersonate; mod in_memory; mod in_memory_ext; mod net; +mod pool; +mod sealer; mod storage_logs; mod time; mod web3; mod zks; +pub use self::{ + block_producer::BlockProducer, impersonate::ImpersonationManager, pool::TxPool, + sealer::BlockSealer, time::TimestampManager, +}; pub use in_memory::*; diff --git a/src/node/pool.rs b/src/node/pool.rs new file mode 100644 index 00000000..78c701da --- /dev/null +++ b/src/node/pool.rs @@ -0,0 +1,62 @@ +use crate::node::impersonate::ImpersonationManager; +use std::sync::{Arc, RwLock}; +use zksync_types::l2::L2Tx; + +#[derive(Clone)] +pub struct TxPool { + inner: Arc>>, + impersonation: ImpersonationManager, +} + +impl TxPool { + pub fn new(impersonation: ImpersonationManager) -> Self { + Self { + inner: Arc::new(RwLock::new(Vec::new())), + impersonation, + } + } + + pub fn add_tx(&self, tx: L2Tx) { + let mut guard = self.inner.write().expect("TxPool lock is poisoned"); + guard.push(tx); + } + + /// Take up to `n` continuous transactions from the pool that are all uniform in impersonation + /// type (either all are impersonating or all non-impersonating). + // TODO: We should distinguish ready transactions from non-ready ones. Only ready txs should be takeable. + pub fn take_uniform(&self, n: usize) -> Option { + if n == 0 { + return None; + } + let mut guard = self.inner.write().expect("TxPool lock is poisoned"); + let mut iter = guard.iter(); + let Some(head_tx) = iter.next() else { + // Pool is empty + return None; + }; + let (impersonating, tx_count) = self.impersonation.inspect(|impersonated_accounts| { + // First tx's impersonation status decides what all other txs' impersonation status is + // expected to be. + let impersonating = + impersonated_accounts.contains(&head_tx.common_data.initiator_address); + let tail_txs = iter + // Guaranteed to be non-zero + .take(n - 1) + .take_while(|tx| { + impersonating + == impersonated_accounts.contains(&tx.common_data.initiator_address) + }); + // The amount of transactions that can be taken from the pool; `+1` accounts for `head_tx`. + (impersonating, tail_txs.count() + 1) + }); + + let txs = guard.drain(0..tx_count).collect(); + Some(TxBatch { impersonating, txs }) + } +} + +/// A batch of transactions sharing the same impersonation status. +pub struct TxBatch { + pub impersonating: bool, + pub txs: Vec, +} diff --git a/src/node/sealer.rs b/src/node/sealer.rs new file mode 100644 index 00000000..72770c78 --- /dev/null +++ b/src/node/sealer.rs @@ -0,0 +1,80 @@ +use crate::node::pool::{TxBatch, TxPool}; +use std::task::{Context, Poll}; +use std::time::Duration; +use tokio::time::{Interval, MissedTickBehavior}; + +/// Mode of operations for the `BlockSealer` +#[derive(Debug)] +pub enum BlockSealer { + /// Seals a block as soon as there is at least one transaction. + Immediate(ImmediateBlockSealer), + /// Seals a new block every `interval` tick + FixedTime(FixedTimeBlockSealer), +} + +impl BlockSealer { + pub fn immediate(max_transactions: usize) -> Self { + Self::Immediate(ImmediateBlockSealer { max_transactions }) + } + + pub fn fixed_time(max_transactions: usize, block_time: Duration) -> Self { + Self::FixedTime(FixedTimeBlockSealer::new(max_transactions, block_time)) + } + + pub fn poll(&mut self, pool: &TxPool, cx: &mut Context<'_>) -> Poll { + match self { + BlockSealer::Immediate(immediate) => immediate.poll(pool), + BlockSealer::FixedTime(fixed) => fixed.poll(pool, cx), + } + } +} + +#[derive(Debug)] +pub struct ImmediateBlockSealer { + /// Maximum number of transactions to include in a block. + max_transactions: usize, +} + +impl ImmediateBlockSealer { + pub fn poll(&mut self, pool: &TxPool) -> Poll { + let Some(tx_batch) = pool.take_uniform(self.max_transactions) else { + return Poll::Pending; + }; + + Poll::Ready(tx_batch) + } +} + +#[derive(Debug)] +pub struct FixedTimeBlockSealer { + /// Maximum number of transactions to include in a block. + max_transactions: usize, + /// The interval when a block should be sealed. + interval: Interval, +} + +impl FixedTimeBlockSealer { + pub fn new(max_transactions: usize, block_time: Duration) -> Self { + let start = tokio::time::Instant::now() + block_time; + let mut interval = tokio::time::interval_at(start, block_time); + // Avoid shortening interval if a tick was missed + interval.set_missed_tick_behavior(MissedTickBehavior::Delay); + Self { + max_transactions, + interval, + } + } + + pub fn poll(&mut self, pool: &TxPool, cx: &mut Context<'_>) -> Poll { + if self.interval.poll_tick(cx).is_ready() { + // Return a batch even if the pool is empty, i.e. we produce empty blocks by design in + // fixed time mode. + let tx_batch = pool.take_uniform(self.max_transactions).unwrap_or(TxBatch { + impersonating: false, + txs: vec![], + }); + return Poll::Ready(tx_batch); + } + Poll::Pending + } +} diff --git a/src/node/time.rs b/src/node/time.rs index 57a1817b..068f34da 100644 --- a/src/node/time.rs +++ b/src/node/time.rs @@ -4,7 +4,7 @@ use std::sync::{Arc, RwLock}; /// Manages timestamps (in seconds) across the system. /// /// Clones always agree on the underlying timestamp and updating one affects all other instances. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct TimestampManager { /// The latest timestamp (in seconds) that has already been used. last_timestamp: Arc>, diff --git a/src/node/zks.rs b/src/node/zks.rs index c2fc00c2..fc383ee8 100644 --- a/src/node/zks.rs +++ b/src/node/zks.rs @@ -742,15 +742,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) + .await + .unwrap(), + )); let result = node .get_transaction_details(input_tx_hash) @@ -832,15 +828,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) + .await + .unwrap(), + )); let result = node .get_block_details(miniblock) @@ -914,15 +906,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) + .await + .unwrap(), + )); let actual_bridge_addresses = node .get_bridge_contracts() @@ -981,15 +969,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) + .await + .unwrap(), + )); let actual = node .get_bytecode_by_hash(input_hash) @@ -1106,15 +1090,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), None, &CacheConfig::None) + .await + .unwrap(), + )); let txns = node .get_raw_block_transactions(miniblock) @@ -1289,15 +1269,11 @@ mod tests { }), ); - let node = InMemoryNode::::new( - Some( - ForkDetails::from_network(&mock_server.url(), Some(1), &CacheConfig::None) - .await - .unwrap(), - ), - None, - &Default::default(), - ); + let node = InMemoryNode::::default_fork(Some( + ForkDetails::from_network(&mock_server.url(), Some(1), &CacheConfig::None) + .await + .unwrap(), + )); { let inner = node.get_inner(); From 8f9c1547390933f02cb98774f57a5ada0ce60f83 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Wed, 20 Nov 2024 23:17:59 +1100 Subject: [PATCH 2/9] fix e2e tests --- e2e-tests/test/debug-apis.test.ts | 23 ++++++++++++++--------- e2e-tests/test/evm-apis.test.ts | 9 ++++++--- e2e-tests/test/main.test.ts | 3 ++- e2e-tests/test/zks-apis.test.ts | 13 ++++++++----- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/e2e-tests/test/debug-apis.test.ts b/e2e-tests/test/debug-apis.test.ts index 609e2f87..034ef69f 100644 --- a/e2e-tests/test/debug-apis.test.ts +++ b/e2e-tests/test/debug-apis.test.ts @@ -5,6 +5,7 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import { RichAccounts } from "../helpers/constants"; import { deployContract, expectThrowsAsync, getTestProvider } from "../helpers/utils"; import { BigNumber } from "ethers"; +import {TransactionResponse} from "@ethersproject/abstract-provider"; const provider = getTestProvider(); @@ -88,15 +89,16 @@ describe("debug_traceTransaction", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const txReceipt = await greeter.setGreeting("Luke Skywalker"); - const trace = await provider.send("debug_traceTransaction", [txReceipt.hash]); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + const txReceipt = await txResponse.wait(); + const trace = await provider.send("debug_traceTransaction", [txReceipt.transactionHash]); // call should be successful expect(trace.error).to.equal(null); expect(trace.calls.length).to.equal(1); // gas limit should match - expect(BigNumber.from(trace.gas).toNumber()).to.equal(txReceipt.gasLimit.toNumber()); + expect(BigNumber.from(trace.gas).toNumber()).to.equal(txResponse.gasLimit.toNumber()); }); it("Should respect only_top_calls option", async function () { @@ -105,9 +107,10 @@ describe("debug_traceTransaction", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const txReceipt = await greeter.setGreeting("Luke Skywalker"); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + const txReceipt = await txResponse.wait(); const trace = await provider.send("debug_traceTransaction", [ - txReceipt.hash, + txReceipt.transactionHash, { tracer: "callTracer", tracerConfig: { onlyTopCall: true } }, ]); @@ -124,7 +127,8 @@ describe("debug_traceBlockByHash", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const txReceipt = await greeter.setGreeting("Luke Skywalker"); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + await txResponse.wait(); const latestBlock = await provider.getBlock("latest"); const block = await provider.getBlock(latestBlock.number - 1); @@ -135,7 +139,7 @@ describe("debug_traceBlockByHash", function () { // should contain trace for our tx const trace = traces[0].result; - expect(trace.input).to.equal(txReceipt.data); + expect(trace.input).to.equal(txResponse.data); }); }); @@ -146,7 +150,8 @@ describe("debug_traceBlockByNumber", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const txReceipt = await greeter.setGreeting("Luke Skywalker"); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + await txResponse.wait(); // latest block will be empty, check we get no traces for it const empty_traces = await provider.send("debug_traceBlockByNumber", ["latest"]); @@ -161,6 +166,6 @@ describe("debug_traceBlockByNumber", function () { // should contain trace for our tx const trace = traces[0].result; - expect(trace.input).to.equal(txReceipt.data); + expect(trace.input).to.equal(txResponse.data); }); }); diff --git a/e2e-tests/test/evm-apis.test.ts b/e2e-tests/test/evm-apis.test.ts index d1a9a181..558a3844 100644 --- a/e2e-tests/test/evm-apis.test.ts +++ b/e2e-tests/test/evm-apis.test.ts @@ -49,10 +49,11 @@ describe("evm_increaseTime", function () { // Act await provider.send("evm_increaseTime", [timeIncreaseInSeconds]); - await wallet.sendTransaction({ + const txResponse = await wallet.sendTransaction({ to: userWallet.address, value: ethers.utils.parseEther("0.1"), }); + await txResponse.wait(); expectedTimestamp += 2; // New transaction will add two blocks // Assert @@ -73,10 +74,11 @@ describe("evm_setNextBlockTimestamp", function () { // Act await provider.send("evm_setNextBlockTimestamp", [expectedTimestamp.toString(16)]); - await wallet.sendTransaction({ + const txResponse = await wallet.sendTransaction({ to: userWallet.address, value: ethers.utils.parseEther("0.1"), }); + await txResponse.wait(); expectedTimestamp += 1; // After executing a transaction, the node puts it into a block and increases its current timestamp // Assert @@ -97,10 +99,11 @@ describe("evm_setTime", function () { // Act await provider.send("evm_setTime", [expectedTimestamp]); - await wallet.sendTransaction({ + const txResponse = await wallet.sendTransaction({ to: userWallet.address, value: ethers.utils.parseEther("0.1"), }); + await txResponse.wait(); expectedTimestamp += 2; // New transaction will add two blocks // Assert diff --git a/e2e-tests/test/main.test.ts b/e2e-tests/test/main.test.ts index 75d4a217..c3d01011 100644 --- a/e2e-tests/test/main.test.ts +++ b/e2e-tests/test/main.test.ts @@ -32,10 +32,11 @@ describe("Greeter Smart Contract", function () { // setup user wallet with 3 ETH const userWallet = Wallet.createRandom().connect(provider); - await wallet.sendTransaction({ + const txResponse = await wallet.sendTransaction({ to: userWallet.address, value: ethers.utils.parseEther("3"), }); + await txResponse.wait(); // deploy Greeter contract const artifact = await deployer.loadArtifact("Greeter"); diff --git a/e2e-tests/test/zks-apis.test.ts b/e2e-tests/test/zks-apis.test.ts index 8b7489a5..0c3f2c80 100644 --- a/e2e-tests/test/zks-apis.test.ts +++ b/e2e-tests/test/zks-apis.test.ts @@ -6,6 +6,7 @@ import { BigNumber, ethers } from "ethers"; import * as hre from "hardhat"; import { TransactionRequest } from "zksync-web3/build/src/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import {TransactionResponse} from "@ethersproject/abstract-provider"; const provider = getTestProvider(); @@ -66,8 +67,9 @@ describe("zks_getTransactionDetails", function () { const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const txReceipt = await greeter.setGreeting("Luke Skywalker"); - const details = await provider.send("zks_getTransactionDetails", [txReceipt.hash]); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + const txReceipt = await txResponse.wait(); + const details = await provider.send("zks_getTransactionDetails", [txReceipt.transactionHash]); expect(details["status"]).to.equal("included"); expect(details["initiatorAddress"].toLowerCase()).to.equal(wallet.address.toLowerCase()); @@ -96,7 +98,7 @@ describe("zks_getBlockDetails", function () { const deployer = new Deployer(hre, wallet); const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - await greeter.setGreeting("Luke Skywalker"); + await (await greeter.setGreeting("Luke Skywalker")).wait(); const latestBlock = await provider.getBlock("latest"); const details = await provider.send("zks_getBlockDetails", [latestBlock.number]); @@ -145,13 +147,14 @@ describe("zks_getRawBlockTransactions", function () { const deployer = new Deployer(hre, wallet); const greeter = await deployContract(deployer, "Greeter", ["Hi"]); - const receipt = await greeter.setGreeting("Luke Skywalker"); + const txResponse: TransactionResponse = await greeter.setGreeting("Luke Skywalker"); + await txResponse.wait(); const latestBlock = await provider.getBlock("latest"); const txns = await provider.send("zks_getRawBlockTransactions", [latestBlock.number - 1]); expect(txns.length).to.equal(1); - expect(txns[0]["execute"]["calldata"]).to.equal(receipt.data); + expect(txns[0]["execute"]["calldata"]).to.equal(txResponse.data); }); }); From ba6ccfc82e5eab03bdf6322ef5295d94064bf472 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Wed, 20 Nov 2024 23:30:43 +1100 Subject: [PATCH 3/9] fmt typescript --- e2e-tests/test/debug-apis.test.ts | 2 +- e2e-tests/test/zks-apis.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/test/debug-apis.test.ts b/e2e-tests/test/debug-apis.test.ts index 034ef69f..ee2a7100 100644 --- a/e2e-tests/test/debug-apis.test.ts +++ b/e2e-tests/test/debug-apis.test.ts @@ -5,7 +5,7 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import { RichAccounts } from "../helpers/constants"; import { deployContract, expectThrowsAsync, getTestProvider } from "../helpers/utils"; import { BigNumber } from "ethers"; -import {TransactionResponse} from "@ethersproject/abstract-provider"; +import { TransactionResponse } from "@ethersproject/abstract-provider"; const provider = getTestProvider(); diff --git a/e2e-tests/test/zks-apis.test.ts b/e2e-tests/test/zks-apis.test.ts index 0c3f2c80..3e8f3a92 100644 --- a/e2e-tests/test/zks-apis.test.ts +++ b/e2e-tests/test/zks-apis.test.ts @@ -6,7 +6,7 @@ import { BigNumber, ethers } from "ethers"; import * as hre from "hardhat"; import { TransactionRequest } from "zksync-web3/build/src/types"; import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; -import {TransactionResponse} from "@ethersproject/abstract-provider"; +import { TransactionResponse } from "@ethersproject/abstract-provider"; const provider = getTestProvider(); From 67c68147d36cca0dd8a6d337a28c561c6524c0cf Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 21 Nov 2024 15:12:08 +1100 Subject: [PATCH 4/9] match anvil's block_time cli behaviour --- src/config/cli.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/cli.rs b/src/config/cli.rs index 95e27daa..fd875984 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -179,7 +179,7 @@ pub struct Cli { /// Block time in seconds for interval sealing. /// If unset, node seals a new block as soon as there is at least one transaction. - #[arg(long, value_parser = duration_from_secs_f64, help_heading = "Block Sealing")] + #[arg(short, long, value_name = "SECONDS", value_parser = duration_from_secs_f64, help_heading = "Block Sealing")] pub block_time: Option, } From b54dece63284402dd48020ec9c0425373bb04e4f Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 21 Nov 2024 16:36:19 +1100 Subject: [PATCH 5/9] add unit tests for `TxPool` --- Cargo.lock | 34 ++++++ Cargo.toml | 1 + src/node/pool.rs | 289 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 323 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index e0c55b74..1ef243ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2502,6 +2502,7 @@ dependencies = [ "serde_json", "sha3 0.10.8", "tempdir", + "test-case", "test-log", "time", "tokio", @@ -7473,6 +7474,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "test-case-core", +] + [[package]] name = "test-log" version = "0.2.16" diff --git a/Cargo.toml b/Cargo.toml index 71effade..5c77c34a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,7 @@ openrpc-types = "0.4.0" alloy = { version = "0.5", features = ["full"] } test-log = "0.2.16" fs2 = "0.4.3" +test-case = "3.3.1" [profile.dev] debug = 0 diff --git a/src/node/pool.rs b/src/node/pool.rs index 78c701da..b0632a05 100644 --- a/src/node/pool.rs +++ b/src/node/pool.rs @@ -5,7 +5,7 @@ use zksync_types::l2::L2Tx; #[derive(Clone)] pub struct TxPool { inner: Arc>>, - impersonation: ImpersonationManager, + pub(crate) impersonation: ImpersonationManager, } impl TxPool { @@ -55,8 +55,295 @@ impl TxPool { } } +// Test utilities +#[cfg(test)] +impl TxPool { + /// Populates pool with `N` randomly generated transactions without impersonation. + pub fn populate(&self) -> [L2Tx; N] { + let to_impersonate = [false; N]; + self.populate_impersonate(to_impersonate) + } + + /// Populates pool with `N` randomly generated transactions where `i`-th transaction is using an + /// impersonated account if `to_impersonate[i]` is `true`. + pub fn populate_impersonate(&self, to_impersonate: [bool; N]) -> [L2Tx; N] { + to_impersonate.map(|to_impersonate| { + let tx = crate::testing::TransactionBuilder::new().build(); + + if to_impersonate { + assert!(self + .impersonation + .impersonate(tx.common_data.initiator_address)); + } + + self.add_tx(tx.clone()); + tx + }) + } +} + /// A batch of transactions sharing the same impersonation status. +#[derive(PartialEq, Debug)] pub struct TxBatch { pub impersonating: bool, pub txs: Vec, } + +#[cfg(test)] +mod tests { + use crate::node::pool::TxBatch; + use crate::node::{ImpersonationManager, TxPool}; + use crate::testing; + use std::collections::HashSet; + use test_case::test_case; + + #[test] + fn take_from_empty() { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + assert_eq!(pool.take_uniform(1), None); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_zero(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + pool.populate_impersonate([imp]); + assert_eq!(pool.take_uniform(0), None); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_exactly_one(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, ..] = pool.populate_impersonate([imp, false]); + assert_eq!( + pool.take_uniform(1), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0] + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_exactly_two(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, ..] = pool.populate_impersonate([imp, imp, false]); + assert_eq!( + pool.take_uniform(2), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0, tx1] + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_one_eligible(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, ..] = pool.populate_impersonate([imp, !imp, !imp, !imp]); + assert_eq!( + pool.take_uniform(4), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0] + }) + ); + } + + // 3 transactions in total: 1 and 2 share impersonation status, 3 does not. + // `TxPool` should only take [1, 2] when 3 txs are requested. + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_two_when_third_is_not_uniform(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, ..] = pool.populate_impersonate([imp, imp, !imp]); + assert_eq!( + pool.take_uniform(3), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0, tx1] + }) + ); + } + + // 4 transactions in total: 1, 2 and 4 share impersonation status, 3 does not. + // `TxPool` should only take [1, 2] when 4 txs are requested. + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_interrupted_by_non_uniformness(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, ..] = pool.populate_impersonate([imp, imp, !imp, imp]); + assert_eq!( + pool.take_uniform(4), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0, tx1] + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_multiple(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, tx2, tx3] = pool.populate_impersonate([imp, !imp, !imp, imp]); + assert_eq!( + pool.take_uniform(100), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0] + }) + ); + assert_eq!( + pool.take_uniform(100), + Some(TxBatch { + impersonating: !imp, + txs: vec![tx1, tx2] + }) + ); + assert_eq!( + pool.take_uniform(100), + Some(TxBatch { + impersonating: imp, + txs: vec![tx3] + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn pool_clones_share_state(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let txs = { + let pool_clone = pool.clone(); + pool_clone.populate_impersonate([imp, imp, imp]) + }; + assert_eq!( + pool.take_uniform(3), + Some(TxBatch { + impersonating: imp, + txs: txs.to_vec() + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_multiple_from_clones(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, tx2, tx3] = { + let pool_clone = pool.clone(); + pool_clone.populate_impersonate([imp, !imp, !imp, imp]) + }; + let pool0 = pool.clone(); + assert_eq!( + pool0.take_uniform(100), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0] + }) + ); + let pool1 = pool.clone(); + assert_eq!( + pool1.take_uniform(100), + Some(TxBatch { + impersonating: !imp, + txs: vec![tx1, tx2] + }) + ); + let pool2 = pool.clone(); + assert_eq!( + pool2.take_uniform(100), + Some(TxBatch { + impersonating: imp, + txs: vec![tx3] + }) + ); + } + + #[test_case(false ; "not impersonated")] + #[test_case(true ; "is impersonated")] + fn take_respects_impersonation_change(imp: bool) { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation); + + let [tx0, tx1, tx2, tx3] = pool.populate_impersonate([imp, imp, !imp, imp]); + assert_eq!( + pool.take_uniform(4), + Some(TxBatch { + impersonating: imp, + txs: vec![tx0, tx1] + }) + ); + + // Change tx2's impersonation status to opposite + if !imp { + pool.impersonation + .stop_impersonating(&tx2.common_data.initiator_address); + } else { + pool.impersonation + .impersonate(tx2.common_data.initiator_address); + } + + assert_eq!( + pool.take_uniform(4), + Some(TxBatch { + impersonating: imp, + txs: vec![tx2, tx3] + }) + ); + } + + #[tokio::test] + async fn take_uses_consistent_impersonation() { + let impersonation = ImpersonationManager::default(); + let pool = TxPool::new(impersonation.clone()); + + for _ in 0..4096 { + let tx = testing::TransactionBuilder::new().build(); + + assert!(pool + .impersonation + .impersonate(tx.common_data.initiator_address)); + + pool.add_tx(tx.clone()); + } + + let take_handle = tokio::spawn(async move { pool.take_uniform(4096) }); + let clear_impersonation_handle = + tokio::spawn(async move { impersonation.set_impersonated_accounts(HashSet::new()) }); + + clear_impersonation_handle.await.unwrap(); + let tx_batch = take_handle + .await + .unwrap() + .expect("failed to take a tx batch"); + // Note that we do not assert impersonation status as both `true` and `false` are valid + // results here depending on the race between the two tasks above. But the returned + // transactions should always be a complete set - in other words, `TxPool` should not see + // a change in impersonation state partway through iterating the transactions. + assert_eq!(tx_batch.txs.len(), 4096); + } +} From 4f604da8db277f391b5a84773322741535b91c58 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 21 Nov 2024 18:13:06 +1100 Subject: [PATCH 6/9] add unit tests for `BlockSealer` --- src/node/sealer.rs | 217 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/src/node/sealer.rs b/src/node/sealer.rs index 72770c78..b8ec8f42 100644 --- a/src/node/sealer.rs +++ b/src/node/sealer.rs @@ -78,3 +78,220 @@ impl FixedTimeBlockSealer { Poll::Pending } } + +#[cfg(test)] +mod tests { + use crate::node::pool::TxBatch; + use crate::node::{BlockSealer, ImpersonationManager, TxPool}; + use std::ptr; + use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; + use std::time::Duration; + + const NOOP: RawWaker = { + const VTABLE: RawWakerVTable = RawWakerVTable::new( + // Cloning just returns a new no-op raw waker + |_| NOOP, + // `wake` does nothing + |_| {}, + // `wake_by_ref` does nothing + |_| {}, + // Dropping does nothing as we don't allocate anything + |_| {}, + ); + RawWaker::new(ptr::null(), &VTABLE) + }; + const WAKER_NOOP: Waker = unsafe { Waker::from_raw(NOOP) }; + + #[test] + fn immediate_empty() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::immediate(1000); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + } + + #[test] + fn immediate_one_tx() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::immediate(1000); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + let [tx] = pool.populate::<1>(); + + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: vec![tx] + }) + ); + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + } + + #[test] + fn immediate_several_txs() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::immediate(1000); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + let txs = pool.populate::<10>(); + + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: txs.to_vec() + }) + ); + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + } + + #[test] + fn immediate_respect_max_txs() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::immediate(3); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + let txs = pool.populate::<10>(); + + for txs in txs.chunks(3) { + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: txs.to_vec() + }) + ); + } + } + + #[test] + fn immediate_gradual_txs() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::immediate(1000); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + // Txs are added to the pool in small chunks + let txs0 = pool.populate::<3>(); + let txs1 = pool.populate::<4>(); + let txs2 = pool.populate::<5>(); + + let mut txs = txs0.to_vec(); + txs.extend(txs1); + txs.extend(txs2); + + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs, + }) + ); + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + + // Txs added after the first poll should be available for sealing + let txs = pool.populate::<10>().to_vec(); + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs, + }) + ); + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + } + + #[tokio::test] + async fn fixed_time_very_long() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_secs(10000)); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + } + + #[tokio::test] + async fn fixed_time_seal_empty() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + // Sleep enough time to (theoretically) produce at least 2 blocks + tokio::time::sleep(Duration::from_millis(250)).await; + + // Sealer should seal one empty block when polled and then refuse to seal another one + // shortly after as it ensures enough time passes in-between of blocks. + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: vec![] + }) + ); + assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); + + // Sleep enough time to produce one block + tokio::time::sleep(Duration::from_millis(150)).await; + + // Next block should be sealable + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: vec![] + }) + ); + } + + #[tokio::test] + async fn fixed_time_seal_with_txs() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + let txs = pool.populate::<3>(); + + // Sleep enough time to produce one block + tokio::time::sleep(Duration::from_millis(150)).await; + + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: txs.to_vec() + }) + ); + } + + #[tokio::test] + async fn fixed_time_respect_max_txs() { + let pool = TxPool::new(ImpersonationManager::default()); + let mut block_sealer = BlockSealer::fixed_time(3, Duration::from_millis(100)); + let waker = &WAKER_NOOP; + let mut cx = Context::from_waker(&waker); + + let txs = pool.populate::<10>(); + + for txs in txs.chunks(3) { + // Sleep enough time to produce one block + tokio::time::sleep(Duration::from_millis(150)).await; + + assert_eq!( + block_sealer.poll(&pool, &mut cx), + Poll::Ready(TxBatch { + impersonating: false, + txs: txs.to_vec() + }) + ); + } + } +} From 3173ee6f1bffc8167184866d84fc40cadde4ed5c Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 21 Nov 2024 18:42:59 +1100 Subject: [PATCH 7/9] lint --- src/node/sealer.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/node/sealer.rs b/src/node/sealer.rs index b8ec8f42..215f3ddd 100644 --- a/src/node/sealer.rs +++ b/src/node/sealer.rs @@ -107,7 +107,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::immediate(1000); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); } @@ -117,7 +117,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::immediate(1000); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); let [tx] = pool.populate::<1>(); @@ -136,7 +136,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::immediate(1000); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); let txs = pool.populate::<10>(); @@ -155,7 +155,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::immediate(3); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); let txs = pool.populate::<10>(); @@ -175,7 +175,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::immediate(1000); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); // Txs are added to the pool in small chunks let txs0 = pool.populate::<3>(); @@ -212,7 +212,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_secs(10000)); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); assert_eq!(block_sealer.poll(&pool, &mut cx), Poll::Pending); } @@ -222,7 +222,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); // Sleep enough time to (theoretically) produce at least 2 blocks tokio::time::sleep(Duration::from_millis(250)).await; @@ -256,7 +256,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); let txs = pool.populate::<3>(); @@ -277,7 +277,7 @@ mod tests { let pool = TxPool::new(ImpersonationManager::default()); let mut block_sealer = BlockSealer::fixed_time(3, Duration::from_millis(100)); let waker = &WAKER_NOOP; - let mut cx = Context::from_waker(&waker); + let mut cx = Context::from_waker(waker); let txs = pool.populate::<10>(); From ad3b8a3043bc1c7526427a1ab3a28dc6c3fb14df Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Wed, 27 Nov 2024 12:33:30 +1100 Subject: [PATCH 8/9] add alloy-zksync powered e2e tests --- .github/workflows/checks.yaml | 6 + .github/workflows/e2e-rust.yml | 35 + e2e-tests-rust/.cargo/config.toml | 2 + e2e-tests-rust/Cargo.lock | 3872 +++++++++++++++++++++++++++++ e2e-tests-rust/Cargo.toml | 21 + e2e-tests-rust/src/lib.rs | 1 + e2e-tests-rust/src/utils.rs | 73 + e2e-tests-rust/tests/lib.rs | 97 + src/node/in_memory.rs | 9 +- 9 files changed, 4108 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/e2e-rust.yml create mode 100644 e2e-tests-rust/.cargo/config.toml create mode 100644 e2e-tests-rust/Cargo.lock create mode 100644 e2e-tests-rust/Cargo.toml create mode 100644 e2e-tests-rust/src/lib.rs create mode 100644 e2e-tests-rust/src/utils.rs create mode 100644 e2e-tests-rust/tests/lib.rs diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 9c4308b3..e1258246 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -63,7 +63,13 @@ jobs: needs: build uses: ./.github/workflows/e2e.yml name: e2e-tests + spec: needs: build uses: ./.github/workflows/spec.yml name: spec-tests + + e2e-rust: + needs: build + uses: ./.github/workflows/e2e-rust.yml + name: e2e-tests-rust diff --git a/.github/workflows/e2e-rust.yml b/.github/workflows/e2e-rust.yml new file mode 100644 index 00000000..ed429f60 --- /dev/null +++ b/.github/workflows/e2e-rust.yml @@ -0,0 +1,35 @@ +name: Testing era_test_node using e2e (Rust version) +on: + workflow_call: + +jobs: + spec: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + name: spec + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: era_test_node-${{ matrix.os }}.tar.gz + + - name: Extract era_test_node + id: extract_node + run: | + echo "Extracting era_test_node binary" + tar -xzf era_test_node-${{ matrix.os }}.tar.gz + chmod +x era_test_node + + - name: Launch tests + id: launch + working-directory: ./e2e-tests-rust + run: cargo test + env: + ERA_TEST_NODE_BINARY_PATH: ../era_test_node diff --git a/e2e-tests-rust/.cargo/config.toml b/e2e-tests-rust/.cargo/config.toml new file mode 100644 index 00000000..ec6a5d0a --- /dev/null +++ b/e2e-tests-rust/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target-dir = "../target" diff --git a/e2e-tests-rust/Cargo.lock b/e2e-tests-rust/Cargo.lock new file mode 100644 index 00000000..5b745825 --- /dev/null +++ b/e2e-tests-rust/Cargo.lock @@ -0,0 +1,3872 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "alloy" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b524b8c28a7145d1fe4950f84360b5de3e307601679ff0558ddc20ea229399" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-network", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", +] + +[[package]] +name = "alloy-chains" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae09ffd7c29062431dd86061deefe4e3c6f07fa0d674930095f8dcedb0baf02c" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "c-kzg", + "derive_more", + "k256", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66430a72d5bf5edead101c8c2f0a24bada5ec9f3cf9909b3e08b6d6899b4803e" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-provider", + "alloy-pubsub", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-core" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8316d83e590f4163b221b8180008f302bda5cf5451202855cdd323e588849c" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-rlp", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2364c782a245cf8725ea6dbfca5f530162702b5d685992ea03ce64529136cc" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6cee6a35793f3db8a5ffe60e86c695f321d081a567211245f503e8c498fce8" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "derive_more", + "k256", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b6aa3961694b30ba53d41006131a2fca3bdab22e4c344e46db2c639e7c2dfdd" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53f7877ded3921d18a0a9556d55bedf84535567198c9edab2aa23106da91855" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84c506bf264110fa7e90d9924f742f40ef53c6572ea56a0b0bd714a567ed389" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3694b7e480728c0b3e228384f223937f14c10caef5a4c766021190fc8f283d35" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea94b8ceb5c75d7df0a93ba0acc53b55a22b47b532b600a800a87ef04eb5b0b4" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9f3e281005943944d15ee8491534a1c7b3cbf7a7de26f8c433b842b93eb5f9" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fce5dbd6a4f118eecc4719eaa9c7ffc31c315e6c5ccde3642db927802312425" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "foldhash", + "hashbrown 0.15.2", + "hex-literal", + "indexmap", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand", + "ruint", + "rustc-hash", + "serde", + "sha3", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c1f9eede27bf4c13c099e8e64d54efd7ce80ef6ea47478aa75d5d74e2dba3b" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-pubsub", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "parking_lot", + "pin-project", + "reqwest", + "schnellru", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-pubsub" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f1f34232f77341076541c405482e4ae12f0ee7153d8f9969fc1691201b2247" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "bimap", + "futures", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374dbe0dc3abdc2c964f36b3d3edf9cdb3db29d16bda34aa123f03d810bec1dd" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-pubsub", + "alloy-transport", + "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c74832aa474b670309c20fffc2a869fa141edab7c79ff7963fad0a08de60bae1" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-engine" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56294dce86af23ad6ee8df46cf8b0d292eb5d1ff67dc88a0886051e32b1faf" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "derive_more", + "serde", + "strum", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a477281940d82d29315846c7216db45b15e90bcd52309da9f54bcf7ad94a11" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "derive_more", + "itertools 0.13.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dfa4a7ccf15b2492bb68088692481fd6b2604ccbee1d0d6c44c21427ae4df83" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e10aec39d60dc27edcac447302c7803d2371946fb737245320a05b78eb2fafd" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8396f6dff60700bc1d215ee03d86ff56de268af96e2bf833a14d0bafcab9882" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "k256", + "rand", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9343289b4a7461ed8bab8618504c995c049c082b70c7332efd7b32125633dc05" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4222d70bec485ceccc5d8fd4f2909edd65b5d5e43d4aca0b5dcee65d519ae98f" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.89", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e17f2677369571b976e51ea1430eb41c3690d344fef567b840bfc0b01b6f83a" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.89", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa64d80ae58ffaafdff9d5d84f58d03775f66c84433916dc9a64ed16af5755da" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6520d427d4a8eb7aa803d852d7a52ceb0c519e784c292f64bb339e636918cf27" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f99acddb34000d104961897dbb0240298e8b775a7efffb9fda2a1a3efedd65b3" +dependencies = [ + "alloy-json-rpc", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", + "wasmtimer", +] + +[[package]] +name = "alloy-transport-http" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc013132e34eeadaa0add7e74164c1503988bfba8bae885b32e0918ba85a8a6" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-ipc" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063edc0660e81260653cc6a95777c29d54c2543a668aa5da2359fb450d25a1ba" +dependencies = [ + "alloy-json-rpc", + "alloy-pubsub", + "alloy-transport", + "bytes", + "futures", + "interprocess", + "pin-project", + "serde_json", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "alloy-transport-ws" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd170e600801116d5efe64f74a4fc073dbbb35c807013a7d0a388742aeebba0" +dependencies = [ + "alloy-pubsub", + "alloy-transport", + "futures", + "http", + "rustls", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "ws_stream_wasm", +] + +[[package]] +name = "alloy-zksync" +version = "0.6.0" +source = "git+https://github.com/itegulov/alloy-zksync.git?rev=b433d2d64e0f7d939891064b00d8a7991a427682#b433d2d64e0f7d939891064b00d8a7991a427682" +dependencies = [ + "alloy", + "async-trait", + "chrono", + "futures-utils-wasm", + "k256", + "rand", + "reqwest", + "serde", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.1", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "const-hex" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487981fa1af147182687064d0a2c336586d337a606595ced9ffb0c685c250c73" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "era_test_node_e2e_tests" +version = "0.0.0" +dependencies = [ + "alloy", + "alloy-zksync", + "anyhow", + "fs2", + "tokio", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "interprocess" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb" +dependencies = [ + "doctest-file", + "futures-core", + "libc", + "recvmsg", + "tokio", + "widestring", + "windows-sys 0.52.0", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.165" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "openssl" +version = "0.10.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.1", +] + +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "recvmsg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schnellru" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +dependencies = [ + "ahash", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.89", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76fe0a3e1476bdaa0775b9aec5b869ed9520c2b2fedfe9c6df3618f8ea6290b" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "wasmtimer" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0048ad49a55b9deb3953841fa1fc5858f0efbcb7a18868c899a360269fac1b23" +dependencies = [ + "futures", + "js-sys", + "parking_lot", + "pin-utils", + "slab", + "wasm-bindgen", +] + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.1", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] diff --git a/e2e-tests-rust/Cargo.toml b/e2e-tests-rust/Cargo.toml new file mode 100644 index 00000000..7c075db8 --- /dev/null +++ b/e2e-tests-rust/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "era_test_node_e2e_tests" +edition = "2021" +authors = ["The Matter Labs Team "] +homepage = "https://zksync.io/" +repository = "https://github.com/matter-labs/era-test-node" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] +publish = false + +[dependencies] +anyhow = "1.0" +fs2 = "0.4.3" +tokio = { version = "1", features = ["time", "rt", "process"] } + +[dev-dependencies] +alloy-zksync = { git = "https://github.com/itegulov/alloy-zksync.git", rev = "b433d2d64e0f7d939891064b00d8a7991a427682" } +alloy = { version = "0.6", features = ["full", "rlp", "serde", "sol-types"] } + +[workspace] # ignore higher-level workspace diff --git a/e2e-tests-rust/src/lib.rs b/e2e-tests-rust/src/lib.rs new file mode 100644 index 00000000..b5614dd8 --- /dev/null +++ b/e2e-tests-rust/src/lib.rs @@ -0,0 +1 @@ +pub mod utils; diff --git a/e2e-tests-rust/src/utils.rs b/e2e-tests-rust/src/utils.rs new file mode 100644 index 00000000..0d605e84 --- /dev/null +++ b/e2e-tests-rust/src/utils.rs @@ -0,0 +1,73 @@ +// FIXME: Copy-pasted from spec-tests, we need to restructure the crates +use anyhow::Context; +use fs2::FileExt; +use std::{ + fs::File, + net::{Ipv4Addr, SocketAddrV4}, +}; +use tokio::net::TcpListener; + +pub struct LockedPort { + pub port: u16, + lockfile: File, +} + +impl LockedPort { + /// Checks if the requested port is free. + /// Returns the unused port (same value as input, except for `0`). + async fn check_port_is_unused(port: u16) -> anyhow::Result { + let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port); + let listener = TcpListener::bind(addr) + .await + .context("failed to bind to random port")?; + let port = listener + .local_addr() + .context("failed to get local address for random port")? + .port(); + Ok(port) + } + + /// Request an unused port from the OS. + async fn pick_unused_port() -> anyhow::Result { + // Port 0 means the OS gives us an unused port + Self::check_port_is_unused(0).await + } + + /// Acquire an unused port and lock it (meaning no other competing callers of this method can + /// take this lock). Lock lasts until the returned `LockedPort` instance is dropped. + pub async fn acquire_unused() -> anyhow::Result { + loop { + let port = Self::pick_unused_port().await?; + let lockpath = std::env::temp_dir().join(format!("era-test-node-port{}.lock", port)); + let lockfile = File::create(lockpath) + .with_context(|| format!("failed to create lockfile for port={}", port))?; + if lockfile.try_lock_exclusive().is_ok() { + break Ok(Self { port, lockfile }); + } + } + } + + /// Acquire the requested port and lock it (meaning no other competing callers of this method + /// can take this lock). Lock lasts until the returned `LockedPort` instance is dropped. + pub async fn acquire(port: u16) -> anyhow::Result { + let port = Self::check_port_is_unused(port).await?; + let lockpath = std::env::temp_dir().join(format!("era-test-node-port{}.lock", port)); + let lockfile = File::create(lockpath) + .with_context(|| format!("failed to create lockfile for port={}", port))?; + lockfile + .try_lock_exclusive() + .with_context(|| format!("failed to lock the lockfile for port={}", port))?; + Ok(Self { port, lockfile }) + } +} + +/// Dropping `LockedPort` unlocks the port, caller needs to make sure the port is already bound to +/// or is not needed anymore. +impl Drop for LockedPort { + fn drop(&mut self) { + self.lockfile + .unlock() + .with_context(|| format!("failed to unlock lockfile for port={}", self.port)) + .unwrap(); + } +} diff --git a/e2e-tests-rust/tests/lib.rs b/e2e-tests-rust/tests/lib.rs new file mode 100644 index 00000000..a6e77973 --- /dev/null +++ b/e2e-tests-rust/tests/lib.rs @@ -0,0 +1,97 @@ +use alloy::network::{ReceiptResponse, TransactionBuilder}; +use alloy::primitives::{address, Address, U256}; +use alloy::providers::{PendingTransaction, PendingTransactionError, Provider, WalletProvider}; +use alloy::transports::http::{reqwest, Http}; +use alloy_zksync::network::transaction_request::TransactionRequest; +use alloy_zksync::network::Zksync; +use alloy_zksync::provider::{zksync_provider, ProviderBuilderExt}; +use era_test_node_e2e_tests::utils::LockedPort; + +fn init( + block_time: u64, + port: u16, +) -> impl Provider, Zksync> + WalletProvider + Clone { + zksync_provider() + .with_recommended_fillers() + .on_era_test_node_with_wallet_and_config(|node| { + node.path( + std::env::var("ERA_TEST_NODE_BINARY_PATH") + .unwrap_or("../target/release/era_test_node".to_string()), + ) + .port(port) + .block_time(block_time) + }) +} + +#[tokio::test] +async fn interval_sealing_finalization() -> anyhow::Result<()> { + // Test that we can submit a transaction and wait for it to finalize when era-test-node is + // operating in interval sealing mode. + let locked_port = LockedPort::acquire_unused().await?; + let provider = init(1, locked_port.port); + + let tx = TransactionRequest::default() + .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) + .with_value(U256::from(100)); + let receipt = provider.send_transaction(tx).await?.get_receipt().await?; + assert!(receipt.status()); + + Ok(()) +} + +#[tokio::test] +async fn interval_sealing_multiple_txs() -> anyhow::Result<()> { + // Test that we can submit two transactions and wait for them to finalize in the same block when + // era-test-node is operating in interval sealing mode. 3 seconds should be long enough for + // the entire flow to execute before the first block is produced. + let locked_port = LockedPort::acquire_unused().await?; + let provider = init(3, locked_port.port); + const RICH_WALLET0: Address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + const RICH_WALLET1: Address = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); + const TARGET: Address = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); + + async fn submit_tx( + provider: impl Provider, Zksync> + WalletProvider + Clone, + rich_wallet: Address, + ) -> Result { + let tx = TransactionRequest::default() + .with_from(rich_wallet) + .with_to(TARGET) + .with_value(U256::from(100)); + provider.send_transaction(tx).await?.register().await + } + + // Submit two txs at the same time + let handle0 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET0)); + let handle1 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET1)); + + // Wait until both are finalized + let (pending_tx0, pending_tx1) = tokio::join!(handle0, handle1); + let pending_tx0 = pending_tx0??; + let pending_tx1 = pending_tx1??; + + // Fetch their receipts + let receipt0 = provider + .get_transaction_receipt(pending_tx0.await?) + .await? + .unwrap(); + assert!(receipt0.status()); + let receipt1 = provider + .get_transaction_receipt(pending_tx1.await?) + .await? + .unwrap(); + assert!(receipt1.status()); + + // Assert that they are different txs but executed in the same block + assert_eq!(receipt0.from, RICH_WALLET0); + assert_eq!(receipt1.from, RICH_WALLET1); + assert_ne!(receipt0.transaction_hash, receipt1.transaction_hash); + + // But executed in the same block + assert!(receipt0.block_number.is_some()); + assert_eq!(receipt0.block_number, receipt1.block_number); + assert!(receipt0.block_hash.is_some()); + assert_eq!(receipt0.block_hash, receipt1.block_hash); + + Ok(()) +} diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index 1ff04d56..7a723495 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -922,13 +922,7 @@ impl InMemoryNode { pool: TxPool, ) -> Self { let system_contracts_options = config.system_contracts_options; - let inner = InMemoryNodeInner::new( - fork, - - config, - time.clone(), - impersonation.clone(), - ); + let inner = InMemoryNodeInner::new(fork, config, time.clone(), impersonation.clone()); InMemoryNode { inner: Arc::new(RwLock::new(inner)), snapshots: Default::default(), @@ -987,7 +981,6 @@ impl InMemoryNode { let config = self.get_config()?; let inner = InMemoryNodeInner::new( fork, - &config, TimestampManager::default(), ImpersonationManager::default(), From 4842a530084a84699036d93fdbff8315327d9143 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Wed, 27 Nov 2024 15:54:58 +1100 Subject: [PATCH 9/9] fix compile errors --- e2e-tests-rust/tests/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/e2e-tests-rust/tests/lib.rs b/e2e-tests-rust/tests/lib.rs index a6e77973..81f1d2f2 100644 --- a/e2e-tests-rust/tests/lib.rs +++ b/e2e-tests-rust/tests/lib.rs @@ -83,15 +83,15 @@ async fn interval_sealing_multiple_txs() -> anyhow::Result<()> { assert!(receipt1.status()); // Assert that they are different txs but executed in the same block - assert_eq!(receipt0.from, RICH_WALLET0); - assert_eq!(receipt1.from, RICH_WALLET1); - assert_ne!(receipt0.transaction_hash, receipt1.transaction_hash); + assert_eq!(receipt0.from(), RICH_WALLET0); + assert_eq!(receipt1.from(), RICH_WALLET1); + assert_ne!(receipt0.transaction_hash(), receipt1.transaction_hash()); // But executed in the same block - assert!(receipt0.block_number.is_some()); - assert_eq!(receipt0.block_number, receipt1.block_number); - assert!(receipt0.block_hash.is_some()); - assert_eq!(receipt0.block_hash, receipt1.block_hash); + assert!(receipt0.block_number().is_some()); + assert_eq!(receipt0.block_number(), receipt1.block_number()); + assert!(receipt0.block_hash().is_some()); + assert_eq!(receipt0.block_hash(), receipt1.block_hash()); Ok(()) }