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

Add predicates #22

Merged
merged 28 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e8ddeab
Add initial add opcode
gianbelinche Jun 10, 2024
dff174d
Begin operand indirection
gianbelinche Jun 11, 2024
584d470
Merge branch 'main' into add-and-sub-opcodes
jrchatruc Jun 11, 2024
15fe24a
Add address for dest
gianbelinche Jun 11, 2024
fe606d4
Fix compilation error
gianbelinche Jun 11, 2024
faef779
Format code
gianbelinche Jun 11, 2024
0003e7c
Run clippy
gianbelinche Jun 11, 2024
3200c71
Add target for asm (#17)
fkrause98 Jun 12, 2024
3ce70b1
Update test setup, add failing sub test and 'add' test
fkrause98 Jun 12, 2024
62221b2
Remove echo
fkrause98 Jun 12, 2024
bf908eb
Clippy
fkrause98 Jun 12, 2024
f39b2ba
Add sub implementation
fkrause98 Jun 12, 2024
10d9c81
Make sub test work
fkrause98 Jun 12, 2024
c1f9203
Add should be zero and modify simple test
fkrause98 Jun 12, 2024
ff7437d
Modify tests
fkrause98 Jun 12, 2024
8b8e7c2
Format
fkrause98 Jun 12, 2024
25f4462
Working tests
fkrause98 Jun 12, 2024
2dc13c1
Lint
fkrause98 Jun 12, 2024
c77db08
Add tests for conditional predicates
fkrause98 Jun 12, 2024
6bea502
Explicitly add flags for vm state.
fkrause98 Jun 12, 2024
4b0e40f
Add tests for predicates
fkrause98 Jun 12, 2024
960d16d
Add failing test
fkrause98 Jun 12, 2024
fef8e46
Merge branch 'main' into add-predicates
fkrause98 Jun 12, 2024
95544b0
Fix complex test
fkrause98 Jun 12, 2024
ba84b72
Cargo fmt
fkrause98 Jun 12, 2024
bafff9d
Make it compile with rust stable
fkrause98 Jun 12, 2024
2ddc04b
Cargo fmt
fkrause98 Jun 13, 2024
16f5623
Clippy + Fmt
fkrause98 Jun 13, 2024
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
16 changes: 16 additions & 0 deletions programs/add_and_sub_with_conditionals.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.eq 20, r0, r1
sub 30, r1, r1
sub.lt 5, r1, r1
sub.gt 5, r1, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.eq 1, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_eq.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.eq 10, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_gt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.gt 20, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_lt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.lt 10, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_not_eq.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.lt 10, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_not_gt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.gt 20, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
13 changes: 13 additions & 0 deletions programs/add_conditional_not_lt.zasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.text
.file "add_conditional.zasm"
.globl __entry
__entry:

.func_begin0:
add.lt 10, r0, r1
sstore r0, r1
ret

.func_end0:
.note.GNU-stack
.rodata
84 changes: 46 additions & 38 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ use zkevm_opcode_defs::ISAVersion;
use zkevm_opcode_defs::LogOpcode;
use zkevm_opcode_defs::Opcode as Variant;

pub fn run_program(bin_path: &str) -> U256 {
pub fn run_program(bin_path: &str) -> (U256, VMState) {
gianbelinche marked this conversation as resolved.
Show resolved Hide resolved
let vm = VMState::new(vec![]);
run_program_with_custom_state(bin_path, vm)
}

pub fn run_program_with_custom_state(bin_path: &str, mut vm: VMState) -> (U256, VMState) {
let opcode_table = synthesize_opcode_decoding_tables(11, ISAVersion(2));

let program = std::fs::read(bin_path).unwrap();
let encoded = String::from_utf8(program.to_vec()).unwrap();
let bin = hex::decode(&encoded[2..]).unwrap();

let mut program_code = vec![];

for raw_opcode_slice in bin.chunks(32) {
let mut raw_opcode_bytes: [u8; 32] = [0; 32];
raw_opcode_bytes.copy_from_slice(&raw_opcode_slice[..32]);
Expand All @@ -30,50 +36,52 @@ pub fn run_program(bin_path: &str) -> U256 {
program_code.push(raw_opcode_u256);
}

let mut vm = VMState::new(program_code);
vm.load_program(program_code);

loop {
let opcode = vm.get_opcode(&opcode_table);
match opcode.variant {
Variant::Invalid(_) => todo!(),
Variant::Nop(_) => todo!(),
Variant::Add(_) => {
_add(&mut vm, opcode);
}
Variant::Sub(_) => _sub(&mut vm, opcode),
Variant::Mul(_) => todo!(),
Variant::Div(_) => todo!(),
Variant::Jump(_) => todo!(),
Variant::Context(_) => todo!(),
Variant::Shift(_) => todo!(),
Variant::Binop(_) => todo!(),
Variant::Ptr(_) => todo!(),
Variant::NearCall(_) => todo!(),
Variant::Log(log_variant) => match log_variant {
LogOpcode::StorageRead => todo!(),
LogOpcode::StorageWrite => {
let src0 = vm.get_register(opcode.src0_index);
let src1 = vm.get_register(opcode.src1_index);
vm.current_frame.storage.insert(src0, src1);
if vm.predicate_holds(&opcode.predicate) {
match opcode.variant {
Variant::Invalid(_) => todo!(),
Variant::Nop(_) => todo!(),
Variant::Add(_) => {
_add(&mut vm, opcode);
}
Variant::Sub(_) => _sub(&mut vm, opcode),
Variant::Mul(_) => todo!(),
Variant::Div(_) => todo!(),
Variant::Jump(_) => todo!(),
Variant::Context(_) => todo!(),
Variant::Shift(_) => todo!(),
Variant::Binop(_) => todo!(),
Variant::Ptr(_) => todo!(),
Variant::NearCall(_) => todo!(),
Variant::Log(log_variant) => match log_variant {
LogOpcode::StorageRead => todo!(),
LogOpcode::StorageWrite => {
let src0 = vm.get_register(opcode.src0_index);
let src1 = vm.get_register(opcode.src1_index);
vm.current_frame.storage.insert(src0, src1);
}
LogOpcode::ToL1Message => todo!(),
LogOpcode::Event => todo!(),
LogOpcode::PrecompileCall => todo!(),
LogOpcode::Decommit => todo!(),
LogOpcode::TransientStorageRead => todo!(),
LogOpcode::TransientStorageWrite => todo!(),
},
Variant::FarCall(_) => todo!(),
Variant::Ret(_) => {
// TODO: This is not how return works. Fix when we have calls between contracts
// hooked up.
break;
}
LogOpcode::ToL1Message => todo!(),
LogOpcode::Event => todo!(),
LogOpcode::PrecompileCall => todo!(),
LogOpcode::Decommit => todo!(),
LogOpcode::TransientStorageRead => todo!(),
LogOpcode::TransientStorageWrite => todo!(),
},
Variant::FarCall(_) => todo!(),
Variant::Ret(_) => {
// TODO: This is not how return works. Fix when we have calls between contracts
// hooked up.
break;
Variant::UMA(_) => todo!(),
}
Variant::UMA(_) => todo!(),
}

vm.current_frame.pc += 1;
}

*vm.current_frame.storage.get(&U256::zero()).unwrap()
let final_storage_value = *vm.current_frame.storage.get(&U256::zero()).unwrap();
(final_storage_value, vm.clone())
}
9 changes: 6 additions & 3 deletions src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ pub struct Opcode {
pub src0_operand_type: Operand,
pub dst0_operand_type: Operand,
pub predicate: Predicate,
pub flags: [bool; 2],
// pub flags: [bool; 2],
pub alters_vm_flags: bool,
pub swap_flag: bool,
pub src0_index: u8,
pub src1_index: u8,
pub dst0_index: u8,
Expand All @@ -50,7 +52,7 @@ impl Opcode {
// First 11 bits
let variant_bits = raw_op & 2047;
let opcode_zksync = opcode_table[variant_bits as usize];

let [alters_vm_flags, swap_flag] = opcode_zksync.flags;
let predicate_u8: u8 = ((raw_op & 0xe000) >> 13) as u8;
let src0_and_1_index: u8 = ((raw_op & 0xff0000) >> 16) as u8;
let dst0_and_1_index: u8 = ((raw_op & 0xff000000) >> 24) as u8;
Expand All @@ -63,7 +65,8 @@ impl Opcode {
src0_operand_type: opcode_zksync.src0_operand_type,
dst0_operand_type: opcode_zksync.dst0_operand_type,
predicate: Predicate::from(predicate_u8),
flags: opcode_zksync.flags,
alters_vm_flags,
swap_flag,
src0_index: first_four_bits(src0_and_1_index),
src1_index: second_four_bits(src0_and_1_index),
dst0_index: first_four_bits(dst0_and_1_index),
Expand Down
44 changes: 38 additions & 6 deletions src/state.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::collections::HashMap;

use crate::{value::TaggedValue, Opcode};
use crate::{opcode::Predicate, value::TaggedValue, Opcode};
use u256::U256;
use zkevm_opcode_defs::OpcodeVariant;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CallFrame {
// Max length for this is 1 << 16. Might want to enforce that at some point
pub stack: Vec<TaggedValue>,
Expand All @@ -20,25 +20,57 @@ pub struct CallFrame {
pub storage: HashMap<U256, U256>,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct VMState {
// The first register, r0, is actually always zero and not really used.
// Writing to it does nothing.
pub registers: [U256; 15],
pub flags: u8, // We only use the first three bits for the flags here: LT, GT, EQ.
pub flag_lt: bool, // We only use the first three bits for the flags here: LT, GT, EQ.
pub flag_gt: bool,
pub flag_eq: bool,
pub current_frame: CallFrame,
}

impl VMState {
// TODO: The VM will probably not take the program to execute as a parameter later on.
pub fn new(program_code: Vec<U256>) -> Self {
Self {
registers: [U256::zero(); 15],
flags: 0,
flag_lt: false,
flag_gt: false,
flag_eq: false,
current_frame: CallFrame::new(program_code),
}
}

pub fn new_with_flag_state(flag_lt: bool, flag_eq: bool, flag_gt: bool) -> Self {
let registers = [U256::zero(); 15];
let current_frame = CallFrame::new(vec![]);
Self {
registers,
flag_lt,
flag_gt,
flag_eq,
current_frame,
}
}

pub fn load_program(&mut self, program_code: Vec<U256>) {
self.current_frame = CallFrame::new(program_code);
}

pub fn predicate_holds(&self, condition: &Predicate) -> bool {
match condition {
Predicate::Always => true,
Predicate::Gt => self.flag_gt,
Predicate::Lt => self.flag_lt,
Predicate::Eq => self.flag_eq,
Predicate::Ge => self.flag_eq || self.flag_gt,
Predicate::Le => self.flag_eq || self.flag_lt,
Predicate::Ne => !self.flag_eq,
Predicate::GtOrLt => self.flag_gt || self.flag_lt,
}
}

pub fn get_register(&self, index: u8) -> U256 {
if index != 0 {
return self.registers[(index - 1) as usize];
Expand Down
2 changes: 1 addition & 1 deletion src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use u256::U256;

/// In the zkEVM, all data in the stack and on registers is tagged to determine
/// whether they are a pointer or not.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct TaggedValue {
pub value: U256,
pub is_pointer: bool,
Expand Down
Loading