Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
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
4 changes: 3 additions & 1 deletion bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod mstore;
mod pc;
mod pop;
mod push;
mod selfbalance;
mod sload;
mod stackonlyop;
mod stop;
Expand All @@ -41,6 +42,7 @@ use msize::Msize;
use mstore::Mstore;
use pc::Pc;
use pop::Pop;
use selfbalance::Selfbalance;
use sload::Sload;
use stackonlyop::StackOnlyOpcode;
use stop::Stop;
Expand Down Expand Up @@ -123,7 +125,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
// OpcodeId::DIFFICULTY => {},
// OpcodeId::GASLIMIT => {},
// OpcodeId::CHAINID => {},
// OpcodeId::SELFBALANCE => {},
OpcodeId::SELFBALANCE => Selfbalance::gen_associated_ops,
// OpcodeId::BASEFEE => {},
OpcodeId::POP => Pop::gen_associated_ops,
OpcodeId::MLOAD => Mload::gen_associated_ops,
Expand Down
132 changes: 132 additions & 0 deletions bus-mapping/src/evm/opcodes/selfbalance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use super::Opcode;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::operation::{AccountField, AccountOp, CallContextField, CallContextOp, RW};
use crate::Error;
use eth_types::{GethExecStep, ToWord};

#[derive(Debug, Copy, Clone)]
pub(crate) struct Selfbalance;

impl Opcode for Selfbalance {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];
let self_balance = steps[1].stack.last()?;
let callee_address = state.call().address;

// CallContext read of the callee_address
state.push_op(
RW::READ,
CallContextOp {
call_id: state.call().call_id,
field: CallContextField::CalleeAddress,
value: callee_address.to_word(),
},
);

// Account read for the balance of the callee_address
state.push_op(
RW::READ,
AccountOp {
address: callee_address,
field: AccountField::Balance,
value: self_balance,
value_prev: self_balance,
},
);

// Stack write of self_balance
state.push_stack_op(
RW::WRITE,
step.stack.last_filled().map(|a| a - 1),
self_balance,
);

Ok(())
}
}

#[cfg(test)]
mod selfbalance_tests {
use super::*;
use crate::circuit_input_builder::{ExecStep, TransactionContext};
use eth_types::{bytecode, evm_types::StackAddress, ToWord};
use pretty_assertions::assert_eq;

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

let mut geth_data = mock::new_single_tx_trace_code(&code)?;
geth_data.geth_trace.struct_logs =
geth_data.geth_trace.struct_logs[code.get_pos("start")..].to_vec();

// Get the execution steps from the external tracer
let block = crate::mock::BlockData::new_from_geth_data(geth_data);

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)
.unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx, &block.geth_trace).unwrap();

// Generate step corresponding to SELFBALANCE
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 callee_address = block.eth_tx.to.unwrap();
let self_balance = state_ref.sdb.get_account(&callee_address).1.balance;

// CallContext read for callee_address
state_ref.push_op(
RW::READ,
CallContextOp {
call_id: state_ref.call().call_id,
field: CallContextField::CalleeAddress,
value: callee_address.to_word(),
},
);

// Account read for balance of callee_address
state_ref.push_op(
RW::READ,
AccountOp {
address: callee_address,
field: AccountField::Balance,
value: self_balance,
value_prev: self_balance,
},
);

// Add the Stack write
state_ref.push_stack_op(RW::WRITE, StackAddress::from(1024 - 1), self_balance);

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,
);

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

Ok(())
}
}
2 changes: 1 addition & 1 deletion bus-mapping/src/operation/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl OperationContainer {
}
}

/// Inserts an [`Operation`] into the container returning a lightwheight
/// Inserts an [`Operation`] into the container returning a lightweight
/// reference to it in the form of an [`OperationRef`] which points to the
/// location of the inserted operation inside the corresponding container
/// vector.
Expand Down
5 changes: 5 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod mul;
mod pc;
mod pop;
mod push;
mod selfbalance;
mod signed_comparator;
mod signextend;
mod stop;
Expand Down Expand Up @@ -68,6 +69,7 @@ use mul::MulGadget;
use pc::PcGadget;
use pop::PopGadget;
use push::PushGadget;
use selfbalance::SelfbalanceGadget;
use signed_comparator::SignedComparatorGadget;
use signextend::SignextendGadget;
use stop::StopGadget;
Expand Down Expand Up @@ -126,6 +128,7 @@ pub(crate) struct ExecutionConfig<F> {
msize_gadget: MsizeGadget<F>,
coinbase_gadget: CoinbaseGadget<F>,
timestamp_gadget: TimestampGadget<F>,
selfbalance_gadget: SelfbalanceGadget<F>,
}

