Skip to content

Commit

Permalink
feat: use taiko-geth for evm execution
Browse files Browse the repository at this point in the history
  • Loading branch information
johntaiko committed Aug 7, 2023
1 parent c973c78 commit 61798cd
Show file tree
Hide file tree
Showing 31 changed files with 2,756 additions and 44 deletions.
60 changes: 40 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ members = [
"zkevm-circuits",
"bus-mapping",
"geth-utils",
"taiko-geth-utils",
"keccak256",
"gadgets",
"integration-tests",
"circuit-benchmarks",
"eth-types",
"external-tracer",
"taiko-external-tracer",
"mock",
"mock-taiko",
"taiko-mock",
"testool",
]

Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions taiko-external-tracer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "taiko-external-tracer"
version = "0.1.0"
edition = "2021"
authors = ["The appliedzkp team"]
license = "MIT OR Apache-2.0"

[dependencies]
eth-types = { path = "../eth-types" }
taiko-geth-utils = { path = "../taiko-geth-utils" }
serde = { version = "1.0.130", features = ["derive"] }
serde_json = "1.0.66"
77 changes: 77 additions & 0 deletions taiko-external-tracer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! This module generates traces by connecting to an external tracer

use eth_types::{
geth_types::{Account, BlockConstants, Transaction},
Address, Error, GethExecTrace, Word,
};
use serde::Serialize;
use std::collections::HashMap;

/// Configuration structure for `geth_utlis::trace`
#[derive(Debug, Default, Clone, Serialize)]
pub struct TraceConfig {
/// chain id
pub chain_id: Word,
/// history hashes contains most recent 256 block hashes in history, where
/// the lastest one is at history_hashes[history_hashes.len() - 1].
pub history_hashes: Vec<Word>,
/// block constants
pub block_constants: BlockConstants,
/// accounts
pub accounts: HashMap<Address, Account>,
/// transaction
pub transactions: Vec<Transaction>,
/// logger
pub logger_config: LoggerConfig,
}

/// Configuration structure for `logger.Config`
#[derive(Debug, Clone, Serialize)]
pub struct LoggerConfig {
/// enable memory capture
#[serde(rename = "EnableMemory")]
pub enable_memory: bool,
/// disable stack capture
#[serde(rename = "DisableStack")]
pub disable_stack: bool,
/// disable storage capture
#[serde(rename = "DisableStorage")]
pub disable_storage: bool,
/// enable return data capture
#[serde(rename = "EnableReturnData")]
pub enable_return_data: bool,
}

impl Default for LoggerConfig {
fn default() -> Self {
Self {
enable_memory: false,
disable_stack: false,
disable_storage: false,
enable_return_data: true,
}
}
}

impl LoggerConfig {
pub fn enable_memory() -> Self {
Self {
enable_memory: true,
..Self::default()
}
}
}

/// Creates a trace for the specified config
pub fn trace(config: &TraceConfig) -> Result<Vec<GethExecTrace>, Error> {
// Get the trace
let trace_string =
taiko_geth_utils::trace(&serde_json::to_string(&config).unwrap()).map_err(|error| {
match error {
taiko_geth_utils::Error::TracingError(error) => Error::TracingError(error),
}
})?;

let trace = serde_json::from_str(&trace_string).map_err(Error::SerdeError)?;
Ok(trace)
}
10 changes: 10 additions & 0 deletions taiko-geth-utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "taiko-geth-utils"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"

[build-dependencies]
gobuild = "0.1.0-alpha.1"
log = "0.4.14"
env_logger = "0.9"
29 changes: 29 additions & 0 deletions taiko-geth-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Go Ethereum Utility

