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

Commit daf1b99

Browse files
committed
draft for tload tstore
1 parent c65544e commit daf1b99

File tree

8 files changed

+476
-4
lines changed

8 files changed

+476
-4
lines changed

bus-mapping/src/operation.rs

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ impl Target {
143143
| Target::TxRefund
144144
| Target::Account
145145
| Target::Storage
146+
| Target::TransientStorage
146147
)
147148
}
148149
}

eth-types/src/evm_types/opcode_ids.rs

-1
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,6 @@ impl OpcodeId {
906906

907907
/// Returns the all invalid opcodes.
908908
pub fn invalid_opcodes() -> Vec<Self> {
909-
println!("invalid opcodes");
910909
(u8::MIN..=u8::MAX).fold(vec![], |mut acc, val| {
911910
if matches!(val.into(), Self::INVALID(_)) {
912911
acc.push(Self::INVALID(val));

zkevm-circuits/src/evm_circuit/execution.rs

+10
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ mod sload;
129129
mod sstore;
130130
mod stop;
131131
mod swap;
132+
mod tload;
133+
mod tstore;
132134

133135
use self::{
134136
begin_chunk::BeginChunkGadget, block_ctx::BlockCtxGadget, end_chunk::EndChunkGadget,
@@ -214,6 +216,8 @@ use sload::SloadGadget;
214216
use sstore::SstoreGadget;
215217
use stop::StopGadget;
216218
use swap::SwapGadget;
219+
use tload::TloadGadget;
220+
use tstore::TstoreGadget;
217221

218222
pub(crate) trait ExecutionGadget<F: Field> {
219223
const NAME: &'static str;
@@ -318,6 +322,8 @@ pub struct ExecutionConfig<F> {
318322
signextend_gadget: Box<SignextendGadget<F>>,
319323
sload_gadget: Box<SloadGadget<F>>,
320324
sstore_gadget: Box<SstoreGadget<F>>,
325+
tload_gadget: Box<TloadGadget<F>>,
326+
tstore_gadget: Box<TstoreGadget<F>>,
321327
stop_gadget: Box<StopGadget<F>>,
322328
swap_gadget: Box<SwapGadget<F>>,
323329
blockhash_gadget: Box<BlockHashGadget<F>>,
@@ -647,6 +653,8 @@ impl<F: Field> ExecutionConfig<F> {
647653
signextend_gadget: configure_gadget!(),
648654
sload_gadget: configure_gadget!(),
649655
sstore_gadget: configure_gadget!(),
656+
tload_gadget: configure_gadget!(),
657+
tstore_gadget: configure_gadget!(),
650658
stop_gadget: configure_gadget!(),
651659
swap_gadget: configure_gadget!(),
652660
block_ctx_gadget: configure_gadget!(),
@@ -1575,6 +1583,8 @@ impl<F: Field> ExecutionConfig<F> {
15751583
ExecutionState::SIGNEXTEND => assign_exec_step!(self.signextend_gadget),
15761584
ExecutionState::SLOAD => assign_exec_step!(self.sload_gadget),
15771585
ExecutionState::SSTORE => assign_exec_step!(self.sstore_gadget),
1586+
ExecutionState::TLOAD => assign_exec_step!(self.tload_gadget),
1587+
ExecutionState::TSTORE => assign_exec_step!(self.tstore_gadget),
15781588
ExecutionState::STOP => assign_exec_step!(self.stop_gadget),
15791589
ExecutionState::SWAP => assign_exec_step!(self.swap_gadget),
15801590
// dummy errors
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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>, // TODO maybe TLOAD doesn't need this
29+
callee_address: WordLoHiCell<F>,
30+
key: WordLoHiCell<F>,
31+
value: WordLoHiCell<F>,
32+
}
33+
34+
impl<F: Field> ExecutionGadget<F> for TloadGadget<F> {
35+
const NAME: &'static str = "TLOAD";
36+
37+
const EXECUTION_STATE: ExecutionState = ExecutionState::TLOAD;
38+
39+
fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
40+
let opcode = cb.query_cell();
41+
42+
let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
43+
let reversion_info = cb.reversion_info_read(None);
44+
let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress);
45+
46+
let key = cb.query_word_unchecked();
47+
// Pop the key from the stack
48+
cb.stack_pop(key.to_word());
49+
50+
let value = cb.query_word_unchecked();
51+
cb.account_transient_storage_read(
52+
callee_address.to_word(),
53+
key.to_word(),
54+
value.to_word(),
55+
tx_id.expr(),
56+
);
57+
58+
cb.stack_push(value.to_word());
59+
60+
let step_state_transition = StepStateTransition {
61+
rw_counter: Delta(7.expr()),
62+
program_counter: Delta(1.expr()),
63+
reversible_write_counter: Delta(0.expr()),
64+
gas_left: Delta(-OpcodeId::TLOAD.constant_gas_cost().expr()),
65+
..Default::default()
66+
};
67+
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition);
68+
69+
Self {
70+
same_context,
71+
tx_id,
72+
reversion_info,
73+
callee_address,
74+
key,
75+
value,
76+
}
77+
}
78+
79+
fn assign_exec_step(
80+
&self,
81+
region: &mut CachedRegion<'_, '_, F>,
82+
offset: usize,
83+
block: &Block<F>,
84+
_chunk: &Chunk<F>,
85+
tx: &Transaction,
86+
call: &Call,
87+
step: &ExecStep,
88+
) -> Result<(), Error> {
89+
self.same_context.assign_exec_step(region, offset, step)?;
90+
91+
self.tx_id
92+
.assign(region, offset, Value::known(F::from(tx.id)))?;
93+
self.reversion_info.assign(
94+
region,
95+
offset,
96+
call.rw_counter_end_of_reversion,
97+
call.is_persistent,
98+
)?;
99+
self.callee_address
100+
.assign_h160(region, offset, call.address)?;
101+
102+
let mut rws = StepRws::new(block, step);
103+
104+
rws.offset_add(4);
105+
106+
let key = rws.next().stack_value();
107+
rws.next(); // TLOAD rw
108+
let value = rws.next().stack_value();
109+
110+
self.key.assign_u256(region, offset, key)?;
111+
self.value.assign_u256(region, offset, value)?;
112+
113+
Ok(())
114+
}
115+
}
116+
117+
#[cfg(test)]
118+
mod test {
119+
120+
use crate::{evm_circuit::test::rand_word, test_util::CircuitTestBuilder};
121+
use eth_types::{bytecode, Word};
122+
use mock::{test_ctx::helpers::tx_from_1_to_0, TestContext, MOCK_ACCOUNTS};
123+
124+
fn test_ok(key: Word, value: Word) {
125+
// Here we use two bytecodes to test both is_persistent(STOP) or not(REVERT)
126+
// Besides, in bytecode we use two TLOADs,
127+
// the first TLOAD is used to test cold, and the second is used to test warm
128+
let bytecode_success = bytecode! {
129+
PUSH32(key)
130+
TLOAD
131+
STOP
132+
};
133+
let bytecode_failure = bytecode! {
134+
PUSH32(key)
135+
TLOAD
136+
PUSH32(0)
137+
PUSH32(0)
138+
REVERT
139+
};
140+
for bytecode in [bytecode_success, bytecode_failure] {
141+
let ctx = TestContext::<2, 1>::new(
142+
None,
143+
|accs| {
144+
accs[0]
145+
.address(MOCK_ACCOUNTS[0])
146+
.balance(Word::from(10u64.pow(19)))
147+
.code(bytecode)
148+
.storage(vec![(key, value)].into_iter());
149+
accs[1]
150+
.address(MOCK_ACCOUNTS[1])
151+
.balance(Word::from(10u64.pow(19)));
152+
},
153+
tx_from_1_to_0,
154+
|block, _txs| block,
155+
)
156+
.unwrap();
157+
158+
CircuitTestBuilder::new_from_test_ctx(ctx).run();
159+
}
160+
}
161+
162+
#[test]
163+
fn tload_gadget_simple() {
164+
let key = 0x030201.into();
165+
let value = 0x060504.into();
166+
test_ok(key, value);
167+
}
168+
169+
#[test]
170+
fn tload_gadget_rand() {
171+
let key = rand_word();
172+
let value = rand_word();
173+
test_ok(key, value);
174+
}
175+
}

0 commit comments

Comments
 (0)