Skip to content

Commit

Permalink
chore: External world (#23)
Browse files Browse the repository at this point in the history
The VM no longer takes ownership of the World. This is necessary because
otherwise Rust requires an extra lifetime on VirtualMachine. It is also
a better interface.
  • Loading branch information
joonazan authored May 16, 2024
1 parent 26157ec commit 297312e
Show file tree
Hide file tree
Showing 23 changed files with 261 additions and 181 deletions.
14 changes: 6 additions & 8 deletions benches/nested_near_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ fn nested_near_call(bencher: Bencher) {
let address = Address::from_low_u64_be(0xabe123ff);

bencher.bench(|| {
let mut world = Box::new(TestWorld::new(&[(address, program.clone())]));
let program = initial_decommit(&mut *world, address);
let mut world = TestWorld::new(&[(address, program.clone())]);
let program = initial_decommit(&mut world, address);
let mut vm = vm2::VirtualMachine::new(
black_box(world),
address,
program,
Address::zero(),
Expand All @@ -41,7 +40,7 @@ fn nested_near_call(bencher: Bencher) {
},
);

vm.run();
vm.run(black_box(&mut world));
});
}

Expand Down Expand Up @@ -70,10 +69,9 @@ fn nested_near_call_with_storage_write(bencher: Bencher) {
let address = Address::from_low_u64_be(0xabe123ff);

bencher.bench(|| {
let mut world = Box::new(TestWorld::new(&[(address, program.clone())]));
let program = initial_decommit(&mut *world, address);
let mut world = TestWorld::new(&[(address, program.clone())]);
let program = initial_decommit(&mut world, address);
let mut vm = vm2::VirtualMachine::new(
black_box(world),
address,
program,
Address::zero(),
Expand All @@ -86,7 +84,7 @@ fn nested_near_call_with_storage_write(bencher: Bencher) {
},
);

vm.run();
vm.run(black_box(&mut world));
});
}

Expand Down
3 changes: 2 additions & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
Add, And, AuxHeap, CallingMode, Div, Heap, Mul, Or, PtrAdd, PtrPack, PtrShrink, PtrSub,
RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor,
},
jump_to_beginning, Instruction, Predicate, VirtualMachine,
jump_to_beginning, Instruction, Predicate, VirtualMachine, World,
};
use zkevm_opcode_defs::{
decoding::{EncodingModeProduction, VmEncodingMode},
Expand Down Expand Up @@ -44,6 +44,7 @@ fn unimplemented_instruction(variant: Opcode) -> Instruction {
fn unimplemented_handler(
vm: &mut VirtualMachine,
instruction: *const Instruction,
_: &mut dyn World,
) -> InstructionResult {
let variant: Opcode = unsafe {
std::mem::transmute(
Expand Down
10 changes: 6 additions & 4 deletions src/decommit.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::{modified_world::ModifiedWorld, program::Program, World};
use crate::{modified_world::WorldDiff, program::Program, World};
use u256::{H160, U256};
use zkevm_opcode_defs::{
ethereum_types::Address, system_params::DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW,
};

impl ModifiedWorld {
impl WorldDiff {
pub(crate) fn decommit(
&mut self,
world: &mut dyn World,
address: U256,
default_aa_code_hash: [u8; 32],
evm_interpreter_code_hash: [u8; 32],
Expand All @@ -19,7 +20,8 @@ impl ModifiedWorld {
let mut is_evm = false;

let mut code_info = {
let (code_info, _) = self.read_storage(deployer_system_contract_address, address);
let (code_info, _) =
self.read_storage(world, deployer_system_contract_address, address);
let mut code_info_bytes = [0; 32];
code_info.to_big_endian(&mut code_info_bytes);

Expand Down Expand Up @@ -65,7 +67,7 @@ impl ModifiedWorld {
self.decommitted_hashes.insert(code_key, ());
};

let program = self.world.decommit(code_key);
let program = world.decommit(code_key);
Some((program, is_evm))
}
}
Expand Down
11 changes: 8 additions & 3 deletions src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::{addressing_modes::Arguments, vm::VirtualMachine, Predicate};
use crate::{addressing_modes::Arguments, vm::VirtualMachine, Predicate, World};

#[derive(Hash, Debug)]
pub struct Instruction {
pub(crate) handler: Handler,
pub(crate) arguments: Arguments,
}

pub(crate) type Handler = fn(&mut VirtualMachine, *const Instruction) -> InstructionResult;
pub(crate) type Handler =
fn(&mut VirtualMachine, *const Instruction, &mut dyn World) -> InstructionResult;
pub(crate) type InstructionResult = Result<*const Instruction, ExecutionEnd>;

#[derive(Debug, PartialEq)]
Expand All @@ -28,7 +29,11 @@ pub fn jump_to_beginning() -> Instruction {
arguments: Arguments::new(Predicate::Always, 0),
}
}
fn jump_to_beginning_handler(vm: &mut VirtualMachine, _: *const Instruction) -> InstructionResult {
fn jump_to_beginning_handler(
vm: &mut VirtualMachine,
_: *const Instruction,
_: &mut dyn World,
) -> InstructionResult {
let first_instruction = &vm.state.current_frame.program.instructions()[0];
Ok(first_instruction)
}
5 changes: 3 additions & 2 deletions src/instruction_handlers/binop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ use crate::{
},
instruction::{Instruction, InstructionResult},
predication::Flags,
VirtualMachine,
VirtualMachine, World,
};
use u256::U256;

fn binop<Op: Binop, In1: Source, Out: Destination, const SWAP: bool, const SET_FLAGS: bool>(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate(vm, instruction, |vm, args| {
instruction_boilerplate(vm, instruction, world, |vm, args, _| {
let a = In1::get(args, &mut vm.state);
let b = Register2::get(args, &mut vm.state);
let (a, b) = if SWAP { (b, a) } else { (a, b) };
Expand Down
17 changes: 12 additions & 5 deletions src/instruction_handlers/common.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::{
addressing_modes::Arguments, instruction::InstructionResult, Instruction, VirtualMachine,
addressing_modes::Arguments, instruction::InstructionResult, Instruction, VirtualMachine, World,
};

#[inline(always)]
pub(crate) fn instruction_boilerplate(
vm: &mut VirtualMachine,
instruction: *const Instruction,
business_logic: impl FnOnce(&mut VirtualMachine, &Arguments),
world: &mut dyn World,
business_logic: impl FnOnce(&mut VirtualMachine, &Arguments, &mut dyn World),
) -> InstructionResult {
unsafe {
business_logic(vm, &(*instruction).arguments);
business_logic(vm, &(*instruction).arguments, world);
Ok(instruction.add(1))
}
}
Expand All @@ -18,7 +19,13 @@ pub(crate) fn instruction_boilerplate(
pub(crate) fn instruction_boilerplate_with_panic(
vm: &mut VirtualMachine,
instruction: *const Instruction,
business_logic: impl FnOnce(&mut VirtualMachine, &Arguments, InstructionResult) -> InstructionResult,
world: &mut dyn World,
business_logic: impl FnOnce(
&mut VirtualMachine,
&Arguments,
&mut dyn World,
InstructionResult,
) -> InstructionResult,
) -> InstructionResult {
unsafe { business_logic(vm, &(*instruction).arguments, Ok(instruction.add(1))) }
unsafe { business_logic(vm, &(*instruction).arguments, world, Ok(instruction.add(1))) }
}
35 changes: 23 additions & 12 deletions src/instruction_handlers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ use crate::{
decommit::address_into_u256,
instruction::InstructionResult,
state::State,
Instruction, VirtualMachine,
Instruction, VirtualMachine, World,
};
use u256::U256;
use zkevm_opcode_defs::VmMetaParameters;

fn context<Op: ContextOp>(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate(vm, instruction, |vm, args| {
instruction_boilerplate(vm, instruction, world, |vm, args, _| {
let result = Op::get(&vm.state);
Register1::set(args, &mut vm.state, result)
})
Expand Down Expand Up @@ -85,24 +86,34 @@ impl ContextOp for Meta {
}
}

fn set_context_u128(vm: &mut VirtualMachine, instruction: *const Instruction) -> InstructionResult {
instruction_boilerplate_with_panic(vm, instruction, |vm, args, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm);
}
fn set_context_u128(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate_with_panic(
vm,
instruction,
world,
|vm, args, world, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm, world);
}

let value = Register1::get(args, &mut vm.state).low_u128();
vm.state.set_context_u128(value);
let value = Register1::get(args, &mut vm.state).low_u128();
vm.state.set_context_u128(value);

continue_normally
})
continue_normally
},
)
}

fn increment_tx_number(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate(vm, instruction, |vm, _| {
instruction_boilerplate(vm, instruction, world, |vm, _, _| {
vm.start_new_tx();
})
}
Expand Down
93 changes: 56 additions & 37 deletions src/instruction_handlers/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,73 @@ use crate::{
addressing_modes::{Arguments, Immediate1, Register1, Register2, Source},
instruction::InstructionResult,
modified_world::{Event, L2ToL1Log},
Instruction, VirtualMachine,
Instruction, VirtualMachine, World,
};
use u256::H160;
use zkevm_opcode_defs::ADDRESS_EVENT_WRITER;

fn event(vm: &mut VirtualMachine, instruction: *const Instruction) -> InstructionResult {
instruction_boilerplate_with_panic(vm, instruction, |vm, args, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm);
}
if vm.state.current_frame.address == H160::from_low_u64_be(ADDRESS_EVENT_WRITER as u64) {
fn event(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate_with_panic(
vm,
instruction,
world,
|vm, args, world, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm, world);
}
if vm.state.current_frame.address == H160::from_low_u64_be(ADDRESS_EVENT_WRITER as u64)
{
let key = Register1::get(args, &mut vm.state);
let value = Register2::get(args, &mut vm.state);
let is_first = Immediate1::get(args, &mut vm.state).low_u32() == 1;

vm.world_diff.record_event(Event {
key,
value,
is_first,
shard_id: 0, // shards currently aren't supported
tx_number: vm.state.transaction_number,
});
}

continue_normally
},
)
}

fn l2_to_l1(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
instruction_boilerplate_with_panic(
vm,
instruction,
world,
|vm, args, world, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm, world);
}

let key = Register1::get(args, &mut vm.state);
let value = Register2::get(args, &mut vm.state);
let is_first = Immediate1::get(args, &mut vm.state).low_u32() == 1;

vm.world.record_event(Event {
let is_service = Immediate1::get(args, &mut vm.state).low_u32() == 1;
vm.world_diff.record_l2_to_l1_log(L2ToL1Log {
key,
value,
is_first,
shard_id: 0, // shards currently aren't supported
is_service,
address: vm.state.current_frame.address,
shard_id: 0,
tx_number: vm.state.transaction_number,
});
}

continue_normally
})
}

fn l2_to_l1(vm: &mut VirtualMachine, instruction: *const Instruction) -> InstructionResult {
instruction_boilerplate_with_panic(vm, instruction, |vm, args, continue_normally| {
if vm.state.current_frame.is_static {
return free_panic(vm);
}

let key = Register1::get(args, &mut vm.state);
let value = Register2::get(args, &mut vm.state);
let is_service = Immediate1::get(args, &mut vm.state).low_u32() == 1;
vm.world.record_l2_to_l1_log(L2ToL1Log {
key,
value,
is_service,
address: vm.state.current_frame.address,
shard_id: 0,
tx_number: vm.state.transaction_number,
});

continue_normally
})
continue_normally
},
)
}

impl Instruction {
Expand Down
8 changes: 5 additions & 3 deletions src/instruction_handlers/far_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
fat_pointer::FatPointer,
instruction::InstructionResult,
predication::Flags,
Instruction, VirtualMachine,
Instruction, VirtualMachine, World,
};
use u256::U256;
use zkevm_opcode_defs::{
Expand Down Expand Up @@ -33,6 +33,7 @@ pub enum CallingMode {
fn far_call<const CALLING_MODE: u8, const IS_STATIC: bool>(
vm: &mut VirtualMachine,
instruction: *const Instruction,
world: &mut dyn World,
) -> InstructionResult {
let args = unsafe { &(*instruction).arguments };

Expand All @@ -47,7 +48,8 @@ fn far_call<const CALLING_MODE: u8, const IS_STATIC: bool>(
let calldata =
get_far_call_calldata(raw_abi, Register1::is_fat_pointer(args, &mut vm.state), vm);

let decommit_result = vm.world.decommit(
let decommit_result = vm.world_diff.decommit(
world,
destination_address,
vm.settings.default_aa_code_hash,
vm.settings.evm_interpreter_code_hash,
Expand Down Expand Up @@ -96,7 +98,7 @@ fn far_call<const CALLING_MODE: u8, const IS_STATIC: bool>(
exception_handler,
IS_STATIC && !is_evm_interpreter,
calldata.memory_page,
vm.world.snapshot(),
vm.world_diff.snapshot(),
);

vm.state.flags = Flags::new(false, false, false);
Expand Down
Loading

0 comments on commit 297312e

Please sign in to comment.