mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 06:43:07 +00:00
Changes in interpreter and implement interpreter version for add11 (#1359)
* Fix interpreter, turn syscall opcodes into actual syscalls, create interpreter test for add11 * Rename test_add11 to test_add11_yml * Apply comments * Cleanup add11_yml interpreter test * Make stack_top() return a Result, and remove Result from add11_yml test * Apply comment
This commit is contained in:
parent
6dd2e313c4
commit
96f3faf26e
@ -21,6 +21,7 @@ use crate::generation::state::GenerationState;
|
|||||||
use crate::generation::GenerationInputs;
|
use crate::generation::GenerationInputs;
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
use crate::util::u256_to_usize;
|
use crate::util::u256_to_usize;
|
||||||
|
use crate::witness::errors::ProgramError;
|
||||||
use crate::witness::gas::gas_to_charge;
|
use crate::witness::gas::gas_to_charge;
|
||||||
use crate::witness::memory::{MemoryAddress, MemoryContextState, MemorySegmentState, MemoryState};
|
use crate::witness::memory::{MemoryAddress, MemoryContextState, MemorySegmentState, MemoryState};
|
||||||
use crate::witness::operation::Operation;
|
use crate::witness::operation::Operation;
|
||||||
@ -43,9 +44,7 @@ impl MemoryState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Interpreter<'a> {
|
pub(crate) struct Interpreter<'a> {
|
||||||
pub(crate) kernel_mode: bool,
|
|
||||||
jumpdests: Vec<usize>,
|
jumpdests: Vec<usize>,
|
||||||
pub(crate) context: usize,
|
|
||||||
pub(crate) generation_state: GenerationState<F>,
|
pub(crate) generation_state: GenerationState<F>,
|
||||||
prover_inputs_map: &'a HashMap<usize, ProverInputFn>,
|
prover_inputs_map: &'a HashMap<usize, ProverInputFn>,
|
||||||
pub(crate) halt_offsets: Vec<usize>,
|
pub(crate) halt_offsets: Vec<usize>,
|
||||||
@ -121,16 +120,16 @@ impl<'a> Interpreter<'a> {
|
|||||||
prover_inputs: &'a HashMap<usize, ProverInputFn>,
|
prover_inputs: &'a HashMap<usize, ProverInputFn>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
kernel_mode: true,
|
|
||||||
jumpdests: find_jumpdests(code),
|
jumpdests: find_jumpdests(code),
|
||||||
generation_state: GenerationState::new(GenerationInputs::default(), code)
|
generation_state: GenerationState::new(GenerationInputs::default(), code)
|
||||||
.expect("Default inputs are known-good"),
|
.expect("Default inputs are known-good"),
|
||||||
prover_inputs_map: prover_inputs,
|
prover_inputs_map: prover_inputs,
|
||||||
context: 0,
|
// `DEFAULT_HALT_OFFSET` is used as a halting point for the interpreter,
|
||||||
halt_offsets: vec![DEFAULT_HALT_OFFSET],
|
// while the label `halt` is the halting label in the kernel.
|
||||||
|
halt_offsets: vec![DEFAULT_HALT_OFFSET, KERNEL.global_labels["halt"]],
|
||||||
debug_offsets: vec![],
|
debug_offsets: vec![],
|
||||||
running: false,
|
running: false,
|
||||||
opcode_count: [0; 0x100],
|
opcode_count: [0; 256],
|
||||||
};
|
};
|
||||||
result.generation_state.registers.program_counter = initial_offset;
|
result.generation_state.registers.program_counter = initial_offset;
|
||||||
let initial_stack_len = initial_stack.len();
|
let initial_stack_len = initial_stack.len();
|
||||||
@ -147,6 +146,10 @@ impl<'a> Interpreter<'a> {
|
|||||||
pub(crate) fn run(&mut self) -> anyhow::Result<()> {
|
pub(crate) fn run(&mut self) -> anyhow::Result<()> {
|
||||||
self.running = true;
|
self.running = true;
|
||||||
while self.running {
|
while self.running {
|
||||||
|
let pc = self.generation_state.registers.program_counter;
|
||||||
|
if self.is_kernel() && self.halt_offsets.contains(&pc) {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
self.run_opcode()?;
|
self.run_opcode()?;
|
||||||
}
|
}
|
||||||
println!("Opcode count:");
|
println!("Opcode count:");
|
||||||
@ -161,8 +164,7 @@ impl<'a> Interpreter<'a> {
|
|||||||
|
|
||||||
fn code(&self) -> &MemorySegmentState {
|
fn code(&self) -> &MemorySegmentState {
|
||||||
// The context is 0 if we are in kernel mode.
|
// The context is 0 if we are in kernel mode.
|
||||||
&self.generation_state.memory.contexts
|
&self.generation_state.memory.contexts[(1 - self.is_kernel() as usize) * self.context()]
|
||||||
[(1 - self.generation_state.registers.is_kernel as usize) * self.context]
|
|
||||||
.segments[Segment::Code as usize]
|
.segments[Segment::Code as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +200,13 @@ impl<'a> Interpreter<'a> {
|
|||||||
.set(field as usize, value)
|
.set(field as usize, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_global_metadata_multi_fields(&mut self, metadata: &[(GlobalMetadata, U256)]) {
|
||||||
|
for &(field, value) in metadata {
|
||||||
|
self.generation_state.memory.contexts[0].segments[Segment::GlobalMetadata as usize]
|
||||||
|
.set(field as usize, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_trie_data(&self) -> &[U256] {
|
pub(crate) fn get_trie_data(&self) -> &[U256] {
|
||||||
&self.generation_state.memory.contexts[0].segments[Segment::TrieData as usize].content
|
&self.generation_state.memory.contexts[0].segments[Segment::TrieData as usize].content
|
||||||
}
|
}
|
||||||
@ -221,7 +230,7 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_current_general_memory(&self) -> Vec<U256> {
|
pub(crate) fn get_current_general_memory(&self) -> Vec<U256> {
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
self.generation_state.memory.contexts[self.context()].segments
|
||||||
[Segment::KernelGeneral as usize]
|
[Segment::KernelGeneral as usize]
|
||||||
.content
|
.content
|
||||||
.clone()
|
.clone()
|
||||||
@ -236,8 +245,8 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_current_general_memory(&mut self, memory: Vec<U256>) {
|
pub(crate) fn set_current_general_memory(&mut self, memory: Vec<U256>) {
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
let context = self.context();
|
||||||
[Segment::KernelGeneral as usize]
|
self.generation_state.memory.contexts[context].segments[Segment::KernelGeneral as usize]
|
||||||
.content = memory;
|
.content = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,18 +288,32 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn stack(&self) -> Vec<U256> {
|
pub(crate) fn stack(&self) -> Vec<U256> {
|
||||||
let mut stack = self.generation_state.memory.contexts[self.context].segments
|
match self.stack_len().cmp(&1) {
|
||||||
[Segment::Stack as usize]
|
Ordering::Greater => {
|
||||||
.content
|
let mut stack = self.generation_state.memory.contexts[self.context()].segments
|
||||||
.clone();
|
[Segment::Stack as usize]
|
||||||
if self.stack_len() > 0 {
|
.content
|
||||||
stack.push(self.stack_top());
|
.clone();
|
||||||
|
stack.truncate(self.stack_len() - 1);
|
||||||
|
stack.push(
|
||||||
|
self.stack_top()
|
||||||
|
.expect("The stack is checked to be nonempty"),
|
||||||
|
);
|
||||||
|
stack
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
vec![self
|
||||||
|
.stack_top()
|
||||||
|
.expect("The stack is checked to be nonempty")]
|
||||||
|
}
|
||||||
|
Ordering::Less => {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stack
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_segment_mut(&mut self) -> &mut Vec<U256> {
|
fn stack_segment_mut(&mut self) -> &mut Vec<U256> {
|
||||||
&mut self.generation_state.memory.contexts[self.context].segments[Segment::Stack as usize]
|
let context = self.context();
|
||||||
|
&mut self.generation_state.memory.contexts[context].segments[Segment::Stack as usize]
|
||||||
.content
|
.content
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,8 +331,12 @@ impl<'a> Interpreter<'a> {
|
|||||||
|
|
||||||
pub(crate) fn push(&mut self, x: U256) {
|
pub(crate) fn push(&mut self, x: U256) {
|
||||||
if self.stack_len() > 0 {
|
if self.stack_len() > 0 {
|
||||||
let top = self.stack_top();
|
let top = self
|
||||||
self.stack_segment_mut().push(top);
|
.stack_top()
|
||||||
|
.expect("The stack is checked to be nonempty");
|
||||||
|
let cur_len = self.stack_len();
|
||||||
|
let stack_addr = MemoryAddress::new(self.context(), Segment::Stack, cur_len - 1);
|
||||||
|
self.generation_state.memory.set(stack_addr, top);
|
||||||
}
|
}
|
||||||
self.generation_state.registers.stack_top = x;
|
self.generation_state.registers.stack_top = x;
|
||||||
self.generation_state.registers.stack_len += 1;
|
self.generation_state.registers.stack_len += 1;
|
||||||
@ -326,12 +353,7 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.generation_state.registers.stack_top = top;
|
self.generation_state.registers.stack_top = top;
|
||||||
}
|
}
|
||||||
self.generation_state.registers.stack_len -= 1;
|
self.generation_state.registers.stack_len -= 1;
|
||||||
let new_len = self.stack_len();
|
|
||||||
if new_len > 0 {
|
|
||||||
self.stack_segment_mut().truncate(new_len - 1);
|
|
||||||
} else {
|
|
||||||
self.stack_segment_mut().truncate(0);
|
|
||||||
}
|
|
||||||
result.expect("Empty stack")
|
result.expect("Empty stack")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,85 +364,85 @@ impl<'a> Interpreter<'a> {
|
|||||||
.byte(0);
|
.byte(0);
|
||||||
self.opcode_count[opcode as usize] += 1;
|
self.opcode_count[opcode as usize] += 1;
|
||||||
self.incr(1);
|
self.incr(1);
|
||||||
|
|
||||||
match opcode {
|
match opcode {
|
||||||
0x00 => self.run_stop(), // "STOP",
|
0x00 => self.run_syscall(opcode, 0, false)?, // "STOP",
|
||||||
0x01 => self.run_add(), // "ADD",
|
0x01 => self.run_add(), // "ADD",
|
||||||
0x02 => self.run_mul(), // "MUL",
|
0x02 => self.run_mul(), // "MUL",
|
||||||
0x03 => self.run_sub(), // "SUB",
|
0x03 => self.run_sub(), // "SUB",
|
||||||
0x04 => self.run_div(), // "DIV",
|
0x04 => self.run_div(), // "DIV",
|
||||||
0x05 => self.run_sdiv(), // "SDIV",
|
0x05 => self.run_syscall(opcode, 2, false)?, // "SDIV",
|
||||||
0x06 => self.run_mod(), // "MOD",
|
0x06 => self.run_mod(), // "MOD",
|
||||||
0x07 => self.run_smod(), // "SMOD",
|
0x07 => self.run_syscall(opcode, 2, false)?, // "SMOD",
|
||||||
0x08 => self.run_addmod(), // "ADDMOD",
|
0x08 => self.run_addmod(), // "ADDMOD",
|
||||||
0x09 => self.run_mulmod(), // "MULMOD",
|
0x09 => self.run_mulmod(), // "MULMOD",
|
||||||
0x0a => self.run_exp(), // "EXP",
|
0x0a => self.run_syscall(opcode, 2, false)?, // "EXP",
|
||||||
0x0b => self.run_signextend(), // "SIGNEXTEND",
|
0x0b => self.run_syscall(opcode, 2, false)?, // "SIGNEXTEND",
|
||||||
0x0c => self.run_addfp254(), // "ADDFP254",
|
0x0c => self.run_addfp254(), // "ADDFP254",
|
||||||
0x0d => self.run_mulfp254(), // "MULFP254",
|
0x0d => self.run_mulfp254(), // "MULFP254",
|
||||||
0x0e => self.run_subfp254(), // "SUBFP254",
|
0x0e => self.run_subfp254(), // "SUBFP254",
|
||||||
0x0f => self.run_submod(), // "SUBMOD",
|
0x0f => self.run_submod(), // "SUBMOD",
|
||||||
0x10 => self.run_lt(), // "LT",
|
0x10 => self.run_lt(), // "LT",
|
||||||
0x11 => self.run_gt(), // "GT",
|
0x11 => self.run_gt(), // "GT",
|
||||||
0x12 => self.run_slt(), // "SLT",
|
0x12 => self.run_syscall(opcode, 2, false)?, // "SLT",
|
||||||
0x13 => self.run_sgt(), // "SGT",
|
0x13 => self.run_syscall(opcode, 2, false)?, // "SGT",
|
||||||
0x14 => self.run_eq(), // "EQ",
|
0x14 => self.run_eq(), // "EQ",
|
||||||
0x15 => self.run_iszero(), // "ISZERO",
|
0x15 => self.run_iszero(), // "ISZERO",
|
||||||
0x16 => self.run_and(), // "AND",
|
0x16 => self.run_and(), // "AND",
|
||||||
0x17 => self.run_or(), // "OR",
|
0x17 => self.run_or(), // "OR",
|
||||||
0x18 => self.run_xor(), // "XOR",
|
0x18 => self.run_xor(), // "XOR",
|
||||||
0x19 => self.run_not(), // "NOT",
|
0x19 => self.run_not(), // "NOT",
|
||||||
0x1a => self.run_byte(), // "BYTE",
|
0x1a => self.run_byte(), // "BYTE",
|
||||||
0x1b => self.run_shl(), // "SHL",
|
0x1b => self.run_shl(), // "SHL",
|
||||||
0x1c => self.run_shr(), // "SHR",
|
0x1c => self.run_shr(), // "SHR",
|
||||||
0x1d => self.run_sar(), // "SAR",
|
0x1d => self.run_syscall(opcode, 2, false)?, // "SAR",
|
||||||
0x20 => self.run_keccak256(), // "KECCAK256",
|
0x20 => self.run_syscall(opcode, 2, false)?, // "KECCAK256",
|
||||||
0x21 => self.run_keccak_general(), // "KECCAK_GENERAL",
|
0x21 => self.run_keccak_general(), // "KECCAK_GENERAL",
|
||||||
0x30 => self.run_address(), // "ADDRESS",
|
0x30 => self.run_syscall(opcode, 0, true)?, // "ADDRESS",
|
||||||
0x31 => self.run_syscall(opcode, 1, false)?, // "BALANCE",
|
0x31 => self.run_syscall(opcode, 1, false)?, // "BALANCE",
|
||||||
0x32 => self.run_origin(), // "ORIGIN",
|
0x32 => self.run_syscall(opcode, 0, true)?, // "ORIGIN",
|
||||||
0x33 => self.run_caller(), // "CALLER",
|
0x33 => self.run_syscall(opcode, 0, true)?, // "CALLER",
|
||||||
0x34 => self.run_callvalue(), // "CALLVALUE",
|
0x34 => self.run_syscall(opcode, 0, true)?, // "CALLVALUE",
|
||||||
0x35 => self.run_calldataload(), // "CALLDATALOAD",
|
0x35 => self.run_syscall(opcode, 1, false)?, // "CALLDATALOAD",
|
||||||
0x36 => self.run_calldatasize(), // "CALLDATASIZE",
|
0x36 => self.run_syscall(opcode, 0, true)?, // "CALLDATASIZE",
|
||||||
0x37 => self.run_calldatacopy(), // "CALLDATACOPY",
|
0x37 => self.run_syscall(opcode, 3, false)?, // "CALLDATACOPY",
|
||||||
0x38 => self.run_codesize(), // "CODESIZE",
|
0x38 => self.run_syscall(opcode, 0, true)?, // "CODESIZE",
|
||||||
0x39 => self.run_codecopy(), // "CODECOPY",
|
0x39 => self.run_syscall(opcode, 3, false)?, // "CODECOPY",
|
||||||
0x3a => self.run_gasprice(), // "GASPRICE",
|
0x3a => self.run_syscall(opcode, 0, true)?, // "GASPRICE",
|
||||||
0x3b => self.run_syscall(opcode, 1, false)?, // "EXTCODESIZE",
|
0x3b => self.run_syscall(opcode, 1, false)?, // "EXTCODESIZE",
|
||||||
0x3c => self.run_syscall(opcode, 4, false)?, // "EXTCODECOPY",
|
0x3c => self.run_syscall(opcode, 4, false)?, // "EXTCODECOPY",
|
||||||
0x3d => self.run_returndatasize(), // "RETURNDATASIZE",
|
0x3d => self.run_syscall(opcode, 0, true)?, // "RETURNDATASIZE",
|
||||||
0x3e => self.run_returndatacopy(), // "RETURNDATACOPY",
|
0x3e => self.run_syscall(opcode, 3, false)?, // "RETURNDATACOPY",
|
||||||
0x3f => self.run_syscall(opcode, 1, false)?, // "EXTCODEHASH",
|
0x3f => self.run_syscall(opcode, 1, false)?, // "EXTCODEHASH",
|
||||||
0x40 => self.run_syscall(opcode, 1, false)?, // "BLOCKHASH",
|
0x40 => self.run_syscall(opcode, 1, false)?, // "BLOCKHASH",
|
||||||
0x41 => self.run_coinbase(), // "COINBASE",
|
0x41 => self.run_syscall(opcode, 0, true)?, // "COINBASE",
|
||||||
0x42 => self.run_timestamp(), // "TIMESTAMP",
|
0x42 => self.run_syscall(opcode, 0, true)?, // "TIMESTAMP",
|
||||||
0x43 => self.run_number(), // "NUMBER",
|
0x43 => self.run_syscall(opcode, 0, true)?, // "NUMBER",
|
||||||
0x44 => self.run_difficulty(), // "DIFFICULTY",
|
0x44 => self.run_syscall(opcode, 0, true)?, // "DIFFICULTY",
|
||||||
0x45 => self.run_gaslimit(), // "GASLIMIT",
|
0x45 => self.run_syscall(opcode, 0, true)?, // "GASLIMIT",
|
||||||
0x46 => self.run_chainid(), // "CHAINID",
|
0x46 => self.run_syscall(opcode, 0, true)?, // "CHAINID",
|
||||||
0x48 => self.run_basefee(), // "BASEFEE",
|
0x47 => self.run_syscall(opcode, 0, true)?, // SELFABALANCE,
|
||||||
0x49 => self.run_prover_input()?, // "PROVER_INPUT",
|
0x48 => self.run_syscall(opcode, 0, true)?, // "BASEFEE",
|
||||||
0x50 => self.run_pop(), // "POP",
|
0x49 => self.run_prover_input()?, // "PROVER_INPUT",
|
||||||
0x51 => self.run_mload(), // "MLOAD",
|
0x50 => self.run_pop(), // "POP",
|
||||||
0x52 => self.run_mstore(), // "MSTORE",
|
0x51 => self.run_syscall(opcode, 1, false)?, // "MLOAD",
|
||||||
0x53 => self.run_mstore8(), // "MSTORE8",
|
0x52 => self.run_syscall(opcode, 2, false)?, // "MSTORE",
|
||||||
0x54 => self.run_syscall(opcode, 1, false)?, // "SLOAD",
|
0x53 => self.run_syscall(opcode, 2, false)?, // "MSTORE8",
|
||||||
0x55 => self.run_syscall(opcode, 2, false)?, // "SSTORE",
|
0x54 => self.run_syscall(opcode, 1, false)?, // "SLOAD",
|
||||||
0x56 => self.run_jump(), // "JUMP",
|
0x55 => self.run_syscall(opcode, 2, false)?, // "SSTORE",
|
||||||
0x57 => self.run_jumpi(), // "JUMPI",
|
0x56 => self.run_jump(), // "JUMP",
|
||||||
0x58 => self.run_pc(), // "PC",
|
0x57 => self.run_jumpi(), // "JUMPI",
|
||||||
0x59 => self.run_msize(), // "MSIZE",
|
0x58 => self.run_pc(), // "PC",
|
||||||
0x5a => self.run_syscall(opcode, 0, true)?, // "GAS",
|
0x59 => self.run_syscall(opcode, 0, true)?, // "MSIZE",
|
||||||
0x5b => self.run_jumpdest(), // "JUMPDEST",
|
0x5a => self.run_syscall(opcode, 0, true)?, // "GAS",
|
||||||
x if (0x5f..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH"
|
0x5b => self.run_jumpdest(), // "JUMPDEST",
|
||||||
x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f)?, // "DUP"
|
x if (0x5f..0x80).contains(&x) => self.run_push(x - 0x5f), // "PUSH"
|
||||||
|
x if (0x80..0x90).contains(&x) => self.run_dup(x - 0x7f)?, // "DUP"
|
||||||
x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f)?, // "SWAP"
|
x if (0x90..0xa0).contains(&x) => self.run_swap(x - 0x8f)?, // "SWAP"
|
||||||
0xa0 => self.run_syscall(opcode, 2, false)?, // "LOG0",
|
0xa0 => self.run_syscall(opcode, 2, false)?, // "LOG0",
|
||||||
0xa1 => self.run_syscall(opcode, 3, false)?, // "LOG1",
|
0xa1 => self.run_syscall(opcode, 3, false)?, // "LOG1",
|
||||||
0xa2 => self.run_syscall(opcode, 4, false)?, // "LOG2",
|
0xa2 => self.run_syscall(opcode, 4, false)?, // "LOG2",
|
||||||
0xa3 => self.run_syscall(opcode, 5, false)?, // "LOG3",
|
0xa3 => self.run_syscall(opcode, 5, false)?, // "LOG3",
|
||||||
0xa4 => self.run_syscall(opcode, 6, false)?, // "LOG4",
|
0xa4 => self.run_syscall(opcode, 6, false)?, // "LOG4",
|
||||||
0xa5 => bail!(
|
0xa5 => bail!(
|
||||||
"Executed PANIC, stack={:?}, memory={:?}",
|
"Executed PANIC, stack={:?}, memory={:?}",
|
||||||
self.stack(),
|
self.stack(),
|
||||||
@ -471,10 +493,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
KERNEL.offset_label(self.generation_state.registers.program_counter)
|
KERNEL.offset_label(self.generation_state.registers.program_counter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_stop(&mut self) {
|
|
||||||
self.running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_add(&mut self) {
|
fn run_add(&mut self) {
|
||||||
let x = self.pop();
|
let x = self.pop();
|
||||||
let y = self.pop();
|
let y = self.pop();
|
||||||
@ -522,75 +540,12 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.push(if y.is_zero() { U256::zero() } else { x / y });
|
self.push(if y.is_zero() { U256::zero() } else { x / y });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sdiv(&mut self) {
|
|
||||||
let mut x = self.pop();
|
|
||||||
let mut y = self.pop();
|
|
||||||
|
|
||||||
let y_is_zero = y.is_zero();
|
|
||||||
|
|
||||||
if y_is_zero {
|
|
||||||
self.push(U256::zero());
|
|
||||||
} else if y.eq(&MINUS_ONE) && x.eq(&MIN_VALUE) {
|
|
||||||
self.push(MIN_VALUE);
|
|
||||||
} else {
|
|
||||||
let x_is_pos = x.eq(&(x & SIGN_MASK));
|
|
||||||
let y_is_pos = y.eq(&(y & SIGN_MASK));
|
|
||||||
|
|
||||||
// We compute the absolute quotient first,
|
|
||||||
// then adapt its sign based on the operands.
|
|
||||||
if !x_is_pos {
|
|
||||||
x = two_complement(x);
|
|
||||||
}
|
|
||||||
if !y_is_pos {
|
|
||||||
y = two_complement(y);
|
|
||||||
}
|
|
||||||
let div = x / y;
|
|
||||||
if div.eq(&U256::zero()) {
|
|
||||||
self.push(U256::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.push(if x_is_pos == y_is_pos {
|
|
||||||
div
|
|
||||||
} else {
|
|
||||||
two_complement(div)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_mod(&mut self) {
|
fn run_mod(&mut self) {
|
||||||
let x = self.pop();
|
let x = self.pop();
|
||||||
let y = self.pop();
|
let y = self.pop();
|
||||||
self.push(if y.is_zero() { U256::zero() } else { x % y });
|
self.push(if y.is_zero() { U256::zero() } else { x % y });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_smod(&mut self) {
|
|
||||||
let mut x = self.pop();
|
|
||||||
let mut y = self.pop();
|
|
||||||
|
|
||||||
if y.is_zero() {
|
|
||||||
self.push(U256::zero());
|
|
||||||
} else {
|
|
||||||
let x_is_pos = x.eq(&(x & SIGN_MASK));
|
|
||||||
let y_is_pos = y.eq(&(y & SIGN_MASK));
|
|
||||||
|
|
||||||
// We compute the absolute remainder first,
|
|
||||||
// then adapt its sign based on the operands.
|
|
||||||
if !x_is_pos {
|
|
||||||
x = two_complement(x);
|
|
||||||
}
|
|
||||||
if !y_is_pos {
|
|
||||||
y = two_complement(y);
|
|
||||||
}
|
|
||||||
let rem = x % y;
|
|
||||||
if rem.eq(&U256::zero()) {
|
|
||||||
self.push(U256::zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remainder always has the same sign as the dividend.
|
|
||||||
self.push(if x_is_pos { rem } else { two_complement(rem) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_addmod(&mut self) {
|
fn run_addmod(&mut self) {
|
||||||
let x = self.pop();
|
let x = self.pop();
|
||||||
let y = self.pop();
|
let y = self.pop();
|
||||||
@ -629,12 +584,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_exp(&mut self) {
|
|
||||||
let x = self.pop();
|
|
||||||
let y = self.pop();
|
|
||||||
self.push(x.overflowing_pow(y).0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_lt(&mut self) {
|
fn run_lt(&mut self) {
|
||||||
let x = self.pop();
|
let x = self.pop();
|
||||||
let y = self.pop();
|
let y = self.pop();
|
||||||
@ -647,43 +596,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.push_bool(x > y);
|
self.push_bool(x > y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_slt(&mut self) {
|
|
||||||
let x = self.pop();
|
|
||||||
let y = self.pop();
|
|
||||||
self.push_bool(signed_cmp(x, y) == Ordering::Less);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_sgt(&mut self) {
|
|
||||||
let x = self.pop();
|
|
||||||
let y = self.pop();
|
|
||||||
self.push_bool(signed_cmp(x, y) == Ordering::Greater);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_signextend(&mut self) {
|
|
||||||
let n = self.pop();
|
|
||||||
let x = self.pop();
|
|
||||||
if n > U256::from(31) {
|
|
||||||
self.push(x);
|
|
||||||
} else {
|
|
||||||
let n = n.low_u64() as usize;
|
|
||||||
let num_bytes_prepend = 31 - n;
|
|
||||||
|
|
||||||
let mut x_bytes = [0u8; 32];
|
|
||||||
x.to_big_endian(&mut x_bytes);
|
|
||||||
let x_bytes = x_bytes[num_bytes_prepend..].to_vec();
|
|
||||||
let sign_bit = x_bytes[0] >> 7;
|
|
||||||
|
|
||||||
let mut bytes = if sign_bit == 0 {
|
|
||||||
vec![0; num_bytes_prepend]
|
|
||||||
} else {
|
|
||||||
vec![0xff; num_bytes_prepend]
|
|
||||||
};
|
|
||||||
bytes.extend_from_slice(&x_bytes);
|
|
||||||
|
|
||||||
self.push(U256::from_big_endian(&bytes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_eq(&mut self) {
|
fn run_eq(&mut self) {
|
||||||
let x = self.pop();
|
let x = self.pop();
|
||||||
let y = self.pop();
|
let y = self.pop();
|
||||||
@ -745,45 +657,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.push(value >> shift);
|
self.push(value >> shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_sar(&mut self) {
|
|
||||||
let shift = self.pop();
|
|
||||||
let value = self.pop();
|
|
||||||
let value_is_neg = !value.eq(&(value & SIGN_MASK));
|
|
||||||
|
|
||||||
if shift < U256::from(256usize) {
|
|
||||||
let shift = shift.low_u64() as usize;
|
|
||||||
let mask = !(MINUS_ONE >> shift);
|
|
||||||
let value_shifted = value >> shift;
|
|
||||||
|
|
||||||
if value_is_neg {
|
|
||||||
self.push(value_shifted | mask);
|
|
||||||
} else {
|
|
||||||
self.push(value_shifted);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
self.push(if value_is_neg {
|
|
||||||
MINUS_ONE
|
|
||||||
} else {
|
|
||||||
U256::zero()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_keccak256(&mut self) {
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let size = self.pop().as_usize();
|
|
||||||
let bytes = (offset..offset + size)
|
|
||||||
.map(|i| {
|
|
||||||
self.generation_state
|
|
||||||
.memory
|
|
||||||
.mload_general(self.context, Segment::MainMemory, i)
|
|
||||||
.byte(0)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let hash = keccak(bytes);
|
|
||||||
self.push(U256::from_big_endian(hash.as_bytes()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_keccak_general(&mut self) {
|
fn run_keccak_general(&mut self) {
|
||||||
let context = self.pop().as_usize();
|
let context = self.pop().as_usize();
|
||||||
let segment = Segment::all()[self.pop().as_usize()];
|
let segment = Segment::all()[self.pop().as_usize()];
|
||||||
@ -804,161 +677,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.push(U256::from_big_endian(hash.as_bytes()));
|
self.push(U256::from_big_endian(hash.as_bytes()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_address(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::Address as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_origin(&mut self) {
|
|
||||||
self.push(self.get_txn_field(NormalizedTxnField::Origin))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_caller(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::Caller as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_callvalue(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::CallValue as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_calldataload(&mut self) {
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let value = U256::from_big_endian(
|
|
||||||
&(0..32)
|
|
||||||
.map(|i| {
|
|
||||||
self.generation_state
|
|
||||||
.memory
|
|
||||||
.mload_general(self.context, Segment::Calldata, offset + i)
|
|
||||||
.byte(0)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
);
|
|
||||||
self.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_calldatasize(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::CalldataSize as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_calldatacopy(&mut self) {
|
|
||||||
let dest_offset = self.pop().as_usize();
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let size = self.pop().as_usize();
|
|
||||||
for i in 0..size {
|
|
||||||
let calldata_byte = self.generation_state.memory.mload_general(
|
|
||||||
self.context,
|
|
||||||
Segment::Calldata,
|
|
||||||
offset + i,
|
|
||||||
);
|
|
||||||
self.generation_state.memory.mstore_general(
|
|
||||||
self.context,
|
|
||||||
Segment::MainMemory,
|
|
||||||
dest_offset + i,
|
|
||||||
calldata_byte,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_codesize(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::CodeSize as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_codecopy(&mut self) {
|
|
||||||
let dest_offset = self.pop().as_usize();
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let size = self.pop().as_usize();
|
|
||||||
for i in 0..size {
|
|
||||||
let code_byte =
|
|
||||||
self.generation_state
|
|
||||||
.memory
|
|
||||||
.mload_general(self.context, Segment::Code, offset + i);
|
|
||||||
self.generation_state.memory.mstore_general(
|
|
||||||
self.context,
|
|
||||||
Segment::MainMemory,
|
|
||||||
dest_offset + i,
|
|
||||||
code_byte,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_gasprice(&mut self) {
|
|
||||||
self.push(self.get_txn_field(NormalizedTxnField::ComputedFeePerGas))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_returndatasize(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::ReturndataSize as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_returndatacopy(&mut self) {
|
|
||||||
let dest_offset = self.pop().as_usize();
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let size = self.pop().as_usize();
|
|
||||||
for i in 0..size {
|
|
||||||
let returndata_byte = self.generation_state.memory.mload_general(
|
|
||||||
self.context,
|
|
||||||
Segment::Returndata,
|
|
||||||
offset + i,
|
|
||||||
);
|
|
||||||
self.generation_state.memory.mstore_general(
|
|
||||||
self.context,
|
|
||||||
Segment::MainMemory,
|
|
||||||
dest_offset + i,
|
|
||||||
returndata_byte,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_coinbase(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockBeneficiary))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_timestamp(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockTimestamp))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_number(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockNumber))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_difficulty(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockDifficulty))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_gaslimit(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockGasLimit))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_basefee(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockBaseFee))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_chainid(&mut self) {
|
|
||||||
self.push(self.get_global_metadata_field(GlobalMetadata::BlockChainId))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_prover_input(&mut self) -> anyhow::Result<()> {
|
fn run_prover_input(&mut self) -> anyhow::Result<()> {
|
||||||
let prover_input_fn = self
|
let prover_input_fn = self
|
||||||
.prover_inputs_map
|
.prover_inputs_map
|
||||||
@ -976,47 +694,6 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.pop();
|
self.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mload(&mut self) {
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let value = U256::from_big_endian(
|
|
||||||
&(0..32)
|
|
||||||
.map(|i| {
|
|
||||||
self.generation_state
|
|
||||||
.memory
|
|
||||||
.mload_general(self.context, Segment::MainMemory, offset + i)
|
|
||||||
.byte(0)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
);
|
|
||||||
self.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_mstore(&mut self) {
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let value = self.pop();
|
|
||||||
let mut bytes = [0; 32];
|
|
||||||
value.to_big_endian(&mut bytes);
|
|
||||||
for (i, byte) in (0..32).zip(bytes) {
|
|
||||||
self.generation_state.memory.mstore_general(
|
|
||||||
self.context,
|
|
||||||
Segment::MainMemory,
|
|
||||||
offset + i,
|
|
||||||
byte.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_mstore8(&mut self) {
|
|
||||||
let offset = self.pop().as_usize();
|
|
||||||
let value = self.pop();
|
|
||||||
self.generation_state.memory.mstore_general(
|
|
||||||
self.context,
|
|
||||||
Segment::MainMemory,
|
|
||||||
offset,
|
|
||||||
value.byte(0).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_syscall(
|
fn run_syscall(
|
||||||
&mut self,
|
&mut self,
|
||||||
opcode: u8,
|
opcode: u8,
|
||||||
@ -1030,7 +707,7 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stack_len_increased
|
if stack_len_increased
|
||||||
&& !self.generation_state.registers.is_kernel
|
&& !self.is_kernel()
|
||||||
&& self.generation_state.registers.stack_len >= MAX_USER_STACK_SIZE
|
&& self.generation_state.registers.stack_len >= MAX_USER_STACK_SIZE
|
||||||
{
|
{
|
||||||
return Err(anyhow!("Stack overflow"));
|
return Err(anyhow!("Stack overflow"));
|
||||||
@ -1048,12 +725,11 @@ impl<'a> Interpreter<'a> {
|
|||||||
u256_to_usize(handler_addr).map_err(|_| anyhow!("The program counter is too large"))?;
|
u256_to_usize(handler_addr).map_err(|_| anyhow!("The program counter is too large"))?;
|
||||||
|
|
||||||
let syscall_info = U256::from(self.generation_state.registers.program_counter)
|
let syscall_info = U256::from(self.generation_state.registers.program_counter)
|
||||||
+ U256::from((self.generation_state.registers.is_kernel as usize) << 32)
|
+ U256::from((self.is_kernel() as usize) << 32)
|
||||||
+ (U256::from(self.generation_state.registers.gas_used) << 192);
|
+ (U256::from(self.generation_state.registers.gas_used) << 192);
|
||||||
self.generation_state.registers.program_counter = new_program_counter;
|
self.generation_state.registers.program_counter = new_program_counter;
|
||||||
|
|
||||||
self.generation_state.registers.is_kernel = true;
|
self.set_is_kernel(true);
|
||||||
self.kernel_mode = true;
|
|
||||||
self.generation_state.registers.gas_used = 0;
|
self.generation_state.registers.gas_used = 0;
|
||||||
self.push(syscall_info);
|
self.push(syscall_info);
|
||||||
|
|
||||||
@ -1084,21 +760,13 @@ impl<'a> Interpreter<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_msize(&mut self) {
|
|
||||||
self.push(
|
|
||||||
self.generation_state.memory.contexts[self.context].segments
|
|
||||||
[Segment::ContextMetadata as usize]
|
|
||||||
.get(ContextMetadata::MemWords as usize),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_jumpdest(&mut self) {
|
fn run_jumpdest(&mut self) {
|
||||||
assert!(!self.kernel_mode, "JUMPDEST is not needed in kernel code");
|
assert!(!self.is_kernel(), "JUMPDEST is not needed in kernel code");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn jump_to(&mut self, offset: usize) {
|
fn jump_to(&mut self, offset: usize) {
|
||||||
// The JUMPDEST rule is not enforced in kernel mode.
|
// The JUMPDEST rule is not enforced in kernel mode.
|
||||||
if !self.kernel_mode && self.jumpdests.binary_search(&offset).is_err() {
|
if !self.is_kernel() && self.jumpdests.binary_search(&offset).is_err() {
|
||||||
panic!("Destination is not a JUMPDEST.");
|
panic!("Destination is not a JUMPDEST.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,14 +784,13 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_dup(&mut self, n: u8) -> anyhow::Result<()> {
|
fn run_dup(&mut self, n: u8) -> anyhow::Result<()> {
|
||||||
if n == 0 {
|
assert!(n > 0);
|
||||||
self.push(self.stack_top());
|
|
||||||
} else {
|
self.push(
|
||||||
self.push(
|
stack_peek(&self.generation_state, n as usize - 1)
|
||||||
stack_peek(&self.generation_state, n as usize - 1)
|
.map_err(|_| anyhow!("Stack underflow."))?,
|
||||||
.map_err(|_| anyhow!("Stack underflow."))?,
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1132,18 +799,40 @@ impl<'a> Interpreter<'a> {
|
|||||||
ensure!(len > n as usize);
|
ensure!(len > n as usize);
|
||||||
let to_swap = stack_peek(&self.generation_state, n as usize)
|
let to_swap = stack_peek(&self.generation_state, n as usize)
|
||||||
.map_err(|_| anyhow!("Stack underflow"))?;
|
.map_err(|_| anyhow!("Stack underflow"))?;
|
||||||
self.stack_segment_mut()[len - n as usize - 1] = self.stack_top();
|
let old_value = self.stack_segment_mut()[len - n as usize - 1];
|
||||||
|
self.stack_segment_mut()[len - n as usize - 1] = self
|
||||||
|
.stack_top()
|
||||||
|
.expect("The stack is checked to be nonempty.");
|
||||||
self.generation_state.registers.stack_top = to_swap;
|
self.generation_state.registers.stack_top = to_swap;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_get_context(&mut self) {
|
fn run_get_context(&mut self) {
|
||||||
self.push(self.context.into());
|
self.push(self.context().into());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_set_context(&mut self) {
|
fn run_set_context(&mut self) {
|
||||||
let x = self.pop();
|
let new_ctx = self.pop().as_usize();
|
||||||
self.context = x.as_usize();
|
let sp_to_save = self.stack_len().into();
|
||||||
|
|
||||||
|
let old_ctx = self.context();
|
||||||
|
|
||||||
|
let sp_field = ContextMetadata::StackSize as usize;
|
||||||
|
|
||||||
|
let old_sp_addr = MemoryAddress::new(old_ctx, Segment::ContextMetadata, sp_field);
|
||||||
|
let new_sp_addr = MemoryAddress::new(new_ctx, Segment::ContextMetadata, sp_field);
|
||||||
|
self.generation_state.memory.set(old_sp_addr, sp_to_save);
|
||||||
|
|
||||||
|
let new_sp = self.generation_state.memory.get(new_sp_addr).as_usize();
|
||||||
|
|
||||||
|
if new_sp > 0 {
|
||||||
|
let new_stack_top = self.generation_state.memory.contexts[new_ctx].segments
|
||||||
|
[Segment::Stack as usize]
|
||||||
|
.content[new_sp - 1];
|
||||||
|
self.generation_state.registers.stack_top = new_stack_top;
|
||||||
|
}
|
||||||
|
self.set_context(new_ctx);
|
||||||
|
self.generation_state.registers.stack_len = new_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_mload_general(&mut self) {
|
fn run_mload_general(&mut self) {
|
||||||
@ -1219,8 +908,7 @@ impl<'a> Interpreter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.generation_state.registers.program_counter = program_counter;
|
self.generation_state.registers.program_counter = program_counter;
|
||||||
self.generation_state.registers.is_kernel = is_kernel_mode;
|
self.set_is_kernel(is_kernel_mode);
|
||||||
self.kernel_mode = is_kernel_mode;
|
|
||||||
self.generation_state.registers.gas_used = gas_used_val;
|
self.generation_state.registers.gas_used = gas_used_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,8 +916,31 @@ impl<'a> Interpreter<'a> {
|
|||||||
self.generation_state.registers.stack_len
|
self.generation_state.registers.stack_len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn stack_top(&self) -> U256 {
|
pub(crate) fn stack_top(&self) -> anyhow::Result<U256> {
|
||||||
self.generation_state.registers.stack_top
|
if self.stack_len() > 0 {
|
||||||
|
Ok(self.generation_state.registers.stack_top)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Stack underflow"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_kernel(&self) -> bool {
|
||||||
|
self.generation_state.registers.is_kernel
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_is_kernel(&mut self, is_kernel: bool) {
|
||||||
|
self.generation_state.registers.is_kernel = is_kernel
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn context(&self) -> usize {
|
||||||
|
self.generation_state.registers.context
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_context(&mut self, context: usize) {
|
||||||
|
if context == 0 {
|
||||||
|
assert!(self.is_kernel());
|
||||||
|
}
|
||||||
|
self.generation_state.registers.context = context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1511,8 +1222,10 @@ fn get_mnemonic(opcode: u8) -> &'static str {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::cpu::kernel::interpreter::run;
|
use crate::cpu::kernel::constants::context_metadata::ContextMetadata;
|
||||||
|
use crate::cpu::kernel::interpreter::{run, Interpreter};
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
|
use crate::witness::memory::MemoryAddress;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_run() -> anyhow::Result<()> {
|
fn test_run() -> anyhow::Result<()> {
|
||||||
@ -1541,20 +1254,51 @@ mod tests {
|
|||||||
// PUSH1 0x42
|
// PUSH1 0x42
|
||||||
// PUSH1 0x27
|
// PUSH1 0x27
|
||||||
// MSTORE8
|
// MSTORE8
|
||||||
let code = vec![
|
let code = [
|
||||||
0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27,
|
0x60, 0xff, 0x60, 0x0, 0x52, 0x60, 0, 0x51, 0x60, 0x1, 0x51, 0x60, 0x42, 0x60, 0x27,
|
||||||
0x53,
|
0x53,
|
||||||
];
|
];
|
||||||
let pis = HashMap::new();
|
let mut interpreter = Interpreter::new_with_kernel(0, vec![]);
|
||||||
let run = run(&code, 0, vec![], &pis)?;
|
|
||||||
assert_eq!(run.stack(), &[0xff.into(), 0xff00.into()]);
|
interpreter.set_code(1, code.to_vec());
|
||||||
|
|
||||||
|
interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize]
|
||||||
|
.set(ContextMetadata::GasLimit as usize, 100_000.into());
|
||||||
|
// Set context and kernel mode.
|
||||||
|
interpreter.set_context(1);
|
||||||
|
interpreter.set_is_kernel(false);
|
||||||
|
// Set memory necessary to sys_stop.
|
||||||
|
interpreter.generation_state.memory.set(
|
||||||
|
MemoryAddress::new(
|
||||||
|
1,
|
||||||
|
Segment::ContextMetadata,
|
||||||
|
ContextMetadata::ParentProgramCounter as usize,
|
||||||
|
),
|
||||||
|
0xdeadbeefu32.into(),
|
||||||
|
);
|
||||||
|
interpreter.generation_state.memory.set(
|
||||||
|
MemoryAddress::new(
|
||||||
|
1,
|
||||||
|
Segment::ContextMetadata,
|
||||||
|
ContextMetadata::ParentContext as usize,
|
||||||
|
),
|
||||||
|
1.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
interpreter.run()?;
|
||||||
|
|
||||||
|
// sys_stop returns `success` and `cum_gas_used`, that we need to pop.
|
||||||
|
interpreter.pop();
|
||||||
|
interpreter.pop();
|
||||||
|
|
||||||
|
assert_eq!(interpreter.stack(), &[0xff.into(), 0xff00.into()]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run.generation_state.memory.contexts[0].segments[Segment::MainMemory as usize]
|
interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory as usize]
|
||||||
.get(0x27),
|
.get(0x27),
|
||||||
0x42.into()
|
0x42.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run.generation_state.memory.contexts[0].segments[Segment::MainMemory as usize]
|
interpreter.generation_state.memory.contexts[1].segments[Segment::MainMemory as usize]
|
||||||
.get(0x1f),
|
.get(0x1f),
|
||||||
0xff.into()
|
0xff.into()
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use crate::cpu::kernel::tests::mpt::nibbles_64;
|
|||||||
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
|
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp};
|
||||||
use crate::generation::TrieInputs;
|
use crate::generation::TrieInputs;
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
|
use crate::witness::memory::MemoryAddress;
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
// Test account with a given code hash.
|
// Test account with a given code hash.
|
||||||
@ -146,19 +147,20 @@ fn test_extcodecopy() -> Result<()> {
|
|||||||
// Prepare the interpreter by inserting the account in the state trie.
|
// Prepare the interpreter by inserting the account in the state trie.
|
||||||
prepare_interpreter(&mut interpreter, address, &account)?;
|
prepare_interpreter(&mut interpreter, address, &account)?;
|
||||||
|
|
||||||
interpreter.generation_state.memory.contexts[interpreter.context].segments
|
let context = interpreter.context();
|
||||||
|
interpreter.generation_state.memory.contexts[context].segments
|
||||||
[Segment::ContextMetadata as usize]
|
[Segment::ContextMetadata as usize]
|
||||||
.set(GasLimit as usize, U256::from(1000000000000u64) << 192);
|
.set(GasLimit as usize, U256::from(1000000000000u64));
|
||||||
|
|
||||||
let extcodecopy = KERNEL.global_labels["sys_extcodecopy"];
|
let extcodecopy = KERNEL.global_labels["sys_extcodecopy"];
|
||||||
|
|
||||||
// Put random data in main memory and the `KernelAccountCode` segment for realism.
|
// Put random data in main memory and the `KernelAccountCode` segment for realism.
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
for i in 0..2000 {
|
for i in 0..2000 {
|
||||||
interpreter.generation_state.memory.contexts[interpreter.context].segments
|
interpreter.generation_state.memory.contexts[context].segments
|
||||||
[Segment::MainMemory as usize]
|
[Segment::MainMemory as usize]
|
||||||
.set(i, U256::from(rng.gen::<u8>()));
|
.set(i, U256::from(rng.gen::<u8>()));
|
||||||
interpreter.generation_state.memory.contexts[interpreter.context].segments
|
interpreter.generation_state.memory.contexts[context].segments
|
||||||
[Segment::KernelAccountCode as usize]
|
[Segment::KernelAccountCode as usize]
|
||||||
.set(i, U256::from(rng.gen::<u8>()));
|
.set(i, U256::from(rng.gen::<u8>()));
|
||||||
}
|
}
|
||||||
@ -176,7 +178,7 @@ fn test_extcodecopy() -> Result<()> {
|
|||||||
interpreter.push(offset.into());
|
interpreter.push(offset.into());
|
||||||
interpreter.push(dest_offset.into());
|
interpreter.push(dest_offset.into());
|
||||||
interpreter.push(U256::from_big_endian(address.as_bytes()));
|
interpreter.push(U256::from_big_endian(address.as_bytes()));
|
||||||
interpreter.push(0xDEADBEEFu32.into()); // kexit_info
|
interpreter.push((0xDEADBEEFu64 + (1 << 32)).into()); // kexit_info
|
||||||
interpreter.generation_state.inputs.contract_code =
|
interpreter.generation_state.inputs.contract_code =
|
||||||
HashMap::from([(keccak(&code), code.clone())]);
|
HashMap::from([(keccak(&code), code.clone())]);
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
@ -184,7 +186,7 @@ fn test_extcodecopy() -> Result<()> {
|
|||||||
assert!(interpreter.stack().is_empty());
|
assert!(interpreter.stack().is_empty());
|
||||||
// Check that the code was correctly copied to memory.
|
// Check that the code was correctly copied to memory.
|
||||||
for i in 0..size {
|
for i in 0..size {
|
||||||
let memory = interpreter.generation_state.memory.contexts[interpreter.context].segments
|
let memory = interpreter.generation_state.memory.contexts[context].segments
|
||||||
[Segment::MainMemory as usize]
|
[Segment::MainMemory as usize]
|
||||||
.get(dest_offset + i);
|
.get(dest_offset + i);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -226,10 +228,24 @@ fn prepare_interpreter_all_accounts(
|
|||||||
);
|
);
|
||||||
interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize]
|
interpreter.generation_state.memory.contexts[1].segments[Segment::ContextMetadata as usize]
|
||||||
.set(ContextMetadata::GasLimit as usize, 100_000.into());
|
.set(ContextMetadata::GasLimit as usize, 100_000.into());
|
||||||
interpreter.context = 1;
|
interpreter.set_context(1);
|
||||||
interpreter.generation_state.registers.context = 1;
|
interpreter.set_is_kernel(false);
|
||||||
interpreter.generation_state.registers.is_kernel = false;
|
interpreter.generation_state.memory.set(
|
||||||
interpreter.kernel_mode = false;
|
MemoryAddress::new(
|
||||||
|
1,
|
||||||
|
Segment::ContextMetadata,
|
||||||
|
ContextMetadata::ParentProgramCounter as usize,
|
||||||
|
),
|
||||||
|
0xdeadbeefu32.into(),
|
||||||
|
);
|
||||||
|
interpreter.generation_state.memory.set(
|
||||||
|
MemoryAddress::new(
|
||||||
|
1,
|
||||||
|
Segment::ContextMetadata,
|
||||||
|
ContextMetadata::ParentContext as usize,
|
||||||
|
),
|
||||||
|
1.into(),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -272,6 +288,11 @@ fn sstore() -> Result<()> {
|
|||||||
|
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
|
|
||||||
|
// The first two elements in the stack are `success` and `leftover_gas`,
|
||||||
|
// returned by the `sys_stop` opcode.
|
||||||
|
interpreter.pop();
|
||||||
|
interpreter.pop();
|
||||||
|
|
||||||
// The code should have added an element to the storage of `to_account`. We run
|
// The code should have added an element to the storage of `to_account`. We run
|
||||||
// `mpt_hash_state_trie` to check that.
|
// `mpt_hash_state_trie` to check that.
|
||||||
let account_after = AccountRlp {
|
let account_after = AccountRlp {
|
||||||
@ -287,10 +308,8 @@ fn sstore() -> Result<()> {
|
|||||||
// Now, execute mpt_hash_state_trie.
|
// Now, execute mpt_hash_state_trie.
|
||||||
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
|
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
|
||||||
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
|
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
|
||||||
interpreter.context = 0;
|
interpreter.set_is_kernel(true);
|
||||||
interpreter.generation_state.registers.context = 0;
|
interpreter.set_context(0);
|
||||||
interpreter.generation_state.registers.is_kernel = true;
|
|
||||||
interpreter.kernel_mode = true;
|
|
||||||
interpreter.push(0xDEADBEEFu32.into());
|
interpreter.push(0xDEADBEEFu32.into());
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
|
|
||||||
@ -353,6 +372,11 @@ fn sload() -> Result<()> {
|
|||||||
|
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
|
|
||||||
|
// The first two elements in the stack are `success` and `leftover_gas`,
|
||||||
|
// returned by the `sys_stop` opcode.
|
||||||
|
interpreter.pop();
|
||||||
|
interpreter.pop();
|
||||||
|
|
||||||
// The SLOAD in the provided code should return 0, since
|
// The SLOAD in the provided code should return 0, since
|
||||||
// the storage trie is empty. The last step in the code
|
// the storage trie is empty. The last step in the code
|
||||||
// pushes the value 3.
|
// pushes the value 3.
|
||||||
@ -362,10 +386,8 @@ fn sload() -> Result<()> {
|
|||||||
// Now, execute mpt_hash_state_trie. We check that the state trie has not changed.
|
// Now, execute mpt_hash_state_trie. We check that the state trie has not changed.
|
||||||
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
|
let mpt_hash_state_trie = KERNEL.global_labels["mpt_hash_state_trie"];
|
||||||
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
|
interpreter.generation_state.registers.program_counter = mpt_hash_state_trie;
|
||||||
interpreter.context = 0;
|
interpreter.set_is_kernel(true);
|
||||||
interpreter.generation_state.registers.context = 0;
|
interpreter.set_context(0);
|
||||||
interpreter.generation_state.registers.is_kernel = true;
|
|
||||||
interpreter.kernel_mode = true;
|
|
||||||
interpreter.push(0xDEADBEEFu32.into());
|
interpreter.push(0xDEADBEEFu32.into());
|
||||||
interpreter.run()?;
|
interpreter.run()?;
|
||||||
|
|
||||||
|
|||||||
212
evm/src/cpu/kernel/tests/add11.rs
Normal file
212
evm/src/cpu/kernel/tests/add11.rs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use eth_trie_utils::nibbles::Nibbles;
|
||||||
|
use eth_trie_utils::partial_trie::{HashedPartialTrie, Node, PartialTrie};
|
||||||
|
use ethereum_types::{Address, H256, U256};
|
||||||
|
use hex_literal::hex;
|
||||||
|
use keccak_hash::keccak;
|
||||||
|
|
||||||
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
|
use crate::cpu::kernel::constants::context_metadata::ContextMetadata;
|
||||||
|
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||||
|
use crate::cpu::kernel::interpreter::Interpreter;
|
||||||
|
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, AccountRlp, LegacyReceiptRlp};
|
||||||
|
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
|
||||||
|
use crate::generation::TrieInputs;
|
||||||
|
use crate::memory::segments::Segment;
|
||||||
|
use crate::proof::TrieRoots;
|
||||||
|
use crate::util::h2u;
|
||||||
|
|
||||||
|
// Stolen from `tests/mpt/insert.rs`
|
||||||
|
// Prepare the interpreter by loading the initial MPTs and
|
||||||
|
// by setting all `GlobalMetadata` and necessary code into memory.
|
||||||
|
fn prepare_interpreter(
|
||||||
|
interpreter: &mut Interpreter,
|
||||||
|
trie_inputs: TrieInputs,
|
||||||
|
transaction: &[u8],
|
||||||
|
contract_code: HashMap<H256, Vec<u8>>,
|
||||||
|
) {
|
||||||
|
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
|
||||||
|
|
||||||
|
interpreter.generation_state.registers.program_counter = load_all_mpts;
|
||||||
|
interpreter.push(0xDEADBEEFu32.into());
|
||||||
|
|
||||||
|
interpreter.generation_state.mpt_prover_inputs =
|
||||||
|
all_mpt_prover_inputs_reversed(&trie_inputs).expect("Invalid MPT data.");
|
||||||
|
interpreter.run().expect("MPT loading failed.");
|
||||||
|
assert_eq!(interpreter.stack(), vec![]);
|
||||||
|
|
||||||
|
// Set necessary `GlobalMetadata`.
|
||||||
|
let global_metadata_to_set = [
|
||||||
|
(
|
||||||
|
GlobalMetadata::StateTrieRootDigestBefore,
|
||||||
|
h2u(trie_inputs.state_trie.hash()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
GlobalMetadata::TransactionTrieRootDigestBefore,
|
||||||
|
h2u(trie_inputs.transactions_trie.hash()),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
GlobalMetadata::ReceiptTrieRootDigestBefore,
|
||||||
|
h2u(trie_inputs.receipts_trie.hash()),
|
||||||
|
),
|
||||||
|
(GlobalMetadata::TxnNumberAfter, 1.into()),
|
||||||
|
(GlobalMetadata::BlockGasUsedAfter, 0xa868u64.into()),
|
||||||
|
(GlobalMetadata::BlockGasLimit, 1_000_000.into()),
|
||||||
|
(GlobalMetadata::BlockBaseFee, 10.into()),
|
||||||
|
(
|
||||||
|
GlobalMetadata::BlockBeneficiary,
|
||||||
|
U256::from_big_endian(
|
||||||
|
&Address::from(hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba")).0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
interpreter.set_global_metadata_multi_fields(&global_metadata_to_set);
|
||||||
|
|
||||||
|
// Set contract code and transaction.
|
||||||
|
interpreter.generation_state.inputs.contract_code = contract_code;
|
||||||
|
|
||||||
|
interpreter.generation_state.inputs.signed_txn = Some(transaction.to_vec());
|
||||||
|
let rlp_prover_inputs = all_rlp_prover_inputs_reversed(transaction);
|
||||||
|
interpreter.generation_state.rlp_prover_inputs = rlp_prover_inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add11_yml() {
|
||||||
|
let beneficiary = hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba");
|
||||||
|
let sender = hex!("a94f5374fce5edbc8e2a8697c15331677e6ebf0b");
|
||||||
|
let to = hex!("095e7baea6a6c7c4c2dfeb977efac326af552d87");
|
||||||
|
|
||||||
|
let beneficiary_state_key = keccak(beneficiary);
|
||||||
|
let sender_state_key = keccak(sender);
|
||||||
|
let to_hashed = keccak(to);
|
||||||
|
|
||||||
|
let beneficiary_nibbles = Nibbles::from_bytes_be(beneficiary_state_key.as_bytes()).unwrap();
|
||||||
|
let sender_nibbles = Nibbles::from_bytes_be(sender_state_key.as_bytes()).unwrap();
|
||||||
|
let to_nibbles = Nibbles::from_bytes_be(to_hashed.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
let code = [0x60, 0x01, 0x60, 0x01, 0x01, 0x60, 0x00, 0x55, 0x00];
|
||||||
|
let code_hash = keccak(code);
|
||||||
|
|
||||||
|
let mut contract_code = HashMap::new();
|
||||||
|
contract_code.insert(keccak(vec![]), vec![]);
|
||||||
|
contract_code.insert(code_hash, code.to_vec());
|
||||||
|
|
||||||
|
let beneficiary_account_before = AccountRlp {
|
||||||
|
nonce: 1.into(),
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
let sender_account_before = AccountRlp {
|
||||||
|
balance: 0x0de0b6b3a7640000u64.into(),
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
let to_account_before = AccountRlp {
|
||||||
|
balance: 0x0de0b6b3a7640000u64.into(),
|
||||||
|
code_hash,
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut state_trie_before = HashedPartialTrie::from(Node::Empty);
|
||||||
|
state_trie_before.insert(
|
||||||
|
beneficiary_nibbles,
|
||||||
|
rlp::encode(&beneficiary_account_before).to_vec(),
|
||||||
|
);
|
||||||
|
state_trie_before.insert(sender_nibbles, rlp::encode(&sender_account_before).to_vec());
|
||||||
|
state_trie_before.insert(to_nibbles, rlp::encode(&to_account_before).to_vec());
|
||||||
|
|
||||||
|
let tries_before = TrieInputs {
|
||||||
|
state_trie: state_trie_before,
|
||||||
|
transactions_trie: Node::Empty.into(),
|
||||||
|
receipts_trie: Node::Empty.into(),
|
||||||
|
storage_tries: vec![(to_hashed, Node::Empty.into())],
|
||||||
|
};
|
||||||
|
|
||||||
|
let txn = hex!("f863800a83061a8094095e7baea6a6c7c4c2dfeb977efac326af552d87830186a0801ba0ffb600e63115a7362e7811894a91d8ba4330e526f22121c994c4692035dfdfd5a06198379fcac8de3dbfac48b165df4bf88e2088f294b61efb9a65fe2281c76e16");
|
||||||
|
|
||||||
|
let initial_stack = vec![];
|
||||||
|
let mut interpreter = Interpreter::new_with_kernel(0, initial_stack);
|
||||||
|
|
||||||
|
prepare_interpreter(&mut interpreter, tries_before.clone(), &txn, contract_code);
|
||||||
|
let expected_state_trie_after = {
|
||||||
|
let beneficiary_account_after = AccountRlp {
|
||||||
|
nonce: 1.into(),
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
let sender_account_after = AccountRlp {
|
||||||
|
balance: 0xde0b6b3a75be550u64.into(),
|
||||||
|
nonce: 1.into(),
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
let to_account_after = AccountRlp {
|
||||||
|
balance: 0xde0b6b3a76586a0u64.into(),
|
||||||
|
code_hash,
|
||||||
|
// Storage map: { 0 => 2 }
|
||||||
|
storage_root: HashedPartialTrie::from(Node::Leaf {
|
||||||
|
nibbles: Nibbles::from_h256_be(keccak([0u8; 32])),
|
||||||
|
value: vec![2],
|
||||||
|
})
|
||||||
|
.hash(),
|
||||||
|
..AccountRlp::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut expected_state_trie_after = HashedPartialTrie::from(Node::Empty);
|
||||||
|
expected_state_trie_after.insert(
|
||||||
|
beneficiary_nibbles,
|
||||||
|
rlp::encode(&beneficiary_account_after).to_vec(),
|
||||||
|
);
|
||||||
|
expected_state_trie_after
|
||||||
|
.insert(sender_nibbles, rlp::encode(&sender_account_after).to_vec());
|
||||||
|
expected_state_trie_after.insert(to_nibbles, rlp::encode(&to_account_after).to_vec());
|
||||||
|
expected_state_trie_after
|
||||||
|
};
|
||||||
|
let receipt_0 = LegacyReceiptRlp {
|
||||||
|
status: true,
|
||||||
|
cum_gas_used: 0xa868u64.into(),
|
||||||
|
bloom: vec![0; 256].into(),
|
||||||
|
logs: vec![],
|
||||||
|
};
|
||||||
|
let mut receipts_trie = HashedPartialTrie::from(Node::Empty);
|
||||||
|
receipts_trie.insert(
|
||||||
|
Nibbles::from_str("0x80").unwrap(),
|
||||||
|
rlp::encode(&receipt_0).to_vec(),
|
||||||
|
);
|
||||||
|
let transactions_trie: HashedPartialTrie = Node::Leaf {
|
||||||
|
nibbles: Nibbles::from_str("0x80").unwrap(),
|
||||||
|
value: txn.to_vec(),
|
||||||
|
}
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let trie_roots_after = TrieRoots {
|
||||||
|
state_root: expected_state_trie_after.hash(),
|
||||||
|
transactions_root: transactions_trie.hash(),
|
||||||
|
receipts_root: receipts_trie.hash(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set trie roots after the transaction was executed.
|
||||||
|
let metadata_to_set = [
|
||||||
|
(
|
||||||
|
GlobalMetadata::StateTrieRootDigestAfter,
|
||||||
|
h2u(trie_roots_after.state_root),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
GlobalMetadata::TransactionTrieRootDigestAfter,
|
||||||
|
h2u(trie_roots_after.transactions_root),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
GlobalMetadata::ReceiptTrieRootDigestAfter,
|
||||||
|
h2u(trie_roots_after.receipts_root),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
interpreter.set_global_metadata_multi_fields(&metadata_to_set);
|
||||||
|
|
||||||
|
let route_txn_label = KERNEL.global_labels["hash_initial_tries"];
|
||||||
|
// Switch context and initialize memory with the data we need for the tests.
|
||||||
|
interpreter.generation_state.registers.program_counter = route_txn_label;
|
||||||
|
interpreter.generation_state.memory.contexts[0].segments[Segment::ContextMetadata as usize]
|
||||||
|
.set(ContextMetadata::GasLimit as usize, 1_000_000.into());
|
||||||
|
interpreter.set_is_kernel(true);
|
||||||
|
interpreter.run().expect("Proving add11 failed.");
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ use ethereum_types::U256;
|
|||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::cpu::kernel::aggregator::KERNEL;
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
use crate::cpu::kernel::interpreter::{run, run_interpreter};
|
use crate::cpu::kernel::interpreter::{run, run_interpreter, Interpreter};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exp() -> Result<()> {
|
fn test_exp() -> Result<()> {
|
||||||
@ -15,33 +15,28 @@ fn test_exp() -> Result<()> {
|
|||||||
|
|
||||||
// Random input
|
// Random input
|
||||||
let initial_stack = vec![0xDEADBEEFu32.into(), b, a];
|
let initial_stack = vec![0xDEADBEEFu32.into(), b, a];
|
||||||
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack().to_vec();
|
let mut interpreter = Interpreter::new_with_kernel(0, initial_stack.clone());
|
||||||
let initial_stack = vec![b, a];
|
|
||||||
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
|
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack();
|
||||||
let stack_with_opcode = run(&code, 0, initial_stack, &KERNEL.prover_inputs)?
|
|
||||||
.stack()
|
let expected_exp = a.overflowing_pow(b).0;
|
||||||
.to_vec();
|
assert_eq!(stack_with_kernel, vec![expected_exp]);
|
||||||
assert_eq!(stack_with_kernel, stack_with_opcode);
|
|
||||||
|
|
||||||
// 0 base
|
// 0 base
|
||||||
let initial_stack = vec![0xDEADBEEFu32.into(), b, U256::zero()];
|
let initial_stack = vec![0xDEADBEEFu32.into(), b, U256::zero()];
|
||||||
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack().to_vec();
|
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack();
|
||||||
let initial_stack = vec![b, U256::zero()];
|
|
||||||
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
|
let expected_exp = U256::zero().overflowing_pow(b).0;
|
||||||
let stack_with_opcode = run(&code, 0, initial_stack, &KERNEL.prover_inputs)?
|
assert_eq!(stack_with_kernel, vec![expected_exp]);
|
||||||
.stack()
|
|
||||||
.to_vec();
|
|
||||||
assert_eq!(stack_with_kernel, stack_with_opcode);
|
|
||||||
|
|
||||||
// 0 exponent
|
// 0 exponent
|
||||||
let initial_stack = vec![0xDEADBEEFu32.into(), U256::zero(), a];
|
let initial_stack = vec![0xDEADBEEFu32.into(), U256::zero(), a];
|
||||||
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack().to_vec();
|
interpreter.set_is_kernel(true);
|
||||||
let initial_stack = vec![U256::zero(), a];
|
interpreter.set_context(0);
|
||||||
let code = [0xa, 0x63, 0xde, 0xad, 0xbe, 0xef, 0x56]; // EXP, PUSH4 deadbeef, JUMP
|
let stack_with_kernel = run_interpreter(exp, initial_stack)?.stack();
|
||||||
let stack_with_opcode = run(&code, 0, initial_stack, &KERNEL.prover_inputs)?
|
|
||||||
.stack()
|
let expected_exp = 1.into();
|
||||||
.to_vec();
|
assert_eq!(stack_with_kernel, vec![expected_exp]);
|
||||||
assert_eq!(stack_with_kernel, stack_with_opcode);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
mod account_code;
|
mod account_code;
|
||||||
|
mod add11;
|
||||||
mod balance;
|
mod balance;
|
||||||
mod bignum;
|
mod bignum;
|
||||||
mod blake2_f;
|
mod blake2_f;
|
||||||
|
|||||||
@ -120,7 +120,9 @@ fn run_test(fn_label: &str, expected_fn: fn(U256, U256) -> U256, opname: &str) {
|
|||||||
let mut interpreter = Interpreter::new_with_kernel(fn_label, stack);
|
let mut interpreter = Interpreter::new_with_kernel(fn_label, stack);
|
||||||
interpreter.run().unwrap();
|
interpreter.run().unwrap();
|
||||||
assert_eq!(interpreter.stack_len(), 1usize, "unexpected stack size");
|
assert_eq!(interpreter.stack_len(), 1usize, "unexpected stack size");
|
||||||
let output = interpreter.stack_top();
|
let output = interpreter
|
||||||
|
.stack_top()
|
||||||
|
.expect("The stack should not be empty.");
|
||||||
let expected_output = expected_fn(x, y);
|
let expected_output = expected_fn(x, y);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
output, expected_output,
|
output, expected_output,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user