Skip to content

Commit

Permalink
Add consensus L2 contracts VM storage reader
Browse files Browse the repository at this point in the history
  • Loading branch information
moshababo committed Jul 10, 2024
1 parent c6c3f96 commit e9b7c36
Show file tree
Hide file tree
Showing 14 changed files with 588 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "contracts"]
path = contracts
url = https://github.com/matter-labs/era-contracts.git
url = https://github.com/matter-labs/era-contracts
branch = consensus_contracts
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion core/node/api_server/src/execution_sandbox/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) struct TransactionExecutionOutput {

/// Executor of transactions.
#[derive(Debug)]
pub(crate) enum TransactionExecutor {
pub enum TransactionExecutor {
Real,
#[doc(hidden)] // Intended for tests only
Mock(MockTransactionExecutor),
Expand Down
9 changes: 5 additions & 4 deletions core/node/api_server/src/execution_sandbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ use zksync_types::{
api, fee_model::BatchFeeInput, AccountTreeId, Address, L1BatchNumber, L2BlockNumber, L2ChainId,
};

pub use self::execute::TransactionExecutor;
use self::vm_metrics::SandboxStage;
pub(super) use self::{
error::SandboxExecutionError,
execute::{TransactionExecutor, TxExecutionArgs},
execute::TxExecutionArgs,
tracers::ApiTracer,
validate::ValidationError,
vm_metrics::{SubmitTxStage, SANDBOX_METRICS},
Expand Down Expand Up @@ -214,7 +215,7 @@ impl BlockStartInfoInner {

/// Information about first L1 batch / L2 block in the node storage.
#[derive(Debug, Clone)]
pub(crate) struct BlockStartInfo {
pub struct BlockStartInfo {
cached_pruning_info: Arc<RwLock<BlockStartInfoInner>>,
max_cache_age: Duration,
}
Expand Down Expand Up @@ -330,7 +331,7 @@ impl BlockStartInfo {
}

#[derive(Debug, thiserror::Error)]
pub(crate) enum BlockArgsError {
pub enum BlockArgsError {
#[error("Block is pruned; first retained block is {0}")]
Pruned(L2BlockNumber),
#[error("Block is missing, but can appear in the future")]
Expand All @@ -341,7 +342,7 @@ pub(crate) enum BlockArgsError {

/// Information about a block provided to VM.
#[derive(Debug, Clone, Copy)]
pub(crate) struct BlockArgs {
pub struct BlockArgs {
block_id: api::BlockId,
resolved_block_number: L2BlockNumber,
l1_batch_timestamp_s: Option<u64>,
Expand Down
2 changes: 1 addition & 1 deletion core/node/api_server/src/tx_sender/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ impl TxSender {
.await
}

pub(super) async fn eth_call(
pub async fn eth_call(
&self,
block_args: BlockArgs,
call_overrides: CallOverrides,
Expand Down
2 changes: 1 addition & 1 deletion core/node/api_server/src/web3/testonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
const TEST_TIMEOUT: Duration = Duration::from_secs(90);
const POLL_INTERVAL: Duration = Duration::from_millis(50);

pub(crate) async fn create_test_tx_sender(
pub async fn create_test_tx_sender(
pool: ConnectionPool<Core>,
l2_chain_id: L2ChainId,
tx_executor: TransactionExecutor,
Expand Down
4 changes: 3 additions & 1 deletion core/node/consensus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ zksync_system_constants.workspace = true
zksync_types.workspace = true
zksync_utils.workspace = true
zksync_web3_decl.workspace = true

zksync_node_api_server.workspace = true
anyhow.workspace = true
async-trait.workspace = true
secrecy.workspace = true
tempfile.workspace = true
thiserror.workspace = true
tracing.workspace = true
zksync_contracts.workspace = true
hex.workspace = true

[dev-dependencies]
zksync_node_genesis.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions core/node/consensus/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub(crate) use store::*;

#[cfg(test)]
pub(crate) mod testonly;
#[cfg(test)]
mod tests;
mod vm_reader;

#[derive(thiserror::Error, Debug)]
pub enum InsertCertificateError {
Expand Down
121 changes: 117 additions & 4 deletions core/node/consensus/src/storage/testonly.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
//! Storage test helpers.
use anyhow::Context as _;
use zksync_concurrency::{ctx, error::Wrap as _, time};
use zksync_concurrency::{ctx, ctx::Ctx, error::Wrap as _, time};
use zksync_consensus_roles::validator;
use zksync_contracts::BaseSystemContracts;
use zksync_contracts::{load_contract, read_bytecode, BaseSystemContracts};
use zksync_dal::CoreDal as _;
use zksync_node_genesis::{insert_genesis_batch, mock_genesis_config, GenesisParams};
use zksync_node_test_utils::{recover, snapshot, Snapshot};
use zksync_state_keeper::testonly::fee;
use zksync_test_account::{Account, TxType};
use zksync_types::{
commitment::L1BatchWithMetadata, protocol_version::ProtocolSemanticVersion,
system_contracts::get_system_smart_contracts, L1BatchNumber, L2BlockNumber, ProtocolVersionId,
commitment::L1BatchWithMetadata,
ethabi::{Address, Contract, Token},
protocol_version::ProtocolSemanticVersion,
system_contracts::get_system_smart_contracts,
Execute, L1BatchNumber, L2BlockNumber, L2ChainId, Nonce, ProtocolVersionId, Transaction, U256,
};

use super::ConnectionPool;
use crate::testonly::StateKeeper;

pub(crate) fn mock_genesis_params(protocol_version: ProtocolVersionId) -> GenesisParams {
let mut cfg = mock_genesis_config();
Expand Down Expand Up @@ -189,3 +195,110 @@ impl ConnectionPool {
Ok(())
}
}

pub struct VMWriter {
pool: ConnectionPool,
node: StateKeeper,
account: Account,
}

impl VMWriter {
pub fn new(pool: ConnectionPool, node: StateKeeper, account: Account) -> Self {
Self {
pool,
node,
account,
}
}

pub async fn deploy_and_add_nodes(
&mut self,
ctx: &Ctx,
owner: Address,
nodes: &[&[Token]],
) -> Address {
let consensus_authority_bytecode = read_bytecode("contracts/l2-contracts/artifacts-zk/contracts/ConsensusAuthority.sol/ConsensusAuthority.json");
let consensus_authority_contract = load_contract("contracts/l2-contracts/artifacts-zk/contracts/ConsensusAuthority.sol/ConsensusAuthority.json");
let validator_registry_bytecode = read_bytecode("contracts/l2-contracts/artifacts-zk/contracts/ValidatorRegistry.sol/ValidatorRegistry.json");
let attester_registry_bytecode = read_bytecode("contracts/l2-contracts/artifacts-zk/contracts/AttesterRegistry.sol/AttesterRegistry.json");

let mut txs: Vec<Transaction> = vec![];
let deploy_tx = self.account.get_deploy_tx_with_factory_deps(
&consensus_authority_bytecode,
Some(&[Token::Address(owner)]),
vec![validator_registry_bytecode, attester_registry_bytecode],
TxType::L2,
);
txs.push(deploy_tx.tx);
for node in nodes {
let tx = self.gen_tx_add(&consensus_authority_contract, deploy_tx.address, node);
txs.push(tx);
}
txs.push(
self.gen_tx_set_validator_committee(deploy_tx.address, &consensus_authority_contract),
);
txs.push(
self.gen_tx_set_attester_committee(deploy_tx.address, &consensus_authority_contract),
);

self.node.push_block(&txs).await;
self.pool
.wait_for_payload(ctx, self.node.last_block())
.await
.unwrap();

deploy_tx.address
}

fn gen_tx_add(
&mut self,
contract: &Contract,
contract_address: Address,
input: &[Token],
) -> Transaction {
let calldata = contract
.function("add")
.unwrap()
.encode_input(input)
.unwrap();
self.gen_tx(contract_address, calldata)
}

fn gen_tx_set_validator_committee(
&mut self,
contract_address: Address,
contract: &Contract,
) -> Transaction {
let calldata = contract
.function("setValidatorCommittee")
.unwrap()
.short_signature()
.to_vec();
self.gen_tx(contract_address, calldata)
}

fn gen_tx_set_attester_committee(
&mut self,
contract_address: Address,
contract: &Contract,
) -> Transaction {
let calldata = contract
.function("setAttesterCommittee")
.unwrap()
.short_signature()
.to_vec();
self.gen_tx(contract_address, calldata)
}

fn gen_tx(&mut self, contract_address: Address, calldata: Vec<u8>) -> Transaction {
self.account.get_l2_tx_for_execute(
Execute {
contract_address,
calldata,
value: Default::default(),
factory_deps: vec![],
},
Some(fee(1_000_000)),
)
}
}
98 changes: 98 additions & 0 deletions core/node/consensus/src/storage/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use rand::Rng;
use zksync_concurrency::{ctx, scope};
use zksync_types::{
api::{BlockId, BlockNumber},
ethabi::{Address, Token},
L2ChainId, ProtocolVersionId, U256,
};

use crate::storage::ConnectionPool;

#[tokio::test(flavor = "multi_thread")]
async fn test_vm_reader() {
zksync_concurrency::testonly::abort_on_panic();
let ctx = &ctx::test_root(&ctx::RealClock);
let rng = &mut ctx.rng();

scope::run!(ctx, |ctx, s| async {
let pool = ConnectionPool::test(false, ProtocolVersionId::latest()).await;
let (node, runner) = crate::testonly::StateKeeper::new(ctx, pool.clone()).await?;
let account = runner.account.clone();
s.spawn_bg(runner.run_real(ctx));

let mut writer = super::testonly::VMWriter::new(pool.clone(), node, account.clone());

let mut nodes: Vec<Vec<Token>> = Vec::new();
let num_nodes = 5;
for _ in 0..num_nodes {
let item = vec![
Token::Address(Address::random()),
Token::Uint(U256::from(rng.gen::<usize>())),
Token::Bytes((0..256).map(|_| rng.gen()).collect()),
Token::Bytes((0..256).map(|_| rng.gen()).collect()),
Token::Uint(U256::from(rng.gen::<usize>())),
Token::Bytes((0..256).map(|_| rng.gen()).collect()),
];
nodes.push(item);
}
let nodes_ref: Vec<&[Token]> = nodes.iter().map(|v| v.as_slice()).collect();
let nodes_slice: &[&[Token]] = nodes_ref.as_slice();
let consensus_authority_address = writer
.deploy_and_add_nodes(ctx, account.address, nodes_slice)
.await;

let (tx_sender, _) = zksync_node_api_server::web3::testonly::create_test_tx_sender(
pool.0.clone(),
L2ChainId::default(),
zksync_node_api_server::execution_sandbox::TransactionExecutor::Real,
)
.await;
let block_id = BlockId::Number(BlockNumber::Pending);
let mut reader = super::vm_reader::VMReader::new(
ctx,
block_id,
pool.clone(),
tx_sender.clone(),
consensus_authority_address,
)
.await;

let validators = reader.read_validator_committee(ctx, block_id).await;
assert_eq!(validators.len(), num_nodes);
let attesters = reader.read_attester_committee(ctx, block_id).await;
assert_eq!(attesters.len(), num_nodes);

for i in 0..nodes.len() {
assert_eq!(
nodes[i][0].clone().into_address().unwrap(),
validators[i].node_owner
);
assert_eq!(
nodes[i][1].clone().into_uint().unwrap().as_usize(),
validators[i].weight
);
assert_eq!(
nodes[i][2].clone().into_bytes().unwrap(),
validators[i].pub_key
);
assert_eq!(nodes[i][3].clone().into_bytes().unwrap(), validators[i].pop);

assert_eq!(
nodes[i][0].clone().into_address().unwrap(),
attesters[i].node_owner
);
assert_eq!(
nodes[i][4].clone().into_uint().unwrap().as_usize(),
attesters[i].weight
);
assert_eq!(
nodes[i][5].clone().into_bytes().unwrap(),
attesters[i].pub_key
);
}

Ok(())
})
.await
.unwrap();
}
Loading

0 comments on commit e9b7c36

Please sign in to comment.