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

Commit

Permalink
draft for tload tstore
Browse files Browse the repository at this point in the history
this fails with a debug assert - EndBlock.get_step_height is 2 instead of 1
  • Loading branch information
zemse committed Apr 5, 2024
1 parent c65544e commit ad710ad
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 4 deletions.
1 change: 1 addition & 0 deletions bus-mapping/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ impl Target {
| Target::TxRefund
| Target::Account
| Target::Storage
| Target::TransientStorage
)
}
}
Expand Down
1 change: 0 additions & 1 deletion eth-types/src/evm_types/opcode_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,6 @@ impl OpcodeId {

/// Returns the all invalid opcodes.
pub fn invalid_opcodes() -> Vec<Self> {
println!("invalid opcodes");
(u8::MIN..=u8::MAX).fold(vec![], |mut acc, val| {
if matches!(val.into(), Self::INVALID(_)) {
acc.push(Self::INVALID(val));
Expand Down
10 changes: 10 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ mod sload;
mod sstore;
mod stop;
mod swap;
mod tload;
mod tstore;

use self::{
begin_chunk::BeginChunkGadget, block_ctx::BlockCtxGadget, end_chunk::EndChunkGadget,
Expand Down Expand Up @@ -214,6 +216,8 @@ use sload::SloadGadget;
use sstore::SstoreGadget;
use stop::StopGadget;
use swap::SwapGadget;
use tload::TloadGadget;
use tstore::TstoreGadget;

pub(crate) trait ExecutionGadget<F: Field> {
const NAME: &'static str;
Expand Down Expand Up @@ -318,6 +322,8 @@ pub struct ExecutionConfig<F> {
signextend_gadget: Box<SignextendGadget<F>>,
sload_gadget: Box<SloadGadget<F>>,
sstore_gadget: Box<SstoreGadget<F>>,
tload_gadget: Box<TloadGadget<F>>,
tstore_gadget: Box<TstoreGadget<F>>,
stop_gadget: Box<StopGadget<F>>,
swap_gadget: Box<SwapGadget<F>>,
blockhash_gadget: Box<BlockHashGadget<F>>,
Expand Down Expand Up @@ -647,6 +653,8 @@ impl<F: Field> ExecutionConfig<F> {
signextend_gadget: configure_gadget!(),
sload_gadget: configure_gadget!(),
sstore_gadget: configure_gadget!(),
tload_gadget: configure_gadget!(),
tstore_gadget: configure_gadget!(),
stop_gadget: configure_gadget!(),
swap_gadget: configure_gadget!(),
block_ctx_gadget: configure_gadget!(),
Expand Down Expand Up @@ -1575,6 +1583,8 @@ impl<F: Field> ExecutionConfig<F> {
ExecutionState::SIGNEXTEND => assign_exec_step!(self.signextend_gadget),
ExecutionState::SLOAD => assign_exec_step!(self.sload_gadget),
ExecutionState::SSTORE => assign_exec_step!(self.sstore_gadget),
ExecutionState::TLOAD => assign_exec_step!(self.tload_gadget),
ExecutionState::TSTORE => assign_exec_step!(self.tstore_gadget),
ExecutionState::STOP => assign_exec_step!(self.stop_gadget),
ExecutionState::SWAP => assign_exec_step!(self.swap_gadget),
// dummy errors
Expand Down
175 changes: 175 additions & 0 deletions zkevm-circuits/src/evm_circuit/execution/tload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use crate::{
evm_circuit::{
execution::ExecutionGadget,
step::ExecutionState,
util::{
common_gadget::SameContextGadget,
constraint_builder::{
EVMConstraintBuilder, ReversionInfo, StepStateTransition, Transition::Delta,
},
CachedRegion, Cell, StepRws,
},
witness::{Block, Call, Chunk, ExecStep, Transaction},
},
table::CallContextFieldTag,
util::{
word::{WordExpr, WordLoHiCell},
Expr,
},
};
use bus_mapping::evm::OpcodeId;
use eth_types::Field;
use halo2_proofs::{circuit::Value, plonk::Error};

#[derive(Clone, Debug)]
pub(crate) struct TloadGadget<F> {
same_context: SameContextGadget<F>,
tx_id: Cell<F>,
reversion_info: ReversionInfo<F>, // TODO maybe TLOAD doesn't need this
callee_address: WordLoHiCell<F>,
key: WordLoHiCell<F>,
value: WordLoHiCell<F>,
}

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

const EXECUTION_STATE: ExecutionState = ExecutionState::TLOAD;

fn configure(cb: &mut EVMConstraintBuilder<F>) -> Self {
let opcode = cb.query_cell();

let tx_id = cb.call_context(None, CallContextFieldTag::TxId);
let reversion_info = cb.reversion_info_read(None);
let callee_address = cb.call_context_read_as_word(None, CallContextFieldTag::CalleeAddress);

let key = cb.query_word_unchecked();
// Pop the key from the stack
cb.stack_pop(key.to_word());

let value = cb.query_word_unchecked();
cb.account_transient_storage_read(
callee_address.to_word(),
key.to_word(),
value.to_word(),
tx_id.expr(),
);

cb.stack_push(value.to_word());

let step_state_transition = StepStateTransition {
rw_counter: Delta(7.expr()),
program_counter: Delta(1.expr()),
reversible_write_counter: Delta(0.expr()),
gas_left: Delta(-OpcodeId::TLOAD.constant_gas_cost().expr()),
..Default::default()
};
let same_context = SameContextGadget::construct(cb, opcode, step_state_transition);

Self {
same_context,
tx_id,
reversion_info,
callee_address,
key,
value,
}
}

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

self.tx_id
.assign(region, offset, Value::known(F::from(tx.id)))?;
self.reversion_info.assign(
region,
offset,
call.rw_counter_end_of_reversion,
call.is_persistent,
)?;
self.callee_address
.assign_h160(region, offset, call.address)?;

let mut rws = StepRws::new(block, step);

rws.offset_add(4);

let key = rws.next().stack_value();
rws.next(); // TLOAD rw
let value = rws.next().stack_value();

self.key.assign_u256(region, offset, key)?;
self.value.assign_u256(region, offset, value)?;

Ok(())
}
}

#[cfg(test)]
mod test {

use crate::{evm_circuit::test::rand_word, test_util::CircuitTestBuilder};
use eth_types::{bytecode, Word};
use mock::{test_ctx::helpers::tx_from_1_to_0, TestContext, MOCK_ACCOUNTS};

fn test_ok(key: Word, value: Word) {
// Here we use two bytecodes to test both is_persistent(STOP) or not(REVERT)
// Besides, in bytecode we use two TLOADs,
// the first TLOAD is used to test cold, and the second is used to test warm
let bytecode_success = bytecode! {
PUSH32(key)
TLOAD
STOP
};
let bytecode_failure = bytecode! {
PUSH32(key)
TLOAD
PUSH32(0)
PUSH32(0)
REVERT
};
for bytecode in [bytecode_success, bytecode_failure] {
let ctx = TestContext::<2, 1>::new(
None,
|accs| {
accs[0]
.address(MOCK_ACCOUNTS[0])
.balance(Word::from(10u64.pow(19)))
.code(bytecode)
.storage(vec![(key, value)].into_iter());
accs[1]
.address(MOCK_ACCOUNTS[1])
.balance(Word::from(10u64.pow(19)));
},
tx_from_1_to_0,
|block, _txs| block,
)
.unwrap();

CircuitTestBuilder::new_from_test_ctx(ctx).run();
}
}

#[test]
fn tload_gadget_simple() {
let key = 0x030201.into();
let value = 0x060504.into();
test_ok(key, value);
}

#[test]
fn tload_gadget_rand() {
let key = rand_word();
let value = rand_word();
test_ok(key, value);
}
}
Loading

0 comments on commit ad710ad

Please sign in to comment.