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

Commit 03da140

Browse files
committed
draft work on tload gadget
1 parent c65544e commit 03da140

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

zkevm-circuits/src/evm_circuit/execution.rs

+4
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ mod sload;
129129
mod sstore;
130130
mod stop;
131131
mod swap;
132+
mod tload;
132133

133134
use self::{
134135
begin_chunk::BeginChunkGadget, block_ctx::BlockCtxGadget, end_chunk::EndChunkGadget,
@@ -214,6 +215,7 @@ use sload::SloadGadget;
214215
use sstore::SstoreGadget;
215216
use stop::StopGadget;
216217
use swap::SwapGadget;
218+
use tload::TloadGadget;
217219

218220
pub(crate) trait ExecutionGadget<F: Field> {
219221
const NAME: &'static str;
@@ -318,6 +320,7 @@ pub struct ExecutionConfig<F> {
318320
signextend_gadget: Box<SignextendGadget<F>>,
319321
sload_gadget: Box<SloadGadget<F>>,
320322
sstore_gadget: Box<SstoreGadget<F>>,
323+
tload_gadget: Box<TloadGadget<F>>,
321324
stop_gadget: Box<StopGadget<F>>,
322325
swap_gadget: Box<SwapGadget<F>>,
323326
blockhash_gadget: Box<BlockHashGadget<F>>,
@@ -647,6 +650,7 @@ impl<F: Field> ExecutionConfig<F> {
647650
signextend_gadget: configure_gadget!(),
648651
sload_gadget: configure_gadget!(),
649652
sstore_gadget: configure_gadget!(),
653+
tload_gadget: configure_gadget!(),
650654
stop_gadget: configure_gadget!(),
651655
swap_gadget: configure_gadget!(),
652656
block_ctx_gadget: configure_gadget!(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
use crate::{
2+
evm_circuit::{
3+
execution::ExecutionGadget,
4+
step::ExecutionState,
5+
util::{
6+
common_gadget::SameContextGadget,
7+
constraint_builder::{
8+
EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta,
9+
},
10+
CachedRegion, Cell, StepRws,
11+
},
12+
witness::{Block, Call, Chunk, ExecStep, Transaction},
13+
},
14+
table::CallContextFieldTag,
15+
util::{
16+
word::{WordExpr, WordLoHiCell},
17+
Expr,
18+
},
19+
};
20+
use bus_mapping::evm::OpcodeId;
21+
use eth_types::Field;
22+
use halo2_proofs::{circuit::Value, plonk::Error};
23+
24+
#[derive(Clone, Debug)]
25+
pub(crate) struct TloadGadget<F> {
26+
same_context: SameContextGadget<F>,
27+
tx_id: Cell<F>,
28+
reversion_info: ReversionInfo<F>,
29+
callee_address: WordLoHiCell<F>,
30+
key: WordLoHiCell<F>,
31+
value: WordLoHiCell<F>,
32+
committed_value: WordLoHiCell<F>,
33+
}
34+
35+
impl<F: Field> ExecutionGadget<F> for TloadGadget<F> {
36+
const NAME: &'static str = "TLOAD";
37+
38+
const EXECUTION_STATE: ExecutionState = ExecutionState::TLOAD;
39+
40+
fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
41+
let opcode = cb.query_cell();
42+
43+
let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
44+
let reversion_info = cb.reversion_info_read(None);
45+
let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress);
46+
47+
let key = cb.query_word_unchecked();
48+
// Pop the key from the stack
49+
cb.stack_pop(key.to_word());
50+
51+
let value = cb.query_word_unchecked();
52+
let committed_value = cb.query_word_unchecked();
53+
cb.account_storage_read(
54+
callee_address.to_word(),
55+
key.to_word(),
56+
value.to_word(),
57+
tx_id.expr(),
58+
committed_value.to_word(),
59+
);
60+
61+
cb.stack_push(value.to_word());
62+
63+
let step_state_transition = StepStateTransition {
64+
rw_counter: Delta(9.expr()),
65+
program_counter: Delta(1.expr()),
66+
reversible_write_counter: Delta(1.expr()),
67+
gas_left: Delta(-OpcodeId::TLOAD.constant_gas_cost().expr()),
68+
..Default::default()
69+
};
70+
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition);
71+
72+
Self {
73+
same_context,
74+
tx_id,
75+
reversion_info,
76+
callee_address,
77+
key,
78+
value,
79+
committed_value,
80+
}
81+
}
82+
83+
fn assign_exec_step(
84+
&self,
85+
region: &mut CachedRegion<'_, '_, F>,
86+
offset: usize,
87+
block: &Block<F>,
88+
_chunk: &Chunk<F>,
89+
tx: &Transaction,
90+
call: &Call,
91+
step: &ExecStep,
92+
) -> Result<(), Error> {
93+
self.same_context.assign_exec_step(region, offset, step)?;
94+
95+
self.tx_id
96+
.assign(region, offset, Value::known(F::from(tx.id)))?;
97+
self.reversion_info.assign(
98+
region,
99+
offset,
100+
call.rw_counter_end_of_reversion,
101+
call.is_persistent,
102+
)?;
103+
self.callee_address
104+
.assign_h160(region, offset, call.address)?;
105+
106+
let mut rws = StepRws::new(block, step);
107+
108+
rws.offset_add(4);
109+
110+
let key = rws.next().stack_value();
111+
let (_, committed_value) = rws.next().aux_pair();
112+
let value = rws.next().stack_value();
113+
114+
self.key.assign_u256(region, offset, key)?;
115+
self.value.assign_u256(region, offset, value)?;
116+
117+
self.committed_value
118+
.assign_u256(region, offset, committed_value)?;
119+
120+
rws.next();
121+
122+
Ok(())
123+
}
124+
}
125+
126+
#[cfg(test)]
127+
mod test {
128+
129+
use crate::{evm_circuit::test::rand_word, test_util::CircuitTestBuilder};
130+
use eth_types::{bytecode, Word};
131+
use mock::{test_ctx::helpers::tx_from_1_to_0, TestContext, MOCK_ACCOUNTS};
132+
133+
fn test_ok(key: Word, value: Word) {
134+
// Here we use two bytecodes to test both is_persistent(STOP) or not(REVERT)
135+
// Besides, in bytecode we use two TLOADs,
136+
// the first TLOAD is used to test cold, and the second is used to test warm
137+
let bytecode_success = bytecode! {
138+
PUSH32(key)
139+
TLOAD
140+
PUSH32(key)
141+
TLOAD
142+
STOP
143+
};
144+
let bytecode_failure = bytecode! {
145+
PUSH32(key)
146+
TLOAD
147+
PUSH32(key)
148+
TLOAD
149+
PUSH32(0)
150+
PUSH32(0)
151+
REVERT
152+
};
153+
for bytecode in [bytecode_success, bytecode_failure] {
154+
let ctx = TestContext::<2, 1>::new(
155+
None,
156+
|accs| {
157+
accs[0]
158+
.address(MOCK_ACCOUNTS[0])
159+
.balance(Word::from(10u64.pow(19)))
160+
.code(bytecode)
161+
.storage(vec![(key, value)].into_iter());
162+
accs[1]
163+
.address(MOCK_ACCOUNTS[1])
164+
.balance(Word::from(10u64.pow(19)));
165+
},
166+
tx_from_1_to_0,
167+
|block, _txs| block,
168+
)
169+
.unwrap();
170+
171+
CircuitTestBuilder::new_from_test_ctx(ctx).run();
172+
}
173+
}
174+
175+
#[test]
176+
fn tload_gadget_simple() {
177+
let key = 0x030201.into();
178+
let value = 0x060504.into();
179+
test_ok(key, value);
180+
}
181+
182+
#[test]
183+
fn tload_gadget_rand() {
184+
let key = rand_word();
185+
let value = rand_word();
186+
test_ok(key, value);
187+
}
188+
}

zkevm-circuits/src/evm_circuit/step.rs

+3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub enum ExecutionState {
119119
MSIZE,
120120
GAS,
121121
JUMPDEST,
122+
TLOAD,
123+
TSTORE,
122124
/// PUSH0, PUSH1, PUSH2, ..., PUSH32
123125
PUSH,
124126
/// DUP1, DUP2, ..., DUP16
@@ -309,6 +311,7 @@ impl From<&ExecStep> for ExecutionState {
309311
OpcodeId::SHL | OpcodeId::SHR => ExecutionState::SHL_SHR,
310312
OpcodeId::SLOAD => ExecutionState::SLOAD,
311313
OpcodeId::SSTORE => ExecutionState::SSTORE,
314+
OpcodeId::TLOAD => ExecutionState::TLOAD,
312315
OpcodeId::CALLDATASIZE => ExecutionState::CALLDATASIZE,
313316
OpcodeId::CALLDATACOPY => ExecutionState::CALLDATACOPY,
314317
OpcodeId::CHAINID => ExecutionState::CHAINID,

0 commit comments

Comments
 (0)