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

Commit

Permalink
[Doc] Cleanup Bus-Mapping, ExecutionSteps, and ExecutionTrace (#1775)
Browse files Browse the repository at this point in the history
### Description

- Bus-Mapping has two library docs, one is inside the lib.rs, another
locates in README.md, untested. We remove the one in lib.rs and make the
README one checked.
- ExecutionSteps and ExecutionTrace were 

We hope the update can reduce confusion.

### Issue Link


### Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [x] This change requires a documentation update
- [ ] Refactor (no updates to logic)

### How Has This Been Tested?

``` 
cargo test --doc
```

---------

Co-authored-by: sm.wu <[email protected]>
  • Loading branch information
ChihChengLiang and hero78119 authored Feb 26, 2024
1 parent 4bdc733 commit 8e2e74a
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 317 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ stats_evm_circuit: # Print a table with EVM Circuit stats by ExecState/opcode
stats_copy_circuit: # Print a table with Copy Circuit stats by ExecState/opcode
@cargo run --bin stats --features stats -- copy

evm_exec_steps_occupancy: # Print a table for each EVM-CellManager CellType with the top 10 occupancy ExecutionSteps associated
evm_exec_steps_occupancy: # Print a table for each EVM-CellManager CellType with the top 10 occupancy ExecSteps associated
@cargo run --bin stats --features stats -- exec

.PHONY: clippy doc fmt test test_benches test-all evm_bench state_bench circuit_benches evm_exec_steps_occupancy stats_state_circuit stats_evm_circuit stats_copy_circuit help
166 changes: 78 additions & 88 deletions bus-mapping/README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,36 @@
# ZKEVM Bus-Mapping

![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/appliedzkp/zkevm-circuits/CI%20checks/main?style=for-the-badge)
The `Bus-Mapping` crate is designed to parse EVM execution traces and manipulate the data they provide to obtain structured witness inputs for the EVM Proof and the State Proof.

`Bus-Mapping` is a crate designed to parse EVM execution traces and manipulate
all of the data they provide in order to obtain structured witness inputs
for the EVM Proof and the State Proof.
## Introduction

### Introduction
At the moment every node on ethereum has to validate every transaction in
the ethereum virtual machine. This means that every transaction adds work
that everyone needs to do to verify Ethereum’s history. Worse still is that
each transaction needs to be verified by every new node. Which means the
amount of work a new node needs to do the sync the network is growing
constantly. We want to build a proof of validity for the Ethereum blocks to
avoid this.
Currently, every node on Ethereum must validate every transaction in the Ethereum Virtual Machine (EVM). This means that each transaction adds work that everyone must do to verify Ethereum’s history. Furthermore, each transaction needs to be verified by every new node, leading to a growing amount of work for new nodes to sync the network. To address this, we aim to build a proof of validity for Ethereum blocks.

This means making a proof of validity for the EVM + state reads / writes +
signatures.
To simplify we separate our proofs into two components.
This involves creating a proof of validity for the EVM, including state reads/writes and signatures. To simplify, we divide our proofs into two components:

- State proof: State/memory/stack ops have been performed correctly. This
does not check if the correct location has been read/written. We allow our
prover to pick any location here and in the EVM proof confirm it is correct.
- State Proof: Validates that state/memory/stack operations have been performed correctly. However, it does not verify if the correct location has been read/written. Our prover can select any location here and in the EVM proof confirm its correctness.
- EVM Proof: Validates that the correct opcode is called at the correct time, checking the validity of these opcodes. It also confirms that for each of these opcodes, the state proof performed the correct operation.

- EVM proof: This checks that the correct opcode is called at the correct
time. It checks the validity of these opcodes. It also confirms that for
each of these opcodes the state proof performed the correct operation.
Only after verifying both proofs can we be confident that the Ethereum block is executed correctly.

Only after verifying both proofs are we confident that that Ethereum block
is executed correctly.
## Bus Mapping

### Bus Mapping
The goal of this crate is to serve as:
- A parsing lib for EVM execution traces.
- A way to infer some witness data that can only be constructed once we've
analyzed the full exec trace.
- An easy interface to collect all of the data to witness into the circuits
and witness it with few function calls.

### Parsing
Provided a JSON file or a JSON as a stream of bytes, which contains an
execution trace from an EVM, you can parse it and construct an
`ExecutionTrace` instance from it. That will automatically fill all of the
bus-mapping instances of each
[`ExecutionStep`](crate::exec_trace::ExecutionStep) plus fill in an
[`OperationContainer`](crate::operation::container::OperationContainer) with
all of the Memory, Stack and Storage ops performed by the provided trace.

- A parsing library for EVM execution traces.
- A way to infer some witness data that can only be constructed once we've analyzed the full exec trace.
- An easy interface to collect all of the data to witness into the circuits and witness it with few function calls.

## Parsing

Given a JSON file or a JSON stream containing an execution trace from an EVM, you can parse it and construct a [`GethExecTrace`](eth_types::GethExecTrace) instance from it. This will automatically populate all of the bus-mapping instances of each [`ExecStep`](crate::circuit_input_builder::ExecStep) and fill an [`OperationContainer`](crate::operation::OperationContainer) with all of the memory, stack, and storage operations performed by the provided trace.

```rust
use bus_mapping::{ExecutionTrace, ExecutionStep, BlockConstants, Error, evm::EvmWord};
use bus_mapping::mock::BlockData;
use eth_types::{
GethExecTrace, GethExecStep, geth_types::GethData, bytecode
};
use mock::test_ctx::{TestContext, helpers::*};

let input_trace = r#"
[
Expand Down Expand Up @@ -98,31 +80,48 @@ let input_trace = r#"
]
"#;

let block_ctants = BlockConstants::new(
Word::from(0),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
pasta_curves::Fp::zero(),
);

// Here we have the ExecutionTrace completely formed with all of the data to witness structured.
let obtained_exec_trace = ExecutionTrace::from_trace_bytes(
input_trace.as_bytes(),
block_ctants,
).expect("Error on trace generation");
// We use the [`TestContext`] struct to mock a block.
let code = bytecode! {
// Write 0x6f to storage slot 0
PUSH1(0x6fu64)
PUSH1(0x00u64)
SSTORE
// Load storage slot 0
PUSH1(0x00u64)
SLOAD
STOP
};
// Get the execution steps from the external tracer
let block: GethData = TestContext::<2, 1>::new(
None,
account_0_code_account_1_no_code(code),
tx_from_1_to_0,
|block, _tx| block.number(0xcafeu64),
)
.unwrap()
.into();
// Here we update the circuit input with the data from the transaction trace.
let builder = BlockData::new_from_geth_data(block.clone()).new_circuit_input_builder();
let builder = builder
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();
let geth_steps: Vec<GethExecStep> = serde_json::from_str(input_trace).unwrap();
let _geth_trace = GethExecTrace {
return_value: "".to_string(),
gas: block.eth_block.transactions[0].gas.as_u64(),
invalid: false,
failed: false,
struct_logs: geth_steps,
};

// Get an ordered vector with all of the Stack operations of this trace.
let stack_ops = obtained_exec_trace.sorted_stack_ops();

let _stack_ops = builder.block.container.sorted_stack();
// You can also iterate over the steps of the trace and witness the EVM Proof.
obtained_exec_trace.steps().iter();
let _ = builder.block.txs()[0].steps().iter();
```

Assume we have the following trace:
Assuming we have the following trace:

```text,ignore
pc op stack (top -> down) memory
-- -------------- ---------------------------------- ---------------------------------------
Expand All @@ -148,37 +147,28 @@ pc op stack (top -> down) memory
...
```

Once you have the trace built (following the code found above) you can
basically:
- Get an iterator/vector over the `Stack`, `Memory` or `Storage` operations
ordered on the way the State Proof needs.
Once you have built the trace (following the code above), you can:

- Get an iterator/vector over the `Stack`, `Memory`, or `Storage` operations ordered in the way the State Proof needs.

For the Memory operations, it might look like this:

On that way, we would get something like this for the Memory ops:
```text,ignore
| `key` | `val` | `rw` | `gc` | Note |
|:------:| ------------- | ------- | ---- | ---------------------------------------- |
| `0x40` | `0` | `Write` | | Init |
| `0x40` | `0x80` | `Write` | 0 | Assume written at the beginning of `code`|
| `0x40` | `0x80` | `Read` | 4 | `56 MLOAD` |
| - | | | | |
| `0x80` | `0` | `Write` | | Init |
| `0x80` | `0xdeadbeef` | `Write` | 10 | `63 MSTORE` |
| `0x80` | `0xdeadbeef` | `Read` | 16 | `70 MLOAD` |
| `0x80` | `0x1d97c6efb` | `Write` | 24 | `73 MSTORE` |
| - | | | | |
| `0xa0` | `0` | `Write` | | Init |
| `0xa0` | `0xcafeb0ba` | `Write` | 34 | `83 MSTORE`
| `key` | `val` | `rw` | `gc` | Note |
| :----: | ------------- | ------- | ---- | ----------------------------------------- |
| `0x40` | `0` | `Write` | | Init |
| `0x40` | `0x80` | `Write` | 0 | Assume written at the beginning of `code` |
| `0x40` | `0x80` | `Read` | 4 | `56 MLOAD` |
| - | | | | |
| `0x80` | `0` | `Write` | | Init |
| `0x80` | `0xdeadbeef` | `Write` | 10 | `63 MSTORE` |
| `0x80` | `0xdeadbeef` | `Read` | 16 | `70 MLOAD` |
| `0x80` | `0x1d97c6efb` | `Write` | 24 | `73 MSTORE` |
| - | | | | |
| `0xa0` | `0` | `Write` | | Init |
| `0xa0` | `0xcafeb0ba` | `Write` | 34 | `83 MSTORE` |
```

Where as you see, we group by `memory_address` and then order by
`global_counter`.

- Iterate over the `ExecutionTrace` itself over
each `ExecutionStep`'s is formed by and check which Stack/Memory&Storage operations are linked to each step.
This is also automatically done via the
[`Opcode`](crate::evm::opcodes::Opcode) trait defined in this crate.
Here, we group by `memory_address` and then order by `global_counter`.

### Documentation
For extra documentation, check the book with the specs written for the
entire ZK-EVM solution.
See: <https://hackmd.io/@liangcc/zkvmbook/https%3A%2F%2Fhackmd.io%2FAmhZ2ryITxicmhYFyQ0DEw#Bus-Mapping>
- Iterate over the [`GethExecTrace`](eth_types::GethExecTrace) itself, over each [`ExecStep`](crate::circuit_input_builder::ExecStep) formed by, and check which Stack/Memory&Storage operations are linked to each step. This is also automatically done via the [`Opcode`](crate::evm::opcodes::Opcode) trait defined in this crate.
5 changes: 2 additions & 3 deletions bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl<'a> CircuitInputStateRef<'a> {
}
}

