Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Parallel transactions execution #246

Draft
wants to merge 18 commits into
base: implement-tracers
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion contracts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
const EMPTY_TXS_ROLLING_HASH: H256 = H256::zero();

#[derive(Debug, Clone)]
pub(crate) struct BootloaderL2Block {
pub struct BootloaderL2Block {
pub(crate) number: u32,
pub(crate) timestamp: u64,
pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock
Expand All @@ -36,7 +36,7 @@ impl BootloaderL2Block {
}
}

pub(super) fn push_tx(&mut self, tx: BootloaderTx) {
pub(crate) fn push_tx(&mut self, tx: BootloaderTx) {
self.update_rolling_hash(tx.hash);
self.txs.push(tx)
}
Expand All @@ -50,7 +50,7 @@ impl BootloaderL2Block {
)
}

fn update_rolling_hash(&mut self, tx_hash: H256) {
pub(crate) fn update_rolling_hash(&mut self, tx_hash: H256) {
self.txs_rolling_hash = concat_and_hash(self.txs_rolling_hash, tx_hash)
}

Expand Down
4 changes: 2 additions & 2 deletions core/lib/multivm/src/versions/era_vm/bootloader_state/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod l2_block;
pub mod l2_block;
mod snapshot;
mod state;
mod tx;
pub mod tx;

pub(crate) mod utils;
pub(crate) use snapshot::BootloaderStateSnapshot;
Expand Down
42 changes: 34 additions & 8 deletions core/lib/multivm/src/versions/era_vm/bootloader_state/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ pub struct BootloaderState {
/// See the structure doc-comment for a better explanation of purpose.
tx_to_execute: usize,
/// Stored txs in bootloader memory
l2_blocks: Vec<BootloaderL2Block>,
pub l2_blocks: Vec<BootloaderL2Block>,
/// The number of 32-byte words spent on the already included compressed bytecodes.
compressed_bytecodes_encoding: usize,
/// Initial memory of bootloader
initial_memory: BootloaderMemory,
pub initial_memory: BootloaderMemory,
/// Mode of txs for execution, it can be changed once per vm lunch
execution_mode: TxExecutionMode,
/// Current offset of the free space in the bootloader memory.
Expand Down Expand Up @@ -88,19 +88,20 @@ impl BootloaderState {
}

/// This method bypass sanity checks and should be used carefully.
pub(crate) fn push_l2_block(&mut self, l2_block: L2BlockEnv) {
pub fn push_l2_block(&mut self, l2_block: L2BlockEnv) {
self.l2_blocks
.push(BootloaderL2Block::new(l2_block, self.free_tx_index()))
}

pub(crate) fn push_tx(
pub(crate) fn push_tx_inner(
&mut self,
tx: TransactionData,
predefined_overhead: u32,
predefined_refund: u64,
compressed_bytecodes: Vec<CompressedBytecodeInfo>,
trusted_ergs_limit: U256,
chain_id: L2ChainId,
start_new_l2_block: bool,
) -> BootloaderMemory {
let tx_offset = self.free_tx_offset();
let bootloader_tx = BootloaderTx::new(
Expand All @@ -122,31 +123,56 @@ impl BootloaderState {
self.free_tx_offset(),
self.compressed_bytecodes_encoding,
self.execution_mode,
self.last_l2_block().txs.is_empty(),
start_new_l2_block,
);
self.compressed_bytecodes_encoding += compressed_bytecode_size;
self.free_tx_offset = tx_offset + bootloader_tx.encoded_len();
self.last_mut_l2_block().push_tx(bootloader_tx);
memory
}

pub(crate) fn last_l2_block(&self) -> &BootloaderL2Block {
pub(crate) fn push_tx(
&mut self,
tx: TransactionData,
predefined_overhead: u32,
predefined_refund: u64,
compressed_bytecodes: Vec<CompressedBytecodeInfo>,
trusted_ergs_limit: U256,
chain_id: L2ChainId,
) -> BootloaderMemory {
self.push_tx_inner(
tx,
predefined_overhead,
predefined_refund,
compressed_bytecodes,
trusted_ergs_limit,
chain_id,
self.last_l2_block().txs.is_empty(),
)
}

pub fn last_l2_block(&self) -> &BootloaderL2Block {
self.l2_blocks.last().unwrap()
}

pub fn last_l2_block_mut(&mut self) -> &mut BootloaderL2Block {
self.l2_blocks.last_mut().unwrap()
}

pub(crate) fn get_pubdata_information(&self) -> &PubdataInput {
self.pubdata_information
.get()
.expect("Pubdata information is not set")
}

fn last_mut_l2_block(&mut self) -> &mut BootloaderL2Block {
pub(crate) fn last_mut_l2_block(&mut self) -> &mut BootloaderL2Block {
self.l2_blocks.last_mut().unwrap()
}

/// Apply all bootloader transaction to the initial memory
pub(crate) fn bootloader_memory(&self) -> BootloaderMemory {
let mut initial_memory = self.initial_memory.clone();
let mut offset = 0;
let mut offset: usize = 0;
let mut compressed_bytecodes_offset = 0;
let mut tx_index = 0;
for l2_block in &self.l2_blocks {
Expand Down
4 changes: 2 additions & 2 deletions core/lib/multivm/src/versions/era_vm/bootloader_state/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use zksync_utils::bytecode::CompressedBytecodeInfo;
use crate::era_vm::transaction_data::TransactionData;

/// Information about tx necessary for execution in bootloader.
#[derive(Debug, Clone)]
#[derive(Debug, Default, Clone)]
pub(crate) struct BootloaderTx {
pub(crate) hash: H256,
/// Encoded transaction
Expand All @@ -22,7 +22,7 @@ pub(crate) struct BootloaderTx {
}

impl BootloaderTx {
pub(super) fn new(
pub fn new(
tx: TransactionData,
predefined_refund: u64,
predefined_overhead: u32,
Expand Down
4 changes: 4 additions & 0 deletions core/lib/multivm/src/versions/era_vm/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub enum Hook {
PostResult,
FinalBatchInfo,
PubdataRequested,
LoadParallel,
TxIndex,
}

impl Hook {
Expand All @@ -34,6 +36,8 @@ impl Hook {
10 => Hook::PostResult,
11 => Hook::FinalBatchInfo,
12 => Hook::PubdataRequested,
13 => Hook::LoadParallel,
14 => Hook::TxIndex,
_ => panic!("Unknown hook {}", hook),
}
}
Expand Down
1 change: 1 addition & 0 deletions core/lib/multivm/src/versions/era_vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod event;
mod hook;
mod initial_bootloader_memory;
mod logs;
pub mod parallel_exec;
mod snapshot;
#[cfg(test)]
mod tests;
Expand Down
32 changes: 32 additions & 0 deletions core/lib/multivm/src/versions/era_vm/parallel_exec/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use zksync_state::{ReadStorage, StoragePtr};

use super::ParallelTransaction;

// this struct is a partial replacemnt of the bootloader transaction processing and system context contract
pub struct ParallelExecutor<S: ReadStorage> {
storage: StoragePtr<S>,
}

impl<S: ReadStorage> ParallelExecutor<S> {
pub fn new(storage: StoragePtr<S>) -> Self {
Self { storage }
}

pub fn append_transaction(&self, txs: Vec<ParallelTransaction>) {}

pub fn process_transaction(&self, tx: ParallelTransaction) {
self.set_l2_block();
// bla bla
}

fn process_l2_transaction(&self, tx: ParallelTransaction) {}

fn process_l1_transaction(&self, tx: ParallelTransaction) {
todo!();
}

fn set_l2_block(&self) {}

/// finalizes transaction processing by commiting final state changes to storage
pub fn finalize(&self) {}
}
4 changes: 4 additions & 0 deletions core/lib/multivm/src/versions/era_vm/parallel_exec/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub use executor::ParallelExecutor;
pub use transaction::ParallelTransaction;
mod executor;
mod transaction;
28 changes: 28 additions & 0 deletions core/lib/multivm/src/versions/era_vm/parallel_exec/transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use zksync_types::Transaction;

use crate::era_vm::bootloader_state::l2_block::BootloaderL2Block;

#[derive(Clone, Debug)]
pub struct ParallelTransaction {
pub tx: Transaction,
pub refund: u64,
pub with_compression: bool,
// the l2 block this transaction belongs to
pub l2_block: BootloaderL2Block,
}

impl ParallelTransaction {
pub fn new(
tx: Transaction,
refund: u64,
with_compression: bool,
l2_block: BootloaderL2Block,
) -> Self {
Self {
tx,
refund,
with_compression,
l2_block,
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::collections::HashSet;

use itertools::Itertools;
use zksync_state::ReadStorage;
use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS;
use zksync_test_account::Account;
Expand Down
1 change: 1 addition & 0 deletions core/lib/multivm/src/versions/era_vm/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ mod is_write_initial;
mod l1_tx_execution;
mod l2_blocks;
mod nonce_holder;
mod parallel_execution;
mod precompiles;
mod refunds;
mod require_eip712;
Expand Down
78 changes: 78 additions & 0 deletions core/lib/multivm/src/versions/era_vm/tests/parallel_execution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use zksync_test_account::Account;
use zksync_types::{K256PrivateKey, Transaction};

use super::tester::VmTester;
use crate::{
era_vm::tests::tester::{TxType, VmTesterBuilder},
interface::{VmExecutionMode, VmInterface},
};

fn prepare_test() -> (VmTester, [Transaction; 3]) {
let bytes = [1; 32];
let account = Account::new(K256PrivateKey::from_bytes(bytes.into()).unwrap());

let mut vm_tester = VmTesterBuilder::new()
.with_empty_in_memory_storage()
.with_deployer()
.with_custom_account(account)
.build();

vm_tester.deploy_test_contract();

let account = &mut vm_tester.rich_accounts[0];

let txs = [
account.get_test_contract_transaction(
vm_tester.test_contract.unwrap(),
false,
Default::default(),
false,
TxType::L1 { serial_id: 1 },
),
account.get_test_contract_transaction(
vm_tester.test_contract.unwrap(),
true,
Default::default(),
false,
TxType::L1 { serial_id: 1 },
),
account.get_test_contract_transaction(
vm_tester.test_contract.unwrap(),
false,
Default::default(),
false,
TxType::L1 { serial_id: 1 },
),
];

(vm_tester, txs)
}

#[test]
fn parallel_execution() {
let normal_execution = {
let (mut vm, txs) = prepare_test();
let vm = &mut vm.vm;
for tx in &txs {
vm.push_transaction_inner(tx.clone(), 0, true);
}
vm.execute(VmExecutionMode::Batch)
};

let parallel_execution = {
let (mut vm, txs) = prepare_test();
let vm = &mut vm.vm;
for tx in txs {
vm.push_parallel_transaction(tx, 0, true);
}
vm.execute_parallel()
};
println!("EXECUTION RESULT {:?}", parallel_execution.result);

assert_eq!(
normal_execution.logs.storage_logs,
parallel_execution.logs.storage_logs
);
assert_eq!(normal_execution.result, parallel_execution.result);
assert_eq!(normal_execution.refunds, parallel_execution.refunds);
}
Loading
Loading