Skip to content

Commit

Permalink
feat: impl evm_mine
Browse files Browse the repository at this point in the history
  • Loading branch information
grw-ms committed Sep 14, 2023
1 parent de35b8f commit 434d220
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 2 deletions.
120 changes: 120 additions & 0 deletions src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@ use std::sync::{Arc, RwLock};
use crate::{fork::ForkSource, node::InMemoryNodeInner};
use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_derive::rpc;
use vm::{
utils::BLOCK_GAS_LIMIT,
vm_with_bootloader::{init_vm_inner, BlockContextMode, BootloaderJobType, TxExecutionMode},
HistoryEnabled, OracleTools,
};
use zksync_basic_types::H256;
use zksync_core::api_server::web3::backend_jsonrpc::error::into_jsrpc_error;
use zksync_state::StorageView;
use zksync_state::WriteStorage;
use zksync_types::api::Block;
use zksync_utils::u256_to_h256;
use zksync_web3_decl::error::Web3Error;

/// Implementation of EvmNamespace
Expand All @@ -30,6 +40,15 @@ pub trait EvmNamespaceT {
#[rpc(name = "evm_increaseTime")]
fn increase_time(&self, time_delta_seconds: u64) -> BoxFuture<Result<u64>>;

/// Force a single block to be mined.
///
/// Will mine an empty block (containing zero transactions)
///
/// # Returns
/// The string "0x0".
#[rpc(name = "evm_mine")]
fn evm_mine(&self) -> BoxFuture<Result<String>>;

/// Set the current timestamp for the node. The timestamp must be in future.
///
/// # Parameters
Expand Down Expand Up @@ -109,11 +128,90 @@ impl<S: Send + Sync + 'static + ForkSource + std::fmt::Debug> EvmNamespaceT
}
})
}

fn evm_mine(&self) -> BoxFuture<Result<String>> {
let inner = Arc::clone(&self.node);
Box::pin(async move {
match inner.write() {
Ok(mut inner) => {
let (keys, block, bytecodes) = {
let mut storage_view = StorageView::new(&inner.fork_storage);
let mut oracle_tools = OracleTools::new(&mut storage_view, HistoryEnabled);

let bootloader_code = &inner.system_contracts.baseline_contracts;
let block_context = inner.create_block_context();
let block_properties =
InMemoryNodeInner::<S>::create_block_properties(bootloader_code);

let block = Block {
hash: H256::random(),
number: inner.current_miniblock.saturating_add(1).into(),
timestamp: block_context.block_timestamp.into(),
l1_batch_number: Some(block_context.block_number.into()),
..Default::default()
};

// init vm
let mut vm = init_vm_inner(
&mut oracle_tools,
BlockContextMode::NewBlock(block_context.into(), Default::default()),
&block_properties,
BLOCK_GAS_LIMIT,
bootloader_code,
TxExecutionMode::VerifyExecute,
);

vm.execute_till_block_end(BootloaderJobType::BlockPostprocessing);

let bytecodes = vm
.state
.decommittment_processor
.known_bytecodes
.inner()
.clone();

let modified_keys = storage_view.modified_storage_keys().clone();
(modified_keys, block, bytecodes)
};

for (key, value) in keys.iter() {
inner.fork_storage.set_value(*key, *value);
}

// Write all the factory deps.
for (hash, code) in bytecodes.iter() {
inner.fork_storage.store_factory_dep(
u256_to_h256(*hash),
code.iter()
.flat_map(|entry| {
let mut bytes = vec![0u8; 32];
entry.to_big_endian(&mut bytes);
bytes.to_vec()
})
.collect(),
)
}
println!("👷 Mined block #{}", block.number.as_u64());

// update node state
inner.block_hashes.insert(block.number.as_u64(), block.hash);
inner.blocks.insert(block.hash, block);
inner.current_timestamp += 1;
inner.current_batch += 1;
inner.current_miniblock += 1;

Ok("0x0".to_string())
}
Err(_) => Err(into_jsrpc_error(Web3Error::InternalError)),
}
})
}
}

#[cfg(test)]
mod tests {
use crate::{http_fork_source::HttpForkSource, node::InMemoryNode};
use zksync_core::api_server::web3::backend_jsonrpc::namespaces::eth::EthNamespaceT;

use super::*;

Expand Down Expand Up @@ -421,4 +519,26 @@ mod tests {
);
}
}

#[tokio::test]
async fn test_evm_mine() {
let node = InMemoryNode::<HttpForkSource>::default();
let evm = EvmNamespaceImpl::new(node.get_inner());

let start_block = node
.get_block_by_number(zksync_types::api::BlockNumber::Latest, true)
.await
.unwrap()
.expect("block exists");

let result = evm.evm_mine().await.expect("evm_mine");
assert_eq!(&result, "0x0");

let current_block = node
.get_block_by_number(zksync_types::api::BlockNumber::Latest, true)
.await
.unwrap()
.expect("block exists");
assert_eq!(start_block.number + 1, current_block.number);
}
}
4 changes: 2 additions & 2 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ type L2TxResult = (
);

impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
fn create_block_context(&self) -> BlockContext {
pub fn create_block_context(&self) -> BlockContext {
BlockContext {
block_number: self.current_batch,
block_timestamp: self.current_timestamp,
Expand All @@ -263,7 +263,7 @@ impl<S: std::fmt::Debug + ForkSource> InMemoryNodeInner<S> {
}
}

fn create_block_properties(contracts: &BaseSystemContracts) -> BlockProperties {
pub fn create_block_properties(contracts: &BaseSystemContracts) -> BlockProperties {
BlockProperties {
default_aa_code_hash: h256_to_u256(contracts.default_aa.hash),
zkporter_is_available: false,
Expand Down

0 comments on commit 434d220

Please sign in to comment.