Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Implement ExecutionState::EndTx #312

Merged
merged 3 commits into from
Mar 14, 2022
Merged
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
506 changes: 301 additions & 205 deletions bus-mapping/src/circuit_input_builder.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions bus-mapping/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum Error {
StorageKeyNotFound(Address, Word),
/// Unable to figure out error at a [`GethExecStep`]
UnexpectedExecStepError(&'static str, GethExecStep),
/// Invalid [`eth_types::GethExecTrace`] due to an invalid/unexpected value
/// in it.
InvalidGethExecTrace(&'static str),
/// Invalid [`GethExecStep`] due to an invalid/unexpected value in it.
InvalidGethExecStep(&'static str, GethExecStep),
/// Eth type related error.
Expand Down
397 changes: 303 additions & 94 deletions bus-mapping/src/evm/opcodes.rs

Large diffs are not rendered by default.

97 changes: 39 additions & 58 deletions bus-mapping/src/evm/opcodes/calldatasize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,91 +21,72 @@ impl Opcode for Calldatasize {
state.push_op(
RW::READ,
CallContextOp {
call_id: state.call().call_id,
call_id: state.call()?.call_id,
field: CallContextField::CallDataLength,
value,
},
);
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value);
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value)?;
Ok(())
}
}

#[cfg(test)]
mod calldatasize_tests {
use crate::{
circuit_input_builder::{ExecStep, TransactionContext},
mock::BlockData,
operation::{CallContextField, CallContextOp, RW},
Error,
};
use eth_types::bytecode;
use eth_types::evm_types::StackAddress;
use mock::new_single_tx_trace_code_at_start;
use crate::operation::{CallContextField, CallContextOp, StackOp, RW};
use eth_types::{bytecode, evm_types::OpcodeId, evm_types::StackAddress};
use pretty_assertions::assert_eq;

#[test]
fn calldatasize_opcode_impl() -> Result<(), Error> {
fn calldatasize_opcode_impl() {
let code = bytecode! {
#[start]
CALLDATASIZE
STOP
};

// Get the execution steps from the external tracer
let block =
BlockData::new_from_geth_data(new_single_tx_trace_code_at_start(&code).unwrap());
let block = crate::mock::BlockData::new_from_geth_data(
mock::new_single_tx_trace_code(&code).unwrap(),
);

let mut builder = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder
.new_tx(&block.eth_tx, !block.geth_trace.failed)
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

// Generate step corresponding to CALLDATASIZE
let mut step = ExecStep::new(
&block.geth_trace.struct_logs[0],
0,
test_builder.block_ctx.rwc,
0,
);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);

// Get calldatasize from eth tx.
let call_data_size = block.eth_tx.input.to_vec().len();
let step = builder.block.txs()[0]
.steps()
.iter()
.find(|step| step.op == OpcodeId::CALLDATASIZE)
.unwrap();

// Add the read operation.
state_ref.push_op(
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
field: CallContextField::CallDataLength,
value: eth_types::U256::from(call_data_size),
let call_id = builder.block.txs()[0].calls()[0].call_id;
let call_data_size = block.eth_block.transactions[0].input.as_ref().len().into();
assert_eq!(
{
let operation =
&builder.block.container.call_context[step.bus_mapping_instance[0].as_usize()];
(operation.rw(), operation.op())
},
(
RW::READ,
&CallContextOp {
call_id,
field: CallContextField::CallDataLength,
value: call_data_size,
}
)
);

// Add the stack write.
state_ref.push_stack_op(
RW::WRITE,
StackAddress::from(1024 - 1),
eth_types::U256::from(call_data_size),
);

tx.steps_mut().push(step);
test_builder.block.txs_mut().push(tx);

// Compare first step bus mapping instance
assert_eq!(
builder.block.txs()[0].steps()[0].bus_mapping_instance,
test_builder.block.txs()[0].steps()[0].bus_mapping_instance,
{
let operation =
&builder.block.container.stack[step.bus_mapping_instance[1].as_usize()];
(operation.rw(), operation.op())
},
(
RW::WRITE,
&StackOp::new(1, StackAddress::from(1023), call_data_size)
)
);

// Compare containers
assert_eq!(builder.block.container, test_builder.block.container);

Ok(())
}
}
82 changes: 37 additions & 45 deletions bus-mapping/src/evm/opcodes/caller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,82 +21,74 @@ impl Opcode for Caller {
state.push_op(
RW::READ,
CallContextOp {
call_id: state.call().call_id,
call_id: state.call()?.call_id,
field: CallContextField::CallerAddress,
value,
},
);
// Stack write of the caller_address
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value);
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value)?;

Ok(())
}
}

