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

handle gas uint overflow (ErrorGasUintOverflow) #1564

Merged
19 changes: 10 additions & 9 deletions zkevm-circuits/src/evm_circuit/execution/callop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
math_gadget::{
ConstantDivisionGadget, IsZeroGadget, LtGadget, LtWordGadget, MinMaxGadget,
},
memory_gadget::CommonMemoryAddressGadget,
memory_gadget::{CommonMemoryAddressGadget, MemoryAddressGadget},
not, or, select, CachedRegion, Cell, StepRws,
},
},
Expand Down Expand Up @@ -46,7 +46,7 @@ pub(crate) struct CallOpGadget<F> {
current_caller_address: WordCell<F>,
is_static: Cell<F>,
depth: Cell<F>,
call: CommonCallGadget<F, true>,
call: CommonCallGadget<F, MemoryAddressGadget<F>, true>,
current_value: WordCell<F>,
is_warm: Cell<F>,
is_warm_prev: Cell<F>,
Expand Down Expand Up @@ -93,13 +93,14 @@ impl<F: Field> ExecutionGadget<F> for CallOpGadget<F> {
)
});

let call_gadget = CommonCallGadget::construct(
cb,
is_call.expr(),
is_callcode.expr(),
is_delegatecall.expr(),
is_staticcall.expr(),
);
let call_gadget: CommonCallGadget<F, MemoryAddressGadget<F>, true> =
CommonCallGadget::construct(
cb,
is_call.expr(),
is_callcode.expr(),
is_delegatecall.expr(),
is_staticcall.expr(),
);
cb.condition(not::expr(is_call.expr() + is_callcode.expr()), |cb| {
cb.require_zero_word(
"for non call/call code, value is zero",
Expand Down
78 changes: 65 additions & 13 deletions zkevm-circuits/src/evm_circuit/execution/error_oog_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use crate::{
common_gadget::{CommonCallGadget, CommonErrorGadget},
constraint_builder::{ConstrainBuilderCommon, EVMConstraintBuilder},
math_gadget::{IsZeroGadget, LtGadget},
CachedRegion, Cell,
memory_gadget::MemoryExpandedAddressGadget,
or, CachedRegion, Cell,
},
},
table::CallContextFieldTag,
Expand All @@ -30,7 +31,7 @@ pub(crate) struct ErrorOOGCallGadget<F> {
is_staticcall: IsZeroGadget<F>,
tx_id: Cell<F>,
is_static: Cell<F>,
call: CommonCallGadget<F, false>,
call: CommonCallGadget<F, MemoryExpandedAddressGadget<F>, false>,
is_warm: Cell<F>,
insufficient_gas: LtGadget<F, N_BYTES_GAS>,
common_error_gadget: CommonErrorGadget<F>,
Expand All @@ -54,13 +55,14 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGCallGadget<F> {
let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
let is_static = cb.call_context(None, CallContextFieldTag::IsStatic);

let call_gadget = CommonCallGadget::construct(
cb,
is_call.expr(),
is_callcode.expr(),
is_delegatecall.expr(),
is_staticcall.expr(),
);
let call_gadget: CommonCallGadget<F, MemoryExpandedAddressGadget<F>, false> =
CommonCallGadget::construct(
cb,
is_call.expr(),
is_callcode.expr(),
is_delegatecall.expr(),
is_staticcall.expr(),
);

// Add callee to access list
let is_warm = cb.query_bool();
Expand All @@ -78,16 +80,24 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGCallGadget<F> {

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

cb.require_equal(
"gas left is less than gas required",
insufficient_gas.expr(),
"Either Memory address is overflow or gas left is less than cost",
or::expr([
call_gadget.cd_address.overflow(),
call_gadget.rd_address.overflow(),
insufficient_gas.expr(),
]),
1.expr(),
);

// Both CALL and CALLCODE opcodes have an extra stack pop `value` relative to
// DELEGATECALL and STATICCALL.
let common_error_gadget =
CommonErrorGadget::construct(cb, opcode.expr(), cb.rw_counter_offset());
let common_error_gadget = CommonErrorGadget::construct(
cb,
opcode.expr(),
11.expr() + is_call.expr() + is_callcode.expr(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed we fall back to manual offset counting here. Is it because cb.rw_counter_offset() doesn't work here?

Copy link
Collaborator Author

@DreamWuGit DreamWuGit Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, it works, but I feel cb.rw_counter_offset() is indirect way for calculating the rw offset. we can not know how the rwc change by reading the code directly, it is always right. I prefer old way of it. so keep it when i touch it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue #1599 for discussion .

);

Self {
opcode,
Expand Down Expand Up @@ -364,4 +374,46 @@ mod test {
});
test_oog(&caller(OpcodeId::CALL, stack), &callee, true);
}

#[test]
fn test_oog_call_max_expanded_address() {
// 0xffffffff1 + 0xffffffff0 = 0x1fffffffe1
// > MAX_EXPANDED_MEMORY_ADDRESS (0x1fffffffe0)
let stack = Stack {
gas: Word::MAX,
cd_offset: 0xffffffff1,
cd_length: 0xffffffff0,
rd_offset: 0xffffffff1,
rd_length: 0xffffffff0,
..Default::default()
};
let callee = callee(bytecode! {
PUSH32(Word::from(0))
PUSH32(Word::from(0))
STOP
});
for opcode in TEST_CALL_OPCODES {
test_oog(&caller(*opcode, stack), &callee, true);
}
}

#[test]
fn test_oog_call_max_u64_address() {
let stack = Stack {
gas: Word::MAX,
cd_offset: u64::MAX,
cd_length: u64::MAX,
rd_offset: u64::MAX,
rd_length: u64::MAX,
..Default::default()
};
let callee = callee(bytecode! {
PUSH32(Word::from(0))
PUSH32(Word::from(0))
STOP
});
for opcode in TEST_CALL_OPCODES {
test_oog(&caller(*opcode, stack), &callee, true);
}
}
}
Loading
Loading