The module `gethutil` tried to provide identical output from APIs `debug_trace*` of latest `geth` as test vectors for [`zkevm-circuits`](https://github.com/privacy-scaling-explorations/zkevm-circuits).

## Usage

<!-- ### CLI Usage -->
<!-- TODO: Implement a CLI to consume bytecode and output logs -->

### Library Usage

For [`./example/mstore_mload.go`](./example/mstore_mload.go) as an example, it defines bytecode directly by builder `asm`, then write the logs produced by `TraceTx` to stdout. To reproduce the logs, run:

```bash
go run ./example/mstore_mload.go > ./mstore_mload.json
```

### Debugging

The execution traces returned by geth omit some information like execution
errors in some situations. Moreover you may want to inspect some intermediate
values of the EVM execution for debugging purposes.

Print debugging can be easily achieved by replacing the dependency of `go-ethereum` by a local copy of the repository. Just clone `go-ethereum` into a folder next to the `zkevm-circuits` repository, and uncomment the following line in `go.mod`:
```
replace github.com/ethereum/go-ethereum => ../../go-ethereum
```

Now you can add print logs in your `go-ethereum` copy as necessary.
51 changes: 51 additions & 0 deletions taiko-geth-utils/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::{
env,
io::{self, Write},
};

fn main() {
let lib_name = "go-geth-utils";
let out_dir = env::var("OUT_DIR").unwrap();

// Build
if let Err(e) = gobuild::Build::new()
.file("./lib/lib.go")
.try_compile(lib_name)
{
// The error type is private so have to check the error string
if format!("{}", e).starts_with("Failed to find tool.") {
fail(
" Failed to find Go. Please install Go 1.16 or later \
following the instructions at https://golang.org/doc/install.
On linux it is also likely available as a package."
.to_string(),
);
} else {
fail(format!("{}", e));
}
}

// Files the lib depends on that should recompile the lib
let dep_files = vec![
"./gethutil/asm.go",
"./gethutil/trace.go",
"./gethutil/util.go",
"./go.mod",
];
for file in dep_files {
println!("cargo:rerun-if-changed={}", file);
}

// Link
println!("cargo:rustc-link-search=native={}", out_dir);
println!("cargo:rustc-link-lib=static={}", lib_name);
}

fn fail(message: String) {
let _ = writeln!(
io::stderr(),
"\n\nError while building geth-utils: {}\n\n",
message
);
std::process::exit(1);
}
31 changes: 31 additions & 0 deletions taiko-geth-utils/example/add_sub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/ethereum/go-ethereum/common"

"main/gethutil"
)

func main() {
address := common.BytesToAddress([]byte{0xff})
assembly := gethutil.NewAssembly().Add(0xdeadbeef, 0xcafeb0ba).Sub(0xfaceb00c, 0xb0bacafe)

accounts := map[common.Address]gethutil.Account{address: {Code: assembly.Bytecode()}}
tx := gethutil.Transaction{To: &address, GasLimit: 21100}

result, err := gethutil.Trace(gethutil.TraceConfig{Accounts: accounts, Transactions: []gethutil.Transaction{tx}})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to trace tx, err: %v\n", err)
}

bytes, err := json.MarshalIndent(result[0].StructLogs, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to marshal logs, err: %v\n", err)
}

fmt.Fprintln(os.Stdout, string(bytes))
}
31 changes: 31 additions & 0 deletions taiko-geth-utils/example/msize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/ethereum/go-ethereum/common"

"main/gethutil"
)

func main() {
address := common.BytesToAddress([]byte{0xff})
assembly := gethutil.NewAssembly().MStore(0x40, 0x80).MSize().Stop()

accounts := map[common.Address]gethutil.Account{address: {Code: assembly.Bytecode()}}
tx := gethutil.Transaction{To: &address, GasLimit: 21100}

result, err := gethutil.Trace(gethutil.TraceConfig{Accounts: accounts, Transactions: []gethutil.Transaction{tx}})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to trace tx, err: %v\n", err)
}

bytes, err := json.MarshalIndent(result[0].StructLogs, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to marshal logs, err: %v\n", err)
}

fmt.Fprintln(os.Stdout, string(bytes))
}
31 changes: 31 additions & 0 deletions taiko-geth-utils/example/mstore_mload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/ethereum/go-ethereum/common"

"main/gethutil"
)

func main() {
address := common.BytesToAddress([]byte{0xff})
assembly := gethutil.NewAssembly().MStore(0x40, 0x80).MLoad(0x40)

accounts := map[common.Address]gethutil.Account{address: {Code: assembly.Bytecode()}}
tx := gethutil.Transaction{To: &address, GasLimit: 21100}

result, err := gethutil.Trace(gethutil.TraceConfig{Accounts: accounts, Transactions: []gethutil.Transaction{tx}})
if err != nil {
fmt.Fprintf(os.Stderr, "failed to trace tx, err: %v\n", err)
}

bytes, err := json.MarshalIndent(result[0].StructLogs, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to marshal logs, err: %v\n", err)
}

fmt.Fprintln(os.Stdout, string(bytes))
}
Loading

0 comments on commit 61798cd

Please sign in to comment.