#[cfg(test)]
mod caller_tests {
use super::*;
use crate::circuit_input_builder::{ExecStep, TransactionContext};
use eth_types::{bytecode, evm_types::StackAddress, ToWord};
use crate::operation::{CallContextField, CallContextOp, StackOp, RW};
use eth_types::{bytecode, evm_types::OpcodeId, evm_types::StackAddress, ToWord};
use pretty_assertions::assert_eq;

#[test]
fn caller_opcode_impl() -> Result<(), Error> {
fn caller_opcode_impl() {
let code = bytecode! {
#[start]
CALLER
STOP
};

// Get the execution steps from the external tracer
let block = crate::mock::BlockData::new_from_geth_data(
mock::new_single_tx_trace_code_at_start(&code).unwrap(),
mock::new_single_tx_trace_code(&code).unwrap(),
);

let mut builder = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder
.new_tx(&block.eth_tx, !block.geth_trace.failed)
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

// Generate step corresponding to CALLER
let mut step = ExecStep::new(
&block.geth_trace.struct_logs[0],
0,
test_builder.block_ctx.rwc,
0,
);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);

let caller_address = block.eth_tx.from.to_word();
let step = builder.block.txs()[0]
.steps()
.iter()
.find(|step| step.op == OpcodeId::CALLER)
.unwrap();

// Add the CallContext read
state_ref.push_op(
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
field: CallContextField::CallerAddress,
value: caller_address,
let call_id = builder.block.txs()[0].calls()[0].call_id;
let caller_address = block.eth_block.transactions[0].from.to_word();
assert_eq!(
{
let operation =
&builder.block.container.call_context[step.bus_mapping_instance[0].as_usize()];
(operation.rw(), operation.op())
},
(
RW::READ,
&CallContextOp {
call_id,
field: CallContextField::CallerAddress,
value: caller_address,
}
)
);
// Add the Stack write
state_ref.push_stack_op(RW::WRITE, StackAddress::from(1024 - 1), caller_address);

tx.steps_mut().push(step);
test_builder.block.txs_mut().push(tx);

// Compare first step bus mapping instance
assert_eq!(
builder.block.txs()[0].steps()[0].bus_mapping_instance,
test_builder.block.txs()[0].steps()[0].bus_mapping_instance,
{
let operation =
&builder.block.container.stack[step.bus_mapping_instance[1].as_usize()];
(operation.rw(), operation.op())
},
(
RW::WRITE,
&StackOp::new(1, StackAddress::from(1023), caller_address)
)
);

// Compare containers
assert_eq!(builder.block.container, test_builder.block.container);

Ok(())
}
}
82 changes: 37 additions & 45 deletions bus-mapping/src/evm/opcodes/callvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,82 +21,74 @@ impl Opcode for Callvalue {
state.push_op(
RW::READ,
CallContextOp {
call_id: state.call().call_id,
call_id: state.call()?.call_id,
field: CallContextField::Value,
value,
},
);
// Stack write of the call_value
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value);
state.push_stack_op(RW::WRITE, step.stack.last_filled().map(|a| a - 1), value)?;

Ok(())
}
}

#[cfg(test)]
mod callvalue_tests {
use super::*;
use crate::circuit_input_builder::{ExecStep, TransactionContext};
use eth_types::{bytecode, evm_types::StackAddress};
use crate::operation::{CallContextField, CallContextOp, StackOp, RW};
use eth_types::{bytecode, evm_types::OpcodeId, evm_types::StackAddress};
use pretty_assertions::assert_eq;

#[test]
fn callvalue_opcode_impl() -> Result<(), Error> {
fn callvalue_opcode_impl() {
let code = bytecode! {
#[start]
CALLVALUE
STOP
};

// Get the execution steps from the external tracer
let block = crate::mock::BlockData::new_from_geth_data(
mock::new_single_tx_trace_code_at_start(&code).unwrap(),
mock::new_single_tx_trace_code(&code).unwrap(),
);

let mut builder = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder
.new_tx(&block.eth_tx, !block.geth_trace.failed)
builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

// Generate step corresponding to CALLVALUE
let mut step = ExecStep::new(
&block.geth_trace.struct_logs[0],
0,
test_builder.block_ctx.rwc,
0,
);
let mut state_ref = test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);

let call_value = block.eth_tx.value;
let step = builder.block.txs()[0]
.steps()
.iter()
.find(|step| step.op == OpcodeId::CALLVALUE)
.unwrap();

// Add the CallContext read
state_ref.push_op(
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
field: CallContextField::Value,
value: call_value,
let call_id = builder.block.txs()[0].calls()[0].call_id;
let call_value = block.eth_block.transactions[0].value;
assert_eq!(
{
let operation =
&builder.block.container.call_context[step.bus_mapping_instance[0].as_usize()];
(operation.rw(), operation.op())
},
(
RW::READ,
&CallContextOp {
call_id,
field: CallContextField::Value,
value: call_value,
}
)
);
// Add the Stack write
state_ref.push_stack_op(RW::WRITE, StackAddress::from(1024 - 1), call_value);

tx.steps_mut().push(step);
test_builder.block.txs_mut().push(tx);

// Compare first step bus mapping instance
assert_eq!(
builder.block.txs()[0].steps()[0].bus_mapping_instance,
test_builder.block.txs()[0].steps()[0].bus_mapping_instance,
{
let operation =
&builder.block.container.stack[step.bus_mapping_instance[1].as_usize()];
(operation.rw(), operation.op())
},
(
RW::WRITE,
&StackOp::new(1, StackAddress::from(1023), call_value)
)
);

// Compare containers
assert_eq!(builder.block.container, test_builder.block.container);

Ok(())
}
}
Loading