/// Push an [`Operation`](crate::operation::Operation) into the
/// Push an [`Operation`] into the
/// [`OperationContainer`](crate::operation::OperationContainer) with the
/// next [`RWCounter`](crate::operation::RWCounter) and then adds a
/// reference to the stored operation ([`OperationRef`]) inside the
Expand Down Expand Up @@ -196,8 +196,7 @@ impl<'a> CircuitInputStateRef<'a> {
self.push_op(step, RW::WRITE, op)
}

/// Push an [`Operation`](crate::operation::Operation) with reversible to be
/// true into the
/// Push an [`Operation`] with reversible to be true into the
/// [`OperationContainer`](crate::operation::OperationContainer) with the
/// next [`RWCounter`](crate::operation::RWCounter) and then adds a
/// reference to the stored operation
Expand Down
3 changes: 1 addition & 2 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,7 @@ pub use crate::precompile::PrecompileCallArgs;

/// Generic opcode trait which defines the logic of the
/// [`Operation`](crate::operation::Operation) that should be generated for one
/// or multiple [`ExecStep`](crate::circuit_input_builder::ExecStep) depending
/// of the [`OpcodeId`] it contains.
/// or multiple [`ExecStep`] depending of the [`OpcodeId`] it contains.
pub trait Opcode: Debug {
/// Generate the associated [`MemoryOp`](crate::operation::MemoryOp)s,
/// [`StackOp`](crate::operation::StackOp)s, and
Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/evm/opcodes/error_oog_exp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
use eth_types::GethExecStep;

/// Placeholder structure used to implement [`Opcode`] trait over it
/// corresponding to the [`OogError::Exp`](crate::error::OogError::Exp).
/// corresponding to the [`OogError::Exp`].
#[derive(Clone, Copy, Debug)]
pub(crate) struct OOGExp;

Expand Down
3 changes: 1 addition & 2 deletions bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use crate::{
use eth_types::{evm_types::OpcodeId, GethExecStep, ToAddress};

/// Placeholder structure used to implement [`Opcode`] trait over it
/// corresponding to the
/// [`OogError::MemoryCopy`](crate::error::OogError::MemoryCopy).
/// corresponding to the [`OogError::MemoryCopy`].
#[derive(Clone, Copy, Debug)]
pub(crate) struct OOGMemoryCopy;

Expand Down
3 changes: 1 addition & 2 deletions bus-mapping/src/evm/opcodes/error_oog_sload_sstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use crate::{
use eth_types::{GethExecStep, ToWord};

/// Placeholder structure used to implement [`Opcode`] trait over it
/// corresponding to the
/// [`OogError::SloadSstore`](crate::error::OogError::SloadSstore).
/// corresponding to the [`OogError::SloadSstore`].
#[derive(Clone, Copy, Debug)]
pub(crate) struct OOGSloadSstore;

Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/exec_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::fmt;

#[derive(Clone, Copy, PartialEq, Eq)]
/// The target and index of an `Operation` in the context of an
/// `ExecutionTrace`.
/// [`GethExecTrace`](eth_types::GethExecTrace).
pub struct OperationRef(pub Target, pub usize);

impl fmt::Debug for OperationRef {
Expand Down
Loading

0 comments on commit 8e2e74a

Please sign in to comment.