Skip to content

Commit

Permalink
refactor: queue-based block production + better separation of node's …
Browse files Browse the repository at this point in the history
…mutable state (#517)

* make block producer an actor

* refactor inner node state into a separate module

* fix unit tests

* fix block sealer tests

* rename block producer to node executor

* refactor `time`: remove traits, rename structs

* relax trait bounds for `ArcRLock`'s clone

* clippy

* add todo for making `net` namespace async upstream

* rustc 1.84 clippy

* migrate `override_bytecodes` to `tokio::fs`

* make `Command` private

* get rid of low-level `Future` implementations

* fix lint errors

* rework `BlockchainReader` into a trait `ReadBlockchain`

* rework `TimeReader` into a trait `ReadTime`

* clippy

* make `ReadBlockchain` and `ReadTime` cloneable + docs

---------

Co-authored-by: Dustin Brickwood <dustinbrickwood204@gmail.com>
  • Loading branch information
itegulov and dutterbutter authored Jan 14, 2025
1 parent e4e9927 commit 56dff28
Show file tree
Hide file tree
Showing 44 changed files with 5,218 additions and 4,421 deletions.
32 changes: 29 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ zksync_web3_decl = { git = "https://github.com/matter-labs/zksync-era.git", rev
anyhow = "1.0"
alloy-signer-local = { version = "0.5.4", features = ["mnemonic"] }
alloy-signer = { version = "0.5.4", default-features = false }
async-trait = "0.1.85"
chrono = { version = "0.4.31", default-features = false }
clap = { version = "4.2.4", features = ["derive", "env"] }
colored = "2"
Expand Down Expand Up @@ -82,6 +83,7 @@ maplit = "1.0.2"
zksync-web3-rs = "0.1.1"
ethers = { version = "2.0.4", features = ["rustls"] }
test-case = "3.3.1"
backon = "1.3.0"

#########################
# Local dependencies #
Expand Down
60 changes: 30 additions & 30 deletions crates/api_decl/src/namespaces/anvil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub trait AnvilNamespace {
/// # Returns
/// Buffer representing the chain state.
#[method(name = "dumpState", aliases = ["hardhat_dumpState"])]
fn dump_state(&self, preserve_historical_states: Option<bool>) -> RpcResult<Bytes>;
async fn dump_state(&self, preserve_historical_states: Option<bool>) -> RpcResult<Bytes>;

/// Append chain state buffer to current chain. Will overwrite any conflicting addresses or
/// storage.
Expand All @@ -30,30 +30,30 @@ pub trait AnvilNamespace {
/// # Returns
/// `true` if a snapshot was reverted, otherwise `false`.
#[method(name = "loadState", aliases = ["hardhat_loadState"])]
fn load_state(&self, bytes: Bytes) -> RpcResult<bool>;
async fn load_state(&self, bytes: Bytes) -> RpcResult<bool>;

/// Mines a single block in the same way as `evm_mine` but returns extra fields.
///
/// # Returns
/// Freshly mined block's representation along with extra fields.
#[method(name = "mine_detailed", aliases = ["evm_mine_detailed"])]
fn mine_detailed(&self) -> RpcResult<Block<DetailedTransaction>>;
async fn mine_detailed(&self) -> RpcResult<Block<DetailedTransaction>>;

/// Sets the fork RPC url. Assumes the underlying chain is the same as before.
///
/// # Arguments
///
/// * `url` - Fork's new URL
#[method(name = "setRpcUrl")]
fn set_rpc_url(&self, url: String) -> RpcResult<()>;
async fn set_rpc_url(&self, url: String) -> RpcResult<()>;

/// Sets the base fee of the next block.
///
/// # Arguments
///
/// * `base_fee` - Value to be set as base fee for the next block
#[method(name = "setNextBlockBaseFeePerGas", aliases = ["hardhat_setNextBlockBaseFeePerGas"])]
fn set_next_block_base_fee_per_gas(&self, base_fee: U256) -> RpcResult<()>;
async fn set_next_block_base_fee_per_gas(&self, base_fee: U256) -> RpcResult<()>;

/// Removes a transaction from the pool.
///
Expand All @@ -64,26 +64,26 @@ pub trait AnvilNamespace {
/// # Returns
/// `Some(hash)` if transaction was in the pool before being removed, `None` otherwise
#[method(name = "dropTransaction", aliases = ["hardhat_dropTransaction"])]
fn drop_transaction(&self, hash: H256) -> RpcResult<Option<H256>>;
async fn drop_transaction(&self, hash: H256) -> RpcResult<Option<H256>>;

/// Remove all transactions from the pool.
#[method(name = "dropAllTransactions", aliases = ["hardhat_dropAllTransactions"])]
fn drop_all_transactions(&self) -> RpcResult<()>;
async fn drop_all_transactions(&self) -> RpcResult<()>;

/// Remove all transactions from the pool by sender address.
///
/// # Arguments
///
/// * `address` - Sender which transactions should be removed from the pool
#[method(name = "removePoolTransactions")]
fn remove_pool_transactions(&self, address: Address) -> RpcResult<()>;
async fn remove_pool_transactions(&self, address: Address) -> RpcResult<()>;

/// Gets node's auto mining status.
///
/// # Returns
/// `true` if auto mining is enabled, `false` otherwise
#[method(name = "getAutomine", aliases = ["hardhat_getAutomine"])]
fn get_auto_mine(&self) -> RpcResult<bool>;
async fn get_auto_mine(&self) -> RpcResult<bool>;

/// Enables or disables, based on the single boolean argument, the automatic mining of new
/// blocks with each new transaction submitted to the network.
Expand All @@ -92,15 +92,15 @@ pub trait AnvilNamespace {
///
/// * `enable` - if `true` automatic mining will be enabled, disabled otherwise
#[method(name = "setAutomine", aliases = ["evm_setAutomine"])]
fn set_auto_mine(&self, enable: bool) -> RpcResult<()>;
async fn set_auto_mine(&self, enable: bool) -> RpcResult<()>;

/// Sets the mining behavior to interval with the given interval (seconds).
///
/// # Arguments
///
/// * `seconds` - Frequency of automatic block production (in seconds)
#[method(name = "setIntervalMining", aliases = ["evm_setIntervalMining"])]
fn set_interval_mining(&self, seconds: u64) -> RpcResult<()>;
async fn set_interval_mining(&self, seconds: u64) -> RpcResult<()>;

/// Sets the block timestamp interval. All future blocks' timestamps will
/// have the provided amount of seconds in-between of them. Does not affect
Expand All @@ -110,14 +110,14 @@ pub trait AnvilNamespace {
///
/// * `seconds` - The interval between two consecutive blocks (in seconds)
#[method(name = "setBlockTimestampInterval")]
fn set_block_timestamp_interval(&self, seconds: u64) -> RpcResult<()>;
async fn set_block_timestamp_interval(&self, seconds: u64) -> RpcResult<()>;

/// Removes the block timestamp interval if it exists.
///
/// # Returns
/// `true` if an existing interval was removed, `false` otherwise
#[method(name = "removeBlockTimestampInterval")]
fn remove_block_timestamp_interval(&self) -> RpcResult<bool>;
async fn remove_block_timestamp_interval(&self) -> RpcResult<bool>;

/// Set the minimum gas price for the node. Unsupported for ZKsync as it is only relevant for
/// pre-EIP1559 chains.
Expand All @@ -126,15 +126,15 @@ pub trait AnvilNamespace {
///
/// * `gas` - The minimum gas price to be set
#[method(name = "setMinGasPrice", aliases = ["hardhat_setMinGasPrice"])]
fn set_min_gas_price(&self, gas: U256) -> RpcResult<()>;
async fn set_min_gas_price(&self, gas: U256) -> RpcResult<()>;

/// Enable or disable logging.
///
/// # Arguments
///
/// * `enable` - if `true` logging will be enabled, disabled otherwise
#[method(name = "setLoggingEnabled", aliases = ["hardhat_setLoggingEnabled"])]
fn set_logging_enabled(&self, enable: bool) -> RpcResult<()>;
async fn set_logging_enabled(&self, enable: bool) -> RpcResult<()>;

/// Snapshot the state of the blockchain at the current block. Takes no parameters. Returns the id of the snapshot
/// that was created. A snapshot can only be reverted once. After a successful `anvil_revert`, the same snapshot id cannot
Expand All @@ -144,7 +144,7 @@ pub trait AnvilNamespace {
/// # Returns
/// The `U64` identifier for this snapshot.
#[method(name = "snapshot", aliases = ["evm_snapshot"])]
fn snapshot(&self) -> RpcResult<U64>;
async fn snapshot(&self) -> RpcResult<U64>;

/// Revert the state of the blockchain to a previous snapshot. Takes a single parameter,
/// which is the snapshot id to revert to. This deletes the given snapshot, as well as any snapshots
Expand All @@ -157,7 +157,7 @@ pub trait AnvilNamespace {
/// # Returns
/// `true` if a snapshot was reverted, otherwise `false`.
#[method(name = "revert", aliases = ["evm_revert"])]
fn revert(&self, id: U64) -> RpcResult<bool>;
async fn revert(&self, id: U64) -> RpcResult<bool>;

/// Set the current timestamp for the node.
/// Warning: This will allow you to move backwards in time, which may cause new blocks to appear to be
Expand All @@ -170,7 +170,7 @@ pub trait AnvilNamespace {
/// # Returns
/// The difference between the current timestamp and the new timestamp.
#[method(name = "setTime", aliases = ["evm_setTime"])]
fn set_time(&self, timestamp: Numeric) -> RpcResult<i128>;
async fn set_time(&self, timestamp: Numeric) -> RpcResult<i128>;

/// Increase the current timestamp for the node
///
Expand All @@ -181,15 +181,15 @@ pub trait AnvilNamespace {
/// # Returns
/// The applied time delta to the current timestamp in seconds.
#[method(name = "increaseTime", aliases = ["evm_increaseTime"])]
fn increase_time(&self, seconds: Numeric) -> RpcResult<u64>;
async fn increase_time(&self, seconds: Numeric) -> RpcResult<u64>;

/// Set timestamp for the next block. The timestamp must be in future.
///
/// # Arguments
///
/// * `timestamp` - The timestamp to set the time to
#[method(name = "setNextBlockTimestamp", aliases = ["evm_setNextBlockTimestamp"])]
fn set_next_block_timestamp(&self, timestamp: Numeric) -> RpcResult<()>;
async fn set_next_block_timestamp(&self, timestamp: Numeric) -> RpcResult<()>;

/// Sets auto impersonation status.
///
Expand All @@ -201,7 +201,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` representing the success of the operation.
#[method(name = "autoImpersonateAccount", aliases = ["hardhat_autoImpersonateAccount"])]
fn auto_impersonate_account(&self, enabled: bool) -> RpcResult<()>;
async fn auto_impersonate_account(&self, enabled: bool) -> RpcResult<()>;

/// Sets the balance of the given address to the given balance.
///
Expand All @@ -214,7 +214,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "setBalance", aliases = ["hardhat_setBalance"])]
fn set_balance(&self, address: Address, balance: U256) -> RpcResult<bool>;
async fn set_balance(&self, address: Address, balance: U256) -> RpcResult<bool>;

/// Modifies an account's nonce by overwriting it.
///
Expand All @@ -227,7 +227,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "setNonce", aliases = ["hardhat_setNonce", "evm_setAccountNonce"])]
fn set_nonce(&self, address: Address, nonce: U256) -> RpcResult<bool>;
async fn set_nonce(&self, address: Address, nonce: U256) -> RpcResult<bool>;

/// Sometimes you may want to advance the latest block number of the network by a large number of blocks.
/// One way to do this would be to call the evm_mine RPC method multiple times, but this is too slow if you want to mine thousands of blocks.
Expand All @@ -242,7 +242,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "mine", aliases = ["hardhat_mine"])]
fn anvil_mine(&self, num_blocks: Option<U64>, interval: Option<U64>) -> RpcResult<()>;
async fn anvil_mine(&self, num_blocks: Option<U64>, interval: Option<U64>) -> RpcResult<()>;

/// Reset the state of the network back to a fresh forked state, or disable forking.
///
Expand All @@ -254,7 +254,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "reset", aliases = ["hardhat_reset"])]
fn reset_network(&self, reset_spec: Option<ResetRequest>) -> RpcResult<bool>;
async fn reset_network(&self, reset_spec: Option<ResetRequest>) -> RpcResult<bool>;

/// anvil-zksync allows transactions impersonating specific account and contract addresses.
/// To impersonate an account use this method, passing the address to impersonate as its parameter.
Expand All @@ -269,7 +269,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "impersonateAccount", aliases = ["hardhat_impersonateAccount"])]
fn impersonate_account(&self, address: Address) -> RpcResult<()>;
async fn impersonate_account(&self, address: Address) -> RpcResult<()>;

/// Use this method to stop impersonating an account after having previously used `anvil_impersonateAccount`
/// The method returns `true` if the account was being impersonated and `false` otherwise.
Expand All @@ -282,7 +282,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "stopImpersonatingAccount", aliases = ["hardhat_stopImpersonatingAccount"])]
fn stop_impersonating_account(&self, address: Address) -> RpcResult<()>;
async fn stop_impersonating_account(&self, address: Address) -> RpcResult<()>;

/// Modifies the bytecode stored at an account's address.
///
Expand All @@ -295,7 +295,7 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "setCode", aliases = ["hardhat_setCode"])]
fn set_code(&self, address: Address, code: String) -> RpcResult<()>;
async fn set_code(&self, address: Address, code: String) -> RpcResult<()>;

/// Directly modifies the storage of a contract at a specified slot.
///
Expand All @@ -309,13 +309,13 @@ pub trait AnvilNamespace {
///
/// A `BoxFuture` containing a `Result` with a `bool` representing the success of the operation.
#[method(name = "setStorageAt", aliases = ["hardhat_setStorageAt"])]
fn set_storage_at(&self, address: Address, slot: U256, value: U256) -> RpcResult<bool>;
async fn set_storage_at(&self, address: Address, slot: U256, value: U256) -> RpcResult<bool>;

/// Sets the chain id.
///
/// # Arguments
///
/// * `id` - The chain id to be set.
#[method(name = "setChainId")]
fn set_chain_id(&self, id: u32) -> RpcResult<()>;
async fn set_chain_id(&self, id: u32) -> RpcResult<()>;
}
Loading

0 comments on commit 56dff28

Please sign in to comment.