impl<F: FieldExt> ExecutionConfig<F> {
Expand Down Expand Up @@ -252,6 +255,7 @@ impl<F: FieldExt> ExecutionConfig<F> {
pc_gadget: configure_gadget!(),
pop_gadget: configure_gadget!(),
push_gadget: configure_gadget!(),
selfbalance_gadget: configure_gadget!(),
signed_comparator_gadget: configure_gadget!(),
signextend_gadget: configure_gadget!(),
stop_gadget: configure_gadget!(),
Expand Down Expand Up @@ -513,6 +517,7 @@ impl<F: FieldExt> ExecutionConfig<F> {
ExecutionState::TIMESTAMP => {
assign_exec_step!(self.timestamp_gadget)
}
ExecutionState::SELFBALANCE => assign_exec_step!(self.selfbalance_gadget),
ExecutionState::CALLDATACOPY => {
assign_exec_step!(self.calldatacopy_gadget)
}
Expand Down
100 changes: 100 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/selfbalance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use crate::{
evm_circuit::{
execution::ExecutionGadget,
step::ExecutionState,
table::{AccountFieldTag, CallContextFieldTag},
util::{
common_gadget::SameContextGadget,
constraint_builder::{ConstraintBuilder, StepStateTransition, Transition::Delta},
Cell, Word,
},
witness::{Block, Call, ExecStep, Transaction},
},
util::Expr,
};
use eth_types::{ToLittleEndian, ToScalar};
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};

#[derive(Clone, Debug)]
pub(crate) struct SelfbalanceGadget<F> {
same_context: SameContextGadget<F>,
callee_address: Cell<F>,
self_balance: Cell<F>,
}

impl<F: FieldExt> ExecutionGadget<F> for SelfbalanceGadget<F> {
const NAME: &'static str = "SELFBALANCE";

const EXECUTION_STATE: ExecutionState = ExecutionState::SELFBALANCE;

fn configure(cb: &mut ConstraintBuilder<F>) -> Self {
let callee_address = cb.call_context(None, CallContextFieldTag::CalleeAddress);

let self_balance = cb.query_cell();
cb.account_read(
callee_address.expr(),
AccountFieldTag::Balance,
self_balance.expr(),
);

cb.stack_push(self_balance.expr());

let opcode = cb.query_cell();
let step_state_transition = StepStateTransition {
rw_counter: Delta(3.expr()),
program_counter: Delta(1.expr()),
stack_pointer: Delta((-1).expr()),
..Default::default()
};
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition, None);

Self {
same_context,
self_balance,
callee_address,
}
}

fn assign_exec_step(
&self,
region: &mut Region<'_, F>,
offset: usize,
block: &Block<F>,
_: &Transaction,
call: &Call,
step: &ExecStep,
) -> Result<(), Error> {
self.same_context.assign_exec_step(region, offset, step)?;

self.callee_address
.assign(region, offset, call.callee_address.to_scalar())?;

let self_balance = block.rws[step.rw_indices[2]].stack_value();
self.self_balance.assign(
region,
offset,
Some(Word::random_linear_combine(
self_balance.to_le_bytes(),
block.randomness,
)),
)?;

Ok(())
}
}

#[cfg(test)]
mod test {
use crate::test_util::run_test_circuits;
use eth_types::bytecode;

#[test]
fn selfbalance_gadget_test() {
let bytecode = bytecode! {
#[start]
SELFBALANCE
STOP
};
assert_eq!(run_test_circuits(bytecode), Ok(()));
}
}
1 change: 1 addition & 0 deletions zkevm-circuits/src/evm_circuit/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,7 @@ impl From<&bus_mapping::circuit_input_builder::ExecStep> for ExecutionState {
OpcodeId::COINBASE => ExecutionState::COINBASE,
OpcodeId::TIMESTAMP => ExecutionState::TIMESTAMP,
OpcodeId::GAS => ExecutionState::GAS,
OpcodeId::SELFBALANCE => ExecutionState::SELFBALANCE,
_ => unimplemented!("unimplemented opcode {:?}", step.op),
}
}
Expand Down