Skip to content

Commit

Permalink
feat: adds init and timestamp genesis cli params (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
dutterbutter authored Nov 27, 2024
1 parent d3e51cc commit e5cd460
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 13 deletions.
16 changes: 13 additions & 3 deletions src/config/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use clap::{arg, command, Parser, Subcommand};
use rand::{rngs::StdRng, SeedableRng};
use zksync_types::{H256, U256};

use super::DEFAULT_DISK_CACHE_DIR;
use crate::config::constants::{DEFAULT_MNEMONIC, TEST_NODE_NETWORK_ID};
use crate::config::{
AccountGenerator, CacheConfig, CacheType, ShowCalls, ShowGasDetails, ShowStorageLogs,
AccountGenerator, CacheConfig, CacheType, Genesis, ShowCalls, ShowGasDetails, ShowStorageLogs,
ShowVMDetails, TestNodeConfig,
};
use crate::observability::LogLevel;
use crate::system_contracts::Options as SystemContractsOptions;

use super::DEFAULT_DISK_CACHE_DIR;
use crate::utils::parse_genesis_file;
use alloy_signer_local::coins_bip39::{English, Mnemonic};
use std::net::IpAddr;

Expand Down Expand Up @@ -171,6 +171,14 @@ pub struct Cli {
)]
pub balance: u64,

/// The timestamp of the genesis block.
#[arg(long, value_name = "NUM")]
pub timestamp: Option<u64>,

/// Initialize the genesis block with the given `genesis.json` file.
#[arg(long, value_name = "PATH", value_parser= parse_genesis_file)]
pub init: Option<Genesis>,

/// BIP39 mnemonic phrase used for generating accounts.
/// Cannot be used if `mnemonic_random` or `mnemonic_seed` are used.
#[arg(long, short, conflicts_with_all = &["mnemonic_seed", "mnemonic_random"], help_heading = "Account Configuration")]
Expand Down Expand Up @@ -338,6 +346,8 @@ impl Cli {
},
}
}))
.with_genesis_timestamp(self.timestamp)
.with_genesis(self.init)
.with_chain_id(self.chain_id)
.set_config_out(self.config_out)
.with_host(self.host)
Expand Down
2 changes: 2 additions & 0 deletions src/config/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub const DERIVATION_PATH: &str = "m/44'/60'/0'/0/0";
pub const DEFAULT_LOG_FILE_PATH: &str = "era_test_node.log";
/// Default mnemonic phrase for the test node
pub const DEFAULT_MNEMONIC: &str = "test test test test test test test test test test test junk";
/// Timestamp of the first block (if not running in fork mode).
pub const NON_FORK_FIRST_BLOCK_TIMESTAMP: u64 = 1_000;
/// Default account balance for the dev accounts
#[cfg(test)]
pub const DEFAULT_ACCOUNT_BALANCE: u128 = 1_000 * 10u128.pow(18);
Expand Down
56 changes: 55 additions & 1 deletion src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use crate::fork::ForkDetails;
use crate::{observability, system_contracts};
use anyhow::anyhow;
use std::net::{IpAddr, Ipv4Addr};
use zksync_multivm::interface::L1BatchEnv;
use zksync_types::api::TransactionVariant;

