Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.
Closed
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
10 changes: 9 additions & 1 deletion bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ impl<'a> CircuitInputStateRef<'a> {
.expect("steps should have at least one BeginTx step");
ExecStep {
exec_state: ExecState::EndTx,
gas_left: Gas(prev_step.gas_left.0 - prev_step.gas_cost.0),
gas_left: if prev_step.error.is_none() {
// no error
Gas(prev_step.gas_left.0 - prev_step.gas_cost.0)
}else{
// if error happend, consume all gas
Gas(0u64)
//prev_step.gas_left
},

rwc: self.block_ctx.rwc,
// For tx without code execution
reversible_write_counter: if let Some(call_ctx) = self.tx_ctx.calls().last() {
Expand Down
42 changes: 28 additions & 14 deletions bus-mapping/src/evm/opcodes/stackonlyop.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use super::Opcode;
use crate::circuit_input_builder::{CircuitInputStateRef, ExecStep};
use crate::Error;
use crate::{
error::{get_step_reported_error, ExecError},
};

use eth_types::GethExecStep;

/// Placeholder structure used to implement [`Opcode`] trait over it
Expand All @@ -20,21 +24,31 @@ impl<const N_POP: usize, const N_PUSH: usize> Opcode for StackOnlyOpcode<N_POP,
let geth_step = &geth_steps[0];
let mut exec_step = state.new_step(geth_step)?;
// N_POP stack reads
for i in 0..N_POP {
state.stack_read(
&mut exec_step,
geth_step.stack.nth_last_filled(i),
geth_step.stack.nth_last(i)?,
)?;
}
let stack_length = geth_step.stack.0.len();
if let Some(error) = geth_step.clone().error {
let execution_error:ExecError = get_step_reported_error(&geth_step.op, &error);
println!("{}", error);
exec_step.error= Some(execution_error);
//exec_step.exec_state =
}
else{
for i in 0..N_POP {
state.stack_read(
&mut exec_step,
geth_step.stack.nth_last_filled(i),
geth_step.stack.nth_last(i)?,
)?;
}

// N_PUSH stack writes
for i in 0..N_PUSH {
state.stack_write(
&mut exec_step,
geth_steps[1].stack.nth_last_filled(N_PUSH - 1 - i),
geth_steps[1].stack.nth_last(N_PUSH - 1 - i)?,
)?;
}

// N_PUSH stack writes
for i in 0..N_PUSH {
state.stack_write(
&mut exec_step,
geth_steps[1].stack.nth_last_filled(N_PUSH - 1 - i),
geth_steps[1].stack.nth_last(N_PUSH - 1 - i)?,
)?;
}

Ok(vec![exec_step])
Expand Down
7 changes: 7 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ mod mul_div_mod;
mod mulmod;
mod not;
mod origin;
mod error_oog_constant;
mod pc;
mod pop;
mod push;
Expand Down Expand Up @@ -110,6 +111,7 @@ use msize::MsizeGadget;
use mul_div_mod::MulDivModGadget;
use mulmod::MulModGadget;
use not::NotGadget;
use error_oog_constant::ErrorOOGConstantGadget;
use origin::OriginGadget;
use pc::PcGadget;
use pop::PopGadget;
Expand Down Expand Up @@ -208,6 +210,7 @@ pub(crate) struct ExecutionConfig<F> {
block_ctx_u160_gadget: BlockCtxU160Gadget<F>,
block_ctx_u256_gadget: BlockCtxU256Gadget<F>,
// error gadgets
error_oog_constant: ErrorOOGConstantGadget<F>,
error_oog_static_memory_gadget: ErrorOOGStaticMemoryGadget<F>,
}

Expand Down Expand Up @@ -405,6 +408,7 @@ impl<F: Field> ExecutionConfig<F> {
block_ctx_u256_gadget: configure_gadget!(),
// error gadgets
error_oog_static_memory_gadget: configure_gadget!(),
error_oog_constant: configure_gadget!(),
// step and presets
step: step_curr,
height_map,
Expand Down Expand Up @@ -846,6 +850,9 @@ impl<F: Field> ExecutionConfig<F> {
ExecutionState::STOP => assign_exec_step!(self.stop_gadget),
ExecutionState::SWAP => assign_exec_step!(self.swap_gadget),
// errors
ExecutionState::ErrorOutOfGasConstant => {
assign_exec_step!(self.error_oog_constant)
}
ExecutionState::ErrorOutOfGasStaticMemoryExpansion => {
assign_exec_step!(self.error_oog_static_memory_gadget)
}
Expand Down
123 changes: 123 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/error_oog_constant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use crate::{
evm_circuit::{
execution::ExecutionGadget,
param::{N_BYTES_GAS, N_BYTES_MEMORY_WORD_SIZE},
step::ExecutionState,
util::{
constraint_builder::ConstraintBuilder,
math_gadget::{IsEqualGadget, IsZeroGadget, RangeCheckGadget},
memory_gadget::{address_high, address_low, MemoryExpansionGadget},
CachedRegion, Cell, Word,
},
witness::{Block, Call, ExecStep, Transaction},
},
util::Expr,
};
use eth_types::{evm_types::OpcodeId, Field, ToLittleEndian};
use halo2_proofs::plonk::Error;

#[derive(Clone, Debug)]
pub(crate) struct ErrorOOGConstantGadget<F> {
opcode: Cell<F>,
// constrain gas left is less than required
gas_required: Cell<F>,
insufficient_gas: RangeCheckGadget<F, N_BYTES_GAS>,
}

impl<F: Field> ExecutionGadget<F> for ErrorOOGConstantGadget<F> {
const NAME: &'static str = "ErrorOutOfGasConstant";

const EXECUTION_STATE: ExecutionState = ExecutionState::ErrorOutOfGasConstant;

// Support other OOG due to pure memory including CREATE, RETURN and REVERT
fn configure(cb: &mut ConstraintBuilder<F>) -> Self {
let opcode = cb.query_cell();
let gas_required = cb.query_cell();

// Check if the amount of gas available is less than the amount of gas
// required
let insufficient_gas = RangeCheckGadget::construct(
cb,
gas_required.expr() - cb.curr.state.gas_left.expr(),
);

// TODO: Use ContextSwitchGadget to switch call context to caller's and
// consume all gas_left.

Self {
opcode,
gas_required,
insufficient_gas,
}
}

fn assign_exec_step(
&self,
region: &mut CachedRegion<'_, '_, F>,
offset: usize,
block: &Block<F>,
_tx: &Transaction,
_call: &Call,
step: &ExecStep,
) -> Result<(), Error> {
let opcode = step.opcode.unwrap();

// Inputs/Outputs
self.gas_required.assign(region, offset, Some(F::from(step.gas_cost)))?;
// Gas insufficient check
// Get `gas_available` variable here once it's available
self.insufficient_gas
.assign(region, offset, F::from(step.gas_cost - step.gas_left))?;

Ok(())
}
}

#[cfg(test)]
mod test {
use crate::{evm_circuit::test::rand_bytes, test_util::run_test_circuits};
use eth_types::bytecode;
use eth_types::evm_types::OpcodeId;
use mock::TestContext;

fn test_ok(opcode: OpcodeId, bytes: &[u8]) {
assert!(bytes.len() as u8 == opcode.as_u8() - OpcodeId::PUSH1.as_u8() + 1,);

let mut bytecode = bytecode! {
.write_op(opcode)
};
for b in bytes {
bytecode.write(*b);
}
bytecode.write_op(OpcodeId::STOP);

assert_eq!(
run_test_circuits(
TestContext::<2, 1>::simple_ctx_with_bytecode(bytecode).unwrap(),
None
),
Ok(())
);
}

#[test]
fn push_gadget_simple() {
test_ok(OpcodeId::PUSH1, &[1]);
// test_ok(OpcodeId::PUSH2, &[1, 2]);
// test_ok(
// OpcodeId::PUSH31,
// &[
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
// 24, 25, 26, 27, 28, 29, 30, 31,
// ],
// );
// test_ok(
// OpcodeId::PUSH32,
// &[
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
// 24, 25, 26, 27, 28, 29, 30, 31, 32,
// ],
// );
}

}