Assessment reports>Scroll zkEVM>Discussion>Unused tx_id column in StepState

Unused tx_id column in StepState

The StepState for each step of execution in the EVM circuit holds data as follows:

#[derive(Clone, Debug)]
pub(crate) struct StepState<F> {
    /// The execution state selector for the step
    pub(crate) execution_state: DynamicSelectorHalf<F>,
    /// The Read/Write counter
    pub(crate) rw_counter: Cell<F>,
    /// The unique identifier of call in the whole proof, using the
    /// `rw_counter` at the call step.
    pub(crate) call_id: Cell<F>,
    /// The transaction id of this transaction within the block.
    pub(crate) tx_id: Cell<F>,
    /// Whether the call is root call
    pub(crate) is_root: Cell<F>,
    /// Whether the call is a create call
    pub(crate) is_create: Cell<F>,
    /// The block number the state currently is in. This is particularly
    /// important as multiple blocks can be assigned and proven in a single
    /// circuit instance.
    pub(crate) block_number: Cell<F>,
    /// Denotes the hash of the bytecode for the current call.
    /// In the case of a contract creation root call, this denotes the hash of
    /// the tx calldata.
    /// In the case of a contract creation internal call, this denotes the hash
    /// of the chunk of bytes from caller's memory that represent the
    /// contract init code.
    pub(crate) code_hash: Cell<F>,
    /// The program counter
    pub(crate) program_counter: Cell<F>,
    /// The stack pointer
    pub(crate) stack_pointer: Cell<F>,
    /// The amount of gas left
    pub(crate) gas_left: Cell<F>,
    /// Memory size in words (32 bytes)
    pub(crate) memory_word_size: Cell<F>,
    /// The counter for reversible writes
    pub(crate) reversible_write_counter: Cell<F>,
    /// The counter for log index
    pub(crate) log_id: Cell<F>,
    /// Whether this is end_tx. Boolean.
    pub(crate) end_tx: Cell<F>,
}

However, the field tx_id is never used, only assigned to. While in various places of the EVM circuit the transaction ID is needed, it is always taken from a lookup in the call context rather than from the StepState, like so (line taken from SstoreGadget::configure):

let tx_id = cb.call_context(None, CallContextFieldTag::TxId);

The tx_id field of StepState could thus be removed to save some cells and avoid confusion.

Zellic © 2024Back to top ↑