use crate::config::{
cache::{CacheConfig, CacheType},
Expand All @@ -23,7 +25,7 @@ use std::collections::HashMap;
use std::fs::File;
use std::time::Duration;
use zksync_types::fee_model::FeeModelConfigV2;
use zksync_types::U256;
use zksync_types::{Bloom, H256, U256};

pub mod cache;
pub mod cli;
Expand Down Expand Up @@ -101,6 +103,10 @@ pub struct TestNodeConfig {
pub account_generator: Option<AccountGenerator>,
/// Signer accounts that can sign messages/transactions
pub signer_accounts: Vec<PrivateKeySigner>,
/// The genesis to use to initialize the node
pub genesis: Option<Genesis>,
/// Genesis block timestamp
pub genesis_timestamp: Option<u64>,
/// Enable auto impersonation of accounts on startup
pub enable_auto_impersonate: bool,
/// Whether the node operates in offline mode
Expand Down Expand Up @@ -156,6 +162,8 @@ impl Default for TestNodeConfig {
enable_auto_impersonate: false,
// 100ETH default balance
genesis_balance: U256::from(100u128 * 10u128.pow(18)),
genesis_timestamp: Some(NON_FORK_FIRST_BLOCK_TIMESTAMP),
genesis: None,

// Offline mode disabled by default
offline: false,
Expand Down Expand Up @@ -298,6 +306,11 @@ impl TestNodeConfig {
);
println!("\n");

tracing::info!("Genesis Timestamp");
tracing::info!("========================");
tracing::info!("{}", self.get_genesis_timestamp().to_string().green());
println!("\n");

tracing::info!("Node Configuration");
tracing::info!("========================");
tracing::info!("Port: {}", self.port);
Expand Down Expand Up @@ -678,6 +691,26 @@ impl TestNodeConfig {
.with_genesis_accounts(accounts)
}

/// Sets the genesis timestamp
#[must_use]
pub fn with_genesis_timestamp(mut self, timestamp: Option<u64>) -> Self {
self.genesis_timestamp = timestamp;
self
}

/// Returns the genesis timestamp to use
pub fn get_genesis_timestamp(&self) -> u64 {
self.genesis_timestamp
.unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP)
}

/// Sets the init genesis (genesis.json)
#[must_use]
pub fn with_genesis(mut self, genesis: Option<Genesis>) -> Self {
self.genesis = genesis;
self
}

/// Sets whether to enable autoImpersonate
#[must_use]
pub fn with_auto_impersonate(mut self, enable_auto_impersonate: bool) -> Self {
Expand Down Expand Up @@ -834,3 +867,24 @@ impl AccountGenerator {
.collect()
}
}

/// Genesis
#[derive(Deserialize, Clone, Debug)]
pub struct Genesis {
/// The hash of the genesis block. If not provided, it can be computed.
pub hash: Option<H256>,
/// The parent hash of the genesis block. Usually zero.
pub parent_hash: Option<H256>,
/// The block number of the genesis block. Usually zero.
pub block_number: Option<u64>,
/// The timestamp of the genesis block.
pub timestamp: Option<u64>,
/// The L1 batch environment.
pub l1_batch_env: Option<L1BatchEnv>,
/// The transactions included in the genesis block.
pub transactions: Option<Vec<TransactionVariant>>,
/// The amount of gas used.
pub gas_used: Option<U256>,
/// The logs bloom filter.
pub logs_bloom: Option<Bloom>,
}
5 changes: 3 additions & 2 deletions src/node/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1453,11 +1453,12 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
#[cfg(test)]
mod tests {
use super::*;
use crate::node::NON_FORK_FIRST_BLOCK_TIMESTAMP;
use crate::{
config::{
cache::CacheConfig,
constants::{DEFAULT_ACCOUNT_BALANCE, DEFAULT_L2_GAS_PRICE},
constants::{
DEFAULT_ACCOUNT_BALANCE, DEFAULT_L2_GAS_PRICE, NON_FORK_FIRST_BLOCK_TIMESTAMP,
},
},
fork::ForkDetails,
http_fork_source::HttpForkSource,
Expand Down
56 changes: 49 additions & 7 deletions src/node/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ use crate::{
bootloader_debug::{BootloaderDebug, BootloaderDebugTracer},
config::{
cache::CacheConfig,
constants::{LEGACY_RICH_WALLETS, RICH_WALLETS},
constants::{LEGACY_RICH_WALLETS, NON_FORK_FIRST_BLOCK_TIMESTAMP, RICH_WALLETS},
show_details::{ShowCalls, ShowGasDetails, ShowStorageLogs, ShowVMDetails},
TestNodeConfig,
Genesis, TestNodeConfig,
},
console_log::ConsoleLogHandler,
deps::{storage_view::StorageView, InMemoryStorage},
Expand All @@ -73,8 +73,6 @@ use crate::{

/// Max possible size of an ABI encoded tx (in bytes).
pub const MAX_TX_SIZE: usize = 1_000_000;
/// Timestamp of the first block (if not running in fork mode).
pub const NON_FORK_FIRST_BLOCK_TIMESTAMP: u64 = 1_000;
/// Acceptable gas overestimation limit.
pub const ESTIMATE_GAS_ACCEPTABLE_OVERESTIMATION: u64 = 1_000;
/// The maximum number of previous blocks to store the state for.
Expand All @@ -91,8 +89,45 @@ pub fn compute_hash<'a>(block_number: u64, tx_hashes: impl IntoIterator<Item = &
H256(keccak256(&digest))
}

pub fn create_genesis<TX>(timestamp: u64) -> Block<TX> {
pub fn create_genesis_from_json(
genesis: &Genesis,
timestamp: Option<u64>,
) -> Block<TransactionVariant> {
let hash = genesis.hash.unwrap_or_else(|| compute_hash(0, []));
let timestamp = timestamp
.or(genesis.timestamp)
.unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP);

let l1_batch_env = genesis.l1_batch_env.clone().unwrap_or_else(|| L1BatchEnv {
previous_batch_hash: None,
number: L1BatchNumber(0),
timestamp,
fee_input: BatchFeeInput::pubdata_independent(0, 0, 0),
fee_account: Address::zero(),
enforced_base_fee: None,
first_l2_block: L2BlockEnv {
number: 0,
timestamp,
prev_block_hash: H256::zero(),
max_virtual_blocks_to_create: 0,
},
});

create_block(
&l1_batch_env,
hash,
genesis.parent_hash.unwrap_or_else(H256::zero),
genesis.block_number.unwrap_or(0),
timestamp,
genesis.transactions.clone().unwrap_or_default(),
genesis.gas_used.unwrap_or_else(U256::zero),
genesis.logs_bloom.unwrap_or_else(Bloom::zero),
)
}

pub fn create_genesis<TX>(timestamp: Option<u64>) -> Block<TX> {
let hash = compute_hash(0, []);
let timestamp = timestamp.unwrap_or(NON_FORK_FIRST_BLOCK_TIMESTAMP);
let batch_env = L1BatchEnv {
previous_batch_hash: None,
number: L1BatchNumber(0),
Expand Down Expand Up @@ -300,7 +335,14 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
let block_hash = compute_hash(0, []);
block_hashes.insert(0, block_hash);
let mut blocks = HashMap::<H256, Block<TransactionVariant>>::new();
blocks.insert(block_hash, create_genesis(NON_FORK_FIRST_BLOCK_TIMESTAMP));
let genesis_block: Block<TransactionVariant> = if let Some(ref genesis) = config.genesis
{
create_genesis_from_json(genesis, config.genesis_timestamp)
} else {
create_genesis(config.genesis_timestamp)
};

blocks.insert(block_hash, genesis_block);
let fee_input_provider = TestNodeFeeInputProvider::default();
time.set_last_timestamp_unchecked(NON_FORK_FIRST_BLOCK_TIMESTAMP);

Expand Down Expand Up @@ -2003,7 +2045,7 @@ mod tests {

#[tokio::test]
async fn test_create_genesis_creates_block_with_hash_and_zero_parent_hash() {
let first_block = create_genesis::<TransactionVariant>(1000);
let first_block = create_genesis::<TransactionVariant>(Some(1000));

assert_eq!(first_block.hash, compute_hash(0, []));
assert_eq!(first_block.parent_hash, H256::zero());
Expand Down
9 changes: 9 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::config::Genesis;
use anyhow::Context;
use chrono::{DateTime, Utc};
use futures::Future;
use jsonrpc_core::{Error, ErrorCode};
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fs;
use std::{convert::TryInto, fmt, pin::Pin};
use zksync_multivm::interface::{Call, CallType, ExecutionResult, VmExecutionResultAndLogs};
use zksync_types::{
Expand All @@ -28,6 +30,13 @@ where
{
}

/// Parses the genesis file from the given path.
pub fn parse_genesis_file(path: &str) -> Result<Genesis, String> {
let file_content =
fs::read_to_string(path).map_err(|err| format!("Failed to read file: {err}"))?;
serde_json::from_str(&file_content).map_err(|err| format!("Failed to parse JSON: {err}"))
}

/// Takes long integers and returns them in human friendly format with "_".
/// For example: 12_334_093
pub fn to_human_size(input: U256) -> String {
Expand Down

0 comments on commit e5cd460

Please sign in to comment.