mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
feat(rollup): add circuits capacity checker (#321)
* add proof for predeployed storages * reverse inneeded code * update for mainbranch merging * add pertx storage trace * dummy tx proof * add txstorage trace * add coinbase storage as trace * enable (sync) tracing by default * basic * init cgo framework * fix break loop * integrate the right zkevm version (#323) * finish rust codes * use dylib (#325) * flip * ? * use cdylib * revert * fix * apply_tx * rename * fixing types fixing types fixing types * clean up * ExecutionResults (#328) * filling * filling * more * clean up * filling * coinbase * add * MPTWitness * ExecutionResults WIP * L1fee L1fee * sender * to * Failed & ReturnValue * createdAcc & after * remove MPTWitness * txStorageTrace * add FeeRecipient * add StorageTrace * fix FFI types * better logger * cargo fmt * fix * add build tags * update Makefile * fix library * improve ld path * correctly deal with circuit_capacity_checker returned result * fix return value * update cargo (#333) * update cargo * update * update go * refactor * raname `circuits capacity checker` to `circuit capacity checker` * some refactorings * [Fix] storage proof generation in capacity checker (#348) * make per-tx storage and deletion proof work * format * fix misplaced markdeletion --------- Co-authored-by: HAOYUatHZ <haoyu@protonmail.com> * docker (#363) * update Dockerfile * build: update go version to 1.19 * update * fix * fix * try * simplify * revert go version update l2geth Dockerfiles * fix * fix coinbase * fix (#369) * format * Update version.go * address comments * Capacity refactor (#374) * init * id * support multiple instances * fix id * fix conflicts * refactor to use same codes (#379) * re-init * WIP * WIP * refactor * go * minor * fix storage proof of l1gas price oracle * move 1 * move 2 * move 3 * move 4 * move 5 move 5 * move 6 move 6 * move 7 * move 8 * move 9 * move 10 * clean up clean up --------- Co-authored-by: Ho Vei <noelwei@gmail.com> * finish basic * minor * config capacity check in block_validator (#380) * init * done ref * fix tests fix tests fix tests fix tests * add more comments * apply_block * improve logs * cargo fmt * Capacity big refactor (#383) * CreateTraceEnv * WIP * draft more fix * for test * fortet * clean up * add more comments * goimports -local github.com/scroll-tech/go-ethereum -w . * fix typos * attempt 1 * attempt 2 * attempt 3 * gogogo * clean up * fix * fix * rename * minor * fix * minor * minor * improve doc * use dedicated `checkCircuitCapacity` flag (#394) * refactor * fix * add lock * [feat] capacity checking: upgrade libzkp (#395) * upgrade * upgrade libzkp * write RowConsumption (#396) * write RowConsumption * name alignments * revert some formatting * add lock to CircuitCapacityChecker in BlockValidator * remove mutex pointer * improve github workflow * improve * store row consumption in mining (#397) * prepare * finish * add more logs * mark `ApplyBlock` as ready * update libzkp (#401) * fix * Capacity detail (#402) * fix(block-validation): consider skipping in ValidateL1Messages (#405) * fix(block-validation): consider skipping in ValidateL1Messages * fix(block): consider skipping in L1MessageCount * fix l1 validation tests * fix NumL1Messages * fix impl.go return types fix * better error handling (#407) * add add * add * add * add * add * cargo fmt * add * update * add * WIP * minor * gogogo * gogogo * fix * fix * fix * cargo clippy * improve * improve * creation lock (#408) * creation lock * update * Debug log (#409) * add more logs * more * more * fix * improve * Update cmd/utils/flags.go Co-authored-by: Péter Garamvölgyi <peter@scroll.io> * refactor worker.commit() * avoid re-calculate * txpool ccc err handling (#411) * more explicit error comments * add more logs * fix unnecessary commit * add more logs * fix `ineffassign` * add more comments * log id for `NewCircuitCapacityChecker` (#414) add log to `NewCircuitCapacityChecker` * Persist skip info for block where all L1 msgs are skipped (#415) persist skip info for block where all L1 msgs are skipped * Update version.go --------- Co-authored-by: Ho Vei <noelwei@gmail.com> Co-authored-by: Zhang Zhuo <mycinbrin@gmail.com> Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
This commit is contained in:
parent
134e1b8f92
commit
2f9edf73ca
56 changed files with 5986 additions and 689 deletions
21
.github/workflows/l2geth_ci.yml
vendored
21
.github/workflows/l2geth_ci.yml
vendored
|
|
@ -13,7 +13,7 @@ on:
|
||||||
- ready_for_review
|
- ready_for_review
|
||||||
name: CI
|
name: CI
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-mock-ccc-geth: # build geth with mock circuit capacity checker
|
||||||
if: github.event.pull_request.draft == false
|
if: github.event.pull_request.draft == false
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -23,6 +23,25 @@ jobs:
|
||||||
go-version: 1.18.x
|
go-version: 1.18.x
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
make nccc_geth
|
||||||
|
build-geth: # build geth with circuit capacity checker
|
||||||
|
if: github.event_name == 'push' # will only be triggered when pushing to main & staging & develop & alpha
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.19.x
|
||||||
|
- name: Install rust
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly-2022-12-10
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make geth
|
make geth
|
||||||
|
|
|
||||||
32
Dockerfile
32
Dockerfile
|
|
@ -3,19 +3,39 @@ ARG COMMIT=""
|
||||||
ARG VERSION=""
|
ARG VERSION=""
|
||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# Build libzkp dependency
|
||||||
FROM golang:1.18-alpine as builder
|
FROM scrolltech/go-rust-builder:go-1.19-rust-nightly-2022-12-10 as chef
|
||||||
|
WORKDIR app
|
||||||
|
|
||||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
FROM chef as planner
|
||||||
|
COPY ./rollup/circuitcapacitychecker/libzkp/ .
|
||||||
|
RUN cargo chef prepare --recipe-path recipe.json
|
||||||
|
|
||||||
|
FROM chef as zkp-builder
|
||||||
|
COPY ./rollup/circuitcapacitychecker/libzkp/rust-toolchain ./
|
||||||
|
COPY --from=planner /app/recipe.json recipe.json
|
||||||
|
RUN cargo chef cook --release --recipe-path recipe.json
|
||||||
|
|
||||||
|
COPY ./rollup/circuitcapacitychecker/libzkp .
|
||||||
|
RUN cargo build --release
|
||||||
|
RUN find ./ | grep libzktrie.so | xargs -I{} cp {} /app/target/release/
|
||||||
|
|
||||||
|
# Build Geth in a stock Go builder container
|
||||||
|
FROM scrolltech/go-rust-builder:go-1.19-rust-nightly-2022-12-10 as builder
|
||||||
|
|
||||||
ADD . /go-ethereum
|
ADD . /go-ethereum
|
||||||
RUN cd /go-ethereum && go run build/ci.go install ./cmd/geth
|
COPY --from=zkp-builder /app/target/release/libzkp.so /usr/local/lib/
|
||||||
|
COPY --from=zkp-builder /app/target/release/libzktrie.so /usr/local/lib/
|
||||||
|
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/
|
||||||
|
RUN cd /go-ethereum && env GO111MODULE=on go run build/ci.go install -buildtags circuit_capacity_checker ./cmd/geth
|
||||||
|
|
||||||
# Pull Geth into a second stage deploy alpine container
|
# Pull Geth into a second stage deploy alpine container
|
||||||
FROM alpine:latest
|
FROM ubuntu:20.04
|
||||||
|
|
||||||
RUN apk add --no-cache ca-certificates
|
|
||||||
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
|
||||||
|
COPY --from=zkp-builder /app/target/release/libzkp.so /usr/local/lib/
|
||||||
|
COPY --from=zkp-builder /app/target/release/libzktrie.so /usr/local/lib/
|
||||||
|
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/
|
||||||
|
|
||||||
EXPOSE 8545 8546 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
ENTRYPOINT ["geth"]
|
ENTRYPOINT ["geth"]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ ARG VERSION=""
|
||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.18-alpine as builder
|
FROM golang:1.19-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
|
|
||||||
|
|
|
||||||
13
Makefile
13
Makefile
|
|
@ -2,17 +2,26 @@
|
||||||
# with Go source code. If you know what GOPATH is then you probably
|
# with Go source code. If you know what GOPATH is then you probably
|
||||||
# don't need to bother with make.
|
# don't need to bother with make.
|
||||||
|
|
||||||
.PHONY: geth android ios evm all test clean
|
.PHONY: geth android ios evm all test clean libzkp
|
||||||
|
|
||||||
GOBIN = ./build/bin
|
GOBIN = ./build/bin
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
GORUN = env GO111MODULE=on go run
|
GORUN = env GO111MODULE=on go run
|
||||||
|
|
||||||
geth:
|
|
||||||
|
libzkp:
|
||||||
|
cd $(PWD)/rollup/circuitcapacitychecker/libzkp && make libzkp
|
||||||
|
|
||||||
|
nccc_geth: ## geth without circuit capacity checker
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||||
|
|
||||||
|
geth: libzkp
|
||||||
|
$(GORUN) build/ci.go install -buildtags circuit_capacity_checker ./cmd/geth
|
||||||
|
@echo "Done building."
|
||||||
|
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||||
|
|
||||||
all:
|
all:
|
||||||
$(GORUN) build/ci.go install
|
$(GORUN) build/ci.go install
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ type SimulatedBackend struct {
|
||||||
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||||
genesis.MustCommit(database)
|
genesis.MustCommit(database)
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
|
|
||||||
backend := &SimulatedBackend{
|
backend := &SimulatedBackend{
|
||||||
database: database,
|
database: database,
|
||||||
|
|
|
||||||
10
build/ci.go
10
build/ci.go
|
|
@ -199,9 +199,10 @@ func main() {
|
||||||
|
|
||||||
func doInstall(cmdline []string) {
|
func doInstall(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
dlgo = flag.Bool("dlgo", false, "Download Go and build with it")
|
||||||
arch = flag.String("arch", "", "Architecture to cross build for")
|
arch = flag.String("arch", "", "Architecture to cross build for")
|
||||||
cc = flag.String("cc", "", "C compiler to cross build with")
|
cc = flag.String("cc", "", "C compiler to cross build with")
|
||||||
|
buildtags = flag.String("buildtags", "", "Tags for go build")
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
||||||
|
|
@ -215,6 +216,9 @@ func doInstall(cmdline []string) {
|
||||||
// Configure the build.
|
// Configure the build.
|
||||||
env := build.Env()
|
env := build.Env()
|
||||||
gobuild := tc.Go("build", buildFlags(env)...)
|
gobuild := tc.Go("build", buildFlags(env)...)
|
||||||
|
if len(*buildtags) != 0 {
|
||||||
|
gobuild.Args = append(gobuild.Args, "-tags", *buildtags)
|
||||||
|
}
|
||||||
|
|
||||||
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
|
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
|
||||||
// better disable it. This check isn't the best, it should probably
|
// better disable it. This check isn't the best, it should probably
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,12 @@ var (
|
||||||
Name: "l1.sync.startblock",
|
Name: "l1.sync.startblock",
|
||||||
Usage: "L1 block height to start syncing from. Should be set to the L1 message queue deployment block number.",
|
Usage: "L1 block height to start syncing from. Should be set to the L1 message queue deployment block number.",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Circuit capacity check settings
|
||||||
|
CircuitCapacityCheckEnabledFlag = cli.BoolFlag{
|
||||||
|
Name: "ccc",
|
||||||
|
Usage: "Enable circuit capacity check during block validation",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||||
|
|
@ -1493,6 +1499,12 @@ func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setCircuitCapacityCheck(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
|
if ctx.GlobalIsSet(CircuitCapacityCheckEnabledFlag.Name) {
|
||||||
|
cfg.CheckCircuitCapacity = ctx.GlobalBool(CircuitCapacityCheckEnabledFlag.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckExclusive verifies that only a single instance of the provided flags was
|
// CheckExclusive verifies that only a single instance of the provided flags was
|
||||||
// set by the user. Each flag might optionally be followed by a string type to
|
// set by the user. Each flag might optionally be followed by a string type to
|
||||||
// specialize it further.
|
// specialize it further.
|
||||||
|
|
@ -1558,6 +1570,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
setMiner(ctx, &cfg.Miner)
|
setMiner(ctx, &cfg.Miner)
|
||||||
setWhitelist(ctx, cfg)
|
setWhitelist(ctx, cfg)
|
||||||
setLes(ctx, cfg)
|
setLes(ctx, cfg)
|
||||||
|
setCircuitCapacityCheck(ctx, cfg)
|
||||||
|
|
||||||
// Cap the cache allowance and tune the garbage collector
|
// Cap the cache allowance and tune the garbage collector
|
||||||
mem, err := gopsutil.VirtualMemory()
|
mem, err := gopsutil.VirtualMemory()
|
||||||
|
|
@ -2006,7 +2019,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||||
|
|
||||||
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
|
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
|
||||||
// Disable transaction indexing/unindexing by default.
|
// Disable transaction indexing/unindexing by default.
|
||||||
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil)
|
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
genesis := genspec.MustCommit(db)
|
genesis := genspec.MustCommit(db)
|
||||||
|
|
||||||
// Generate a batch of blocks, each properly signed
|
// Generate a batch of blocks, each properly signed
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
||||||
|
|
@ -89,7 +89,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
genspec.MustCommit(db)
|
genspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
||||||
|
|
@ -102,7 +102,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
// Simulate a crash by creating a new chain on top of the database, without
|
// Simulate a crash by creating a new chain on top of the database, without
|
||||||
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
// flushing the dirty states out. Insert the last block, triggering a sidechain
|
||||||
// reimport.
|
// reimport.
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -450,7 +450,7 @@ func TestClique(t *testing.T) {
|
||||||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||||
}
|
}
|
||||||
// Pass all the headers through clique and ensure tallying succeeds
|
// Pass all the headers through clique and ensure tallying succeeds
|
||||||
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,7 @@ var (
|
||||||
|
|
||||||
// ErrInvalidL1MessageOrder is returned if a block contains L1 messages in the wrong
|
// ErrInvalidL1MessageOrder is returned if a block contains L1 messages in the wrong
|
||||||
// order. Possible scenarios are: (1) L1 messages do not follow their QueueIndex order,
|
// order. Possible scenarios are: (1) L1 messages do not follow their QueueIndex order,
|
||||||
// (2) the block skipped one or more L1 messages, (3) L1 messages are not included in
|
// (2) L1 messages are not included in a contiguous block at the front of the block.
|
||||||
// a contiguous block at the front of the block.
|
|
||||||
ErrInvalidL1MessageOrder = errors.New("invalid L1 message order")
|
ErrInvalidL1MessageOrder = errors.New("invalid L1 message order")
|
||||||
|
|
||||||
// ErrUnknownL1Message is returned if a block contains an L1 message that does not
|
// ErrUnknownL1Message is returned if a block contains an L1 message that does not
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -316,7 +316,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, &cacheConfig, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,18 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/consensus"
|
"github.com/scroll-tech/go-ethereum/consensus"
|
||||||
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
"github.com/scroll-tech/go-ethereum/core/rawdb"
|
||||||
"github.com/scroll-tech/go-ethereum/core/state"
|
"github.com/scroll-tech/go-ethereum/core/state"
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
"github.com/scroll-tech/go-ethereum/ethdb"
|
||||||
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/circuitcapacitychecker"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -35,15 +40,25 @@ type BlockValidator struct {
|
||||||
config *params.ChainConfig // Chain configuration options
|
config *params.ChainConfig // Chain configuration options
|
||||||
bc *BlockChain // Canonical block chain
|
bc *BlockChain // Canonical block chain
|
||||||
engine consensus.Engine // Consensus engine used for validating
|
engine consensus.Engine // Consensus engine used for validating
|
||||||
|
|
||||||
|
// circuit capacity checker related fields
|
||||||
|
checkCircuitCapacity bool // whether enable circuit capacity check
|
||||||
|
db ethdb.Database // db to store row consumption
|
||||||
|
cMu sync.Mutex // mutex for circuit capacity checker
|
||||||
|
circuitCapacityChecker *circuitcapacitychecker.CircuitCapacityChecker // circuit capacity checker instance
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
|
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine, db ethdb.Database, checkCircuitCapacity bool) *BlockValidator {
|
||||||
validator := &BlockValidator{
|
validator := &BlockValidator{
|
||||||
config: config,
|
config: config,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
bc: blockchain,
|
bc: blockchain,
|
||||||
|
checkCircuitCapacity: checkCircuitCapacity,
|
||||||
|
db: db,
|
||||||
|
circuitCapacityChecker: circuitcapacitychecker.NewCircuitCapacityChecker(),
|
||||||
}
|
}
|
||||||
|
log.Info("created new BlockValidator", "CircuitCapacityChecker ID", validator.circuitCapacityChecker.ID)
|
||||||
return validator
|
return validator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,18 +94,34 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
}
|
}
|
||||||
return consensus.ErrPrunedAncestor
|
return consensus.ErrPrunedAncestor
|
||||||
}
|
}
|
||||||
return v.ValidateL1Messages(block)
|
if err := v.ValidateL1Messages(block); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if v.checkCircuitCapacity {
|
||||||
|
// if a block's RowConsumption has been stored, which means it has been processed before,
|
||||||
|
// (e.g., in miner/worker.go or in insertChain),
|
||||||
|
// we simply skip its calculation and validation
|
||||||
|
if rawdb.ReadBlockRowConsumption(v.db, block.Hash()) != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rowConsumption, err := v.validateCircuitRowConsumption(block)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawdb.WriteBlockRowConsumption(v.db, block.Hash(), rowConsumption)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateL1Messages validates L1 messages contained in a block.
|
// ValidateL1Messages validates L1 messages contained in a block.
|
||||||
// We check the following conditions:
|
// We check the following conditions:
|
||||||
// - L1 messages are in a contiguous section at the front of the block.
|
// - L1 messages are in a contiguous section at the front of the block.
|
||||||
// - The first L1 message's QueueIndex is right after the last L1 message included in the chain.
|
// - The first L1 message's QueueIndex is right after the last L1 message included in the chain.
|
||||||
// - L1 messages follow the QueueIndex order. No L1 message is skipped.
|
// - L1 messages follow the QueueIndex order.
|
||||||
// - The L1 messages included in the block match the node's view of the L1 ledger.
|
// - The L1 messages included in the block match the node's view of the L1 ledger.
|
||||||
func (v *BlockValidator) ValidateL1Messages(block *types.Block) error {
|
func (v *BlockValidator) ValidateL1Messages(block *types.Block) error {
|
||||||
// no further processing if the block contains no L1 messages
|
// skip DB read if the block contains no L1 messages
|
||||||
if block.L1MessageCount() == 0 {
|
if !block.ContainsL1Messages() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,16 +151,30 @@ func (v *BlockValidator) ValidateL1Messages(block *types.Block) error {
|
||||||
return consensus.ErrInvalidL1MessageOrder
|
return consensus.ErrInvalidL1MessageOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
// check queue index
|
// queue index cannot decrease
|
||||||
// TODO: account for skipped messages here
|
txQueueIndex := tx.AsL1MessageTx().QueueIndex
|
||||||
if tx.AsL1MessageTx().QueueIndex != queueIndex {
|
|
||||||
|
if txQueueIndex < queueIndex {
|
||||||
return consensus.ErrInvalidL1MessageOrder
|
return consensus.ErrInvalidL1MessageOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
queueIndex += 1
|
// skipped messages
|
||||||
|
// TODO: consider verifying that skipped messages overflow
|
||||||
|
for index := queueIndex; index < txQueueIndex; index++ {
|
||||||
|
log.Debug("Skipped L1 message", "block", block.Hash().String(), "queueIndex", index)
|
||||||
|
|
||||||
|
if exists := it.Next(); !exists {
|
||||||
|
// the message in this block is not available in our local db.
|
||||||
|
// we'll reprocess this block at a later time.
|
||||||
|
return consensus.ErrMissingL1MessageData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queueIndex = txQueueIndex + 1
|
||||||
|
|
||||||
if exists := it.Next(); !exists {
|
if exists := it.Next(); !exists {
|
||||||
// we'll reprocess this block at a later time
|
// the message in this block is not available in our local db.
|
||||||
|
// we'll reprocess this block at a later time.
|
||||||
return consensus.ErrMissingL1MessageData
|
return consensus.ErrMissingL1MessageData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,3 +247,35 @@ func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
|
||||||
}
|
}
|
||||||
return limit
|
return limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *BlockValidator) createTraceEnv(block *types.Block) (*TraceEnv, error) {
|
||||||
|
parent := v.bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
|
if parent == nil {
|
||||||
|
return nil, errors.New("validateCircuitRowConsumption: no parent block found")
|
||||||
|
}
|
||||||
|
|
||||||
|
statedb, err := v.bc.StateAt(parent.Hash())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateTraceEnv(v.config, v.bc, v.engine, statedb, parent, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BlockValidator) validateCircuitRowConsumption(block *types.Block) (*types.RowConsumption, error) {
|
||||||
|
env, err := v.createTraceEnv(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
traces, err := env.GetBlockTrace(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v.cMu.Lock()
|
||||||
|
defer v.cMu.Unlock()
|
||||||
|
|
||||||
|
v.circuitCapacityChecker.Reset()
|
||||||
|
return v.circuitCapacityChecker.ApplyBlock(traces)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) {
|
||||||
headers[i] = block.Header()
|
headers[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
|
@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
||||||
var results <-chan error
|
var results <-chan error
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
} else {
|
} else {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil, false)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
||||||
defer runtime.GOMAXPROCS(old)
|
defer runtime.GOMAXPROCS(old)
|
||||||
|
|
||||||
// Start the verifications and immediately abort
|
// Start the verifications and immediately abort
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator and
|
// available in the database. It initialises the default Ethereum Validator and
|
||||||
// Processor.
|
// Processor.
|
||||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit *uint64) (*BlockChain, error) {
|
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit *uint64, checkCircuitCapacity bool) (*BlockChain, error) {
|
||||||
if cacheConfig == nil {
|
if cacheConfig == nil {
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = defaultCacheConfig
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +263,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
engine: engine,
|
engine: engine,
|
||||||
vmConfig: vmConfig,
|
vmConfig: vmConfig,
|
||||||
}
|
}
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
bc.validator = NewBlockValidator(chainConfig, bc, engine, db, checkCircuitCapacity)
|
||||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
||||||
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
||||||
|
|
||||||
|
|
@ -1182,10 +1182,14 @@ func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (e
|
||||||
rawdb.WriteBlock(batch, block)
|
rawdb.WriteBlock(batch, block)
|
||||||
|
|
||||||
queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(bc.db, block.ParentHash())
|
queueIndex := rawdb.ReadFirstQueueIndexNotInL2Block(bc.db, block.ParentHash())
|
||||||
|
|
||||||
|
// note: we can insert blocks with header-only ancestors here,
|
||||||
|
// so queueIndex might not yet be available in DB.
|
||||||
if queueIndex != nil {
|
if queueIndex != nil {
|
||||||
// note: we can insert blocks with header-only ancestors here,
|
// do not overwrite the index written by the miner worker
|
||||||
// so queueIndex might not yet be available in DB.
|
if index := rawdb.ReadFirstQueueIndexNotInL2Block(bc.db, block.Hash()); index == nil {
|
||||||
rawdb.WriteFirstQueueIndexNotInL2Block(batch, block.Hash(), *queueIndex+uint64(block.L1MessageCount()))
|
rawdb.WriteFirstQueueIndexNotInL2Block(batch, block.Hash(), *queueIndex+uint64(block.NumL1MessagesProcessed(*queueIndex)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
|
|
@ -1249,7 +1253,10 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||||
// so the parent will always be inserted first.
|
// so the parent will always be inserted first.
|
||||||
log.Crit("Queue index in DB is nil", "parent", block.ParentHash(), "hash", block.Hash())
|
log.Crit("Queue index in DB is nil", "parent", block.ParentHash(), "hash", block.Hash())
|
||||||
}
|
}
|
||||||
rawdb.WriteFirstQueueIndexNotInL2Block(blockBatch, block.Hash(), *queueIndex+uint64(block.L1MessageCount()))
|
// do not overwrite the index written by the miner worker
|
||||||
|
if index := rawdb.ReadFirstQueueIndexNotInL2Block(bc.db, block.Hash()); index == nil {
|
||||||
|
rawdb.WriteFirstQueueIndexNotInL2Block(blockBatch, block.Hash(), *queueIndex+uint64(block.NumL1MessagesProcessed(*queueIndex)))
|
||||||
|
}
|
||||||
|
|
||||||
if err := blockBatch.Write(); err != nil {
|
if err := blockBatch.Write(); err != nil {
|
||||||
log.Crit("Failed to write block into disk", "err", err)
|
log.Crit("Failed to write block into disk", "err", err)
|
||||||
|
|
|
||||||
|
|
@ -1783,7 +1783,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
config.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1836,7 +1836,7 @@ func testRepair(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1907,7 +1907,7 @@ func TestIssue23496(t *testing.T) {
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1951,7 +1951,7 @@ func TestIssue23496(t *testing.T) {
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err = NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1982,7 +1982,7 @@ func testSetHead(t *testing.T, tt *rewindTest, snapshots bool) {
|
||||||
config.SnapshotLimit = 256
|
config.SnapshotLimit = 256
|
||||||
config.SnapshotWait = true
|
config.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, config, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Blo
|
||||||
// will happen during the block insertion.
|
// will happen during the block insertion.
|
||||||
cacheConfig = defaultCacheConfig
|
cacheConfig = defaultCacheConfig
|
||||||
)
|
)
|
||||||
chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create chain: %v", err)
|
t.Fatalf("Failed to create chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -223,7 +223,7 @@ func (snaptest *snapshotTest) test(t *testing.T) {
|
||||||
|
|
||||||
// Restart the chain normally
|
// Restart the chain normally
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -259,13 +259,13 @@ func (snaptest *crashSnapshotTest) test(t *testing.T) {
|
||||||
// the crash, we do restart twice here: one after the crash and one
|
// the crash, we do restart twice here: one after the crash and one
|
||||||
// after the normal stop. It's used to ensure the broken snapshot
|
// after the normal stop. It's used to ensure the broken snapshot
|
||||||
// can be detected all the time.
|
// can be detected all the time.
|
||||||
newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +301,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +309,7 @@ func (snaptest *gappedSnapshotTest) test(t *testing.T) {
|
||||||
newchain.Stop()
|
newchain.Stop()
|
||||||
|
|
||||||
// Restart the chain with enabling the snapshot
|
// Restart the chain with enabling the snapshot
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -337,7 +337,7 @@ func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
|
||||||
chain.SetHead(snaptest.setHead)
|
chain.SetHead(snaptest.setHead)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +368,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// and state committed.
|
// and state committed.
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
|
|
||||||
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -385,7 +385,7 @@ func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
|
||||||
// journal and latest state will be committed
|
// journal and latest state will be committed
|
||||||
|
|
||||||
// Restart the chain after the crash
|
// Restart the chain after the crash
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -420,7 +420,7 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
TrieTimeLimit: 5 * time.Minute,
|
TrieTimeLimit: 5 * time.Minute,
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
}
|
}
|
||||||
newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -436,13 +436,13 @@ func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
|
||||||
SnapshotLimit: 256,
|
SnapshotLimit: 256,
|
||||||
SnapshotWait: false, // Don't wait rebuild
|
SnapshotWait: false, // Don't wait rebuild
|
||||||
}
|
}
|
||||||
newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
// Simulate the blockchain crash.
|
// Simulate the blockchain crash.
|
||||||
|
|
||||||
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
|
newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to recreate chain: %v", err)
|
t.Fatalf("Failed to recreate chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize a fresh chain with only a genesis block
|
// Initialize a fresh chain with only a genesis block
|
||||||
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, false)
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
@ -524,7 +524,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
blockchain.Stop()
|
blockchain.Stop()
|
||||||
|
|
||||||
// Create a new BlockChain and check that it rolled back the state.
|
// Create a new BlockChain and check that it rolled back the state.
|
||||||
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -637,7 +637,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := rawdb.NewMemoryDatabase()
|
archiveDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer archive.Stop()
|
defer archive.Stop()
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
|
|
@ -646,7 +646,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := rawdb.NewMemoryDatabase()
|
fastDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -670,7 +670,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -792,7 +792,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
archiveCaching := *defaultCacheConfig
|
archiveCaching := *defaultCacheConfig
|
||||||
archiveCaching.TrieDirtyDisabled = true
|
archiveCaching.TrieDirtyDisabled = true
|
||||||
|
|
||||||
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
archive, _ := NewBlockChain(archiveDb, &archiveCaching, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -805,7 +805,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb, delfn := makeDb()
|
fastDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -825,7 +825,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||||
ancientDb, delfn := makeDb()
|
ancientDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -844,7 +844,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a light node and ensure all pointers are updated
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb, delfn := makeDb()
|
lightDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -913,7 +913,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -983,7 +983,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
rmLogsCh := make(chan RemovedLogsEvent)
|
||||||
|
|
@ -1036,7 +1036,7 @@ func TestLogRebirth(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
engine = ethash.NewFaker()
|
engine = ethash.NewFaker()
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
@ -1099,7 +1099,7 @@ func TestSideLogRebirth(t *testing.T) {
|
||||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000000)}}}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
@ -1174,7 +1174,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -1306,7 +1306,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1414,7 +1414,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1489,7 +1489,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1533,7 +1533,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1572,7 +1572,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1633,7 +1633,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -1653,7 +1653,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
||||||
|
|
||||||
// Reopen broken blockchain again
|
// Reopen broken blockchain again
|
||||||
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
||||||
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
||||||
|
|
@ -1705,7 +1705,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
|
||||||
}
|
}
|
||||||
gspec := Genesis{Config: params.AllEthashProtocolChanges}
|
gspec := Genesis{Config: params.AllEthashProtocolChanges}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
ancientChain, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer ancientChain.Stop()
|
defer ancientChain.Stop()
|
||||||
|
|
||||||
// Import the canonical header chain.
|
// Import the canonical header chain.
|
||||||
|
|
@ -1766,7 +1766,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1813,7 +1813,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1910,7 +1910,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(chaindb)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2019,7 +2019,7 @@ func getLongAndShortChains() (bc *BlockChain, longChain []*types.Block, heavyCha
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2212,7 +2212,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
|
|
||||||
// Import all blocks into ancient db
|
// Import all blocks into ancient db
|
||||||
l := uint64(0)
|
l := uint64(0)
|
||||||
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2237,7 +2237,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2261,7 +2261,7 @@ func TestTransactionIndices(t *testing.T) {
|
||||||
limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */}
|
limit = []uint64{0, 64 /* drop stale */, 32 /* shorten history */, 64 /* extend history */, 0 /* restore all */}
|
||||||
tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0}
|
tails := []uint64{0, 67 /* 130 - 64 + 1 */, 100 /* 131 - 32 + 1 */, 69 /* 132 - 64 + 1 */, 0}
|
||||||
for i, l := range limit {
|
for i, l := range limit {
|
||||||
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2339,7 +2339,7 @@ func TestSkipStaleTxIndicesInFastSync(t *testing.T) {
|
||||||
|
|
||||||
// Import all blocks into ancient db, only HEAD-32 indices are kept.
|
// Import all blocks into ancient db, only HEAD-32 indices are kept.
|
||||||
l := uint64(32)
|
l := uint64(32)
|
||||||
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l)
|
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, &l, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2403,7 +2403,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to create tester chain: %v", err)
|
b.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2485,7 +2485,7 @@ func TestSideImportPrunedBlocks(t *testing.T) {
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
(&Genesis{BaseFee: big.NewInt(params.InitialBaseFee)}).MustCommit(diskdb)
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2625,7 +2625,7 @@ func TestDeleteCreateRevert(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2730,7 +2730,7 @@ func TestInitThenFailCreateContract(t *testing.T) {
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
|
||||||
//Debug: true,
|
//Debug: true,
|
||||||
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
//Tracer: vm.NewJSONLogger(nil, os.Stdout),
|
||||||
}, nil, nil)
|
}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2817,7 +2817,7 @@ func TestEIP2718Transition(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2912,7 +2912,7 @@ func TestEIP1559Transition(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3036,7 +3036,7 @@ func TestPoseidonCodeHash(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
engine = ethash.NewFaker()
|
engine = ethash.NewFaker()
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
@ -3150,7 +3150,7 @@ func TestFeeVault(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3202,7 +3202,7 @@ func TestTransactionCountLimit(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize blockchain
|
// Initialize blockchain
|
||||||
blockchain, err := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil)
|
blockchain, err := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3266,7 +3266,7 @@ func TestInsertBlocksWithL1Messages(t *testing.T) {
|
||||||
rawdb.WriteL1Messages(db, msgs)
|
rawdb.WriteL1Messages(db, msgs)
|
||||||
|
|
||||||
// initialize blockchain
|
// initialize blockchain
|
||||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
// generate blocks with 1 L1 message in each
|
// generate blocks with 1 L1 message in each
|
||||||
|
|
@ -3302,6 +3302,42 @@ func TestInsertBlocksWithL1Messages(t *testing.T) {
|
||||||
queueIndex = rawdb.ReadFirstQueueIndexNotInL2Block(db, blocks[len(blocks)-1].Hash())
|
queueIndex = rawdb.ReadFirstQueueIndexNotInL2Block(db, blocks[len(blocks)-1].Hash())
|
||||||
assert.NotNil(t, queueIndex)
|
assert.NotNil(t, queueIndex)
|
||||||
assert.Equal(t, uint64(len(msgs)), *queueIndex)
|
assert.Equal(t, uint64(len(msgs)), *queueIndex)
|
||||||
|
|
||||||
|
// generate block with messages #1 and #2 skipped
|
||||||
|
blocks, _ = GenerateChain(config, genesis, engine, db, 1, func(_ int, b *BlockGen) {
|
||||||
|
tx := types.NewTx(&msgs[0])
|
||||||
|
b.AddTxWithChain(blockchain, tx)
|
||||||
|
tx = types.NewTx(&msgs[3])
|
||||||
|
b.AddTxWithChain(blockchain, tx)
|
||||||
|
})
|
||||||
|
|
||||||
|
// insert blocks, validation should pass
|
||||||
|
index, err = blockchain.InsertChain(blocks)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, index)
|
||||||
|
|
||||||
|
// L1 message DB should be updated
|
||||||
|
queueIndex = rawdb.ReadFirstQueueIndexNotInL2Block(db, blocks[0].Hash())
|
||||||
|
assert.NotNil(t, queueIndex)
|
||||||
|
assert.Equal(t, uint64(len(msgs)), *queueIndex)
|
||||||
|
|
||||||
|
// generate block with messages #0 and #1 skipped
|
||||||
|
blocks, _ = GenerateChain(config, genesis, engine, db, 1, func(_ int, b *BlockGen) {
|
||||||
|
tx := types.NewTx(&msgs[2])
|
||||||
|
b.AddTxWithChain(blockchain, tx)
|
||||||
|
tx = types.NewTx(&msgs[3])
|
||||||
|
b.AddTxWithChain(blockchain, tx)
|
||||||
|
})
|
||||||
|
|
||||||
|
// insert blocks, validation should pass
|
||||||
|
index, err = blockchain.InsertChain(blocks)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, 1, index)
|
||||||
|
|
||||||
|
// L1 message DB should be updated
|
||||||
|
queueIndex = rawdb.ReadFirstQueueIndexNotInL2Block(db, blocks[0].Hash())
|
||||||
|
assert.NotNil(t, queueIndex)
|
||||||
|
assert.Equal(t, uint64(len(msgs)), *queueIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestL1MessageValidationFailure tests that the chain rejects blocks with incorrect L1MessageTx transactions.
|
// TestL1MessageValidationFailure tests that the chain rejects blocks with incorrect L1MessageTx transactions.
|
||||||
|
|
@ -3336,7 +3372,7 @@ func TestL1MessageValidationFailure(t *testing.T) {
|
||||||
rawdb.WriteL1Messages(db, msgs)
|
rawdb.WriteL1Messages(db, msgs)
|
||||||
|
|
||||||
// initialize blockchain
|
// initialize blockchain
|
||||||
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
generateBlock := func(txs []*types.Transaction) ([]*types.Block, []types.Receipts) {
|
generateBlock := func(txs []*types.Transaction) ([]*types.Block, []types.Receipts) {
|
||||||
|
|
@ -3347,24 +3383,10 @@ func TestL1MessageValidationFailure(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip #0
|
|
||||||
blocks, _ := generateBlock([]*types.Transaction{types.NewTx(&msgs[1])})
|
|
||||||
index, err := blockchain.InsertChain(blocks)
|
|
||||||
assert.Equal(t, 0, index)
|
|
||||||
assert.Equal(t, consensus.ErrInvalidL1MessageOrder, err)
|
|
||||||
assert.Equal(t, big.NewInt(0), blockchain.CurrentBlock().Number())
|
|
||||||
|
|
||||||
// skip #1
|
|
||||||
blocks, _ = generateBlock([]*types.Transaction{types.NewTx(&msgs[0]), types.NewTx(&msgs[2])})
|
|
||||||
index, err = blockchain.InsertChain(blocks)
|
|
||||||
assert.Equal(t, 0, index)
|
|
||||||
assert.Equal(t, consensus.ErrInvalidL1MessageOrder, err)
|
|
||||||
assert.Equal(t, big.NewInt(0), blockchain.CurrentBlock().Number())
|
|
||||||
|
|
||||||
// L2 tx precedes L1 message tx
|
// L2 tx precedes L1 message tx
|
||||||
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{0x00}, new(big.Int), params.TxGas, genspec.BaseFee, nil), signer, key)
|
tx, _ := types.SignTx(types.NewTransaction(0, common.Address{0x00}, new(big.Int), params.TxGas, genspec.BaseFee, nil), signer, key)
|
||||||
blocks, _ = generateBlock([]*types.Transaction{tx, types.NewTx(&msgs[0])})
|
blocks, _ := generateBlock([]*types.Transaction{tx, types.NewTx(&msgs[0])})
|
||||||
index, err = blockchain.InsertChain(blocks)
|
index, err := blockchain.InsertChain(blocks)
|
||||||
assert.Equal(t, 0, index)
|
assert.Equal(t, 0, index)
|
||||||
assert.Equal(t, consensus.ErrInvalidL1MessageOrder, err)
|
assert.Equal(t, consensus.ErrInvalidL1MessageOrder, err)
|
||||||
assert.Equal(t, big.NewInt(0), blockchain.CurrentBlock().Number())
|
assert.Equal(t, big.NewInt(0), blockchain.CurrentBlock().Number())
|
||||||
|
|
@ -3425,7 +3447,7 @@ func TestBlockPayloadSizeLimit(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize blockchain
|
// Initialize blockchain
|
||||||
blockchain, err := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil)
|
blockchain, err := NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -3537,7 +3559,7 @@ func TestEIP3651(t *testing.T) {
|
||||||
}
|
}
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
})
|
})
|
||||||
chain, err := NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func ExampleGenerateChain() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
proConf.DAOForkBlock = forkBlock
|
proConf.DAOForkBlock = forkBlock
|
||||||
proConf.DAOForkSupport = true
|
proConf.DAOForkSupport = true
|
||||||
|
|
||||||
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer proBc.Stop()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := rawdb.NewMemoryDatabase()
|
conDb := rawdb.NewMemoryDatabase()
|
||||||
|
|
@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
conConf.DAOForkBlock = forkBlock
|
conConf.DAOForkBlock = forkBlock
|
||||||
conConf.DAOForkSupport = false
|
conConf.DAOForkSupport = false
|
||||||
|
|
||||||
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer conBc.Stop()
|
defer conBc.Stop()
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
|
|
@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
genesis := oldcustomg.MustCommit(db)
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
|
||||||
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, false)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteBlockRowConsumption writes a RowConsumption of the block to the database.
|
// WriteBlockRowConsumption writes a RowConsumption of the block to the database.
|
||||||
func WriteBlockRowConsumption(db ethdb.KeyValueWriter, l2BlockHash common.Hash, rc types.RowConsumption) {
|
func WriteBlockRowConsumption(db ethdb.KeyValueWriter, l2BlockHash common.Hash, rc *types.RowConsumption) {
|
||||||
|
if rc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bytes, err := rlp.EncodeToBytes(&rc)
|
bytes, err := rlp.EncodeToBytes(&rc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to RLP encode RowConsumption ", "err", err)
|
log.Crit("Failed to RLP encode RowConsumption ", "err", err)
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,12 @@ import (
|
||||||
|
|
||||||
func TestReadBlockRowConsumption(t *testing.T) {
|
func TestReadBlockRowConsumption(t *testing.T) {
|
||||||
l2BlockHash := common.BigToHash(big.NewInt(10))
|
l2BlockHash := common.BigToHash(big.NewInt(10))
|
||||||
rc := types.RowConsumption{types.SubCircuitRowConsumption{CircuitName: "aa", Rows: 12}, types.SubCircuitRowConsumption{CircuitName: "bb", Rows: 100}}
|
rc := types.RowConsumption{
|
||||||
|
types.SubCircuitRowUsage{Name: "aa", RowNumber: 12},
|
||||||
|
types.SubCircuitRowUsage{Name: "bb", RowNumber: 100},
|
||||||
|
}
|
||||||
db := NewMemoryDatabase()
|
db := NewMemoryDatabase()
|
||||||
WriteBlockRowConsumption(db, l2BlockHash, rc)
|
WriteBlockRowConsumption(db, l2BlockHash, &rc)
|
||||||
got := ReadBlockRowConsumption(db, l2BlockHash)
|
got := ReadBlockRowConsumption(db, l2BlockHash)
|
||||||
if got == nil || !reflect.DeepEqual(rc, *got) {
|
if got == nil || !reflect.DeepEqual(rc, *got) {
|
||||||
t.Fatal("RowConsumption mismatch", "expected", rc, "got", got)
|
t.Fatal("RowConsumption mismatch", "expected", rc, "got", got)
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
|
||||||
|
|
@ -246,7 +246,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
|
@ -286,7 +286,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
)
|
)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
for i, tt := range []struct {
|
for i, tt := range []struct {
|
||||||
|
|
@ -341,7 +341,7 @@ func TestStateProcessorErrors(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
|
||||||
smallInitCode = [320]byte{}
|
smallInitCode = [320]byte{}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
493
core/trace.go
Normal file
493
core/trace.go
Normal file
|
|
@ -0,0 +1,493 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/common"
|
||||||
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
|
"github.com/scroll-tech/go-ethereum/consensus"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/state"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/withdrawtrie"
|
||||||
|
"github.com/scroll-tech/go-ethereum/trie/zkproof"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TraceEnv struct {
|
||||||
|
logConfig *vm.LogConfig
|
||||||
|
chainConfig *params.ChainConfig
|
||||||
|
|
||||||
|
coinbase common.Address
|
||||||
|
|
||||||
|
// rMu lock is used to protect txs executed in parallel.
|
||||||
|
signer types.Signer
|
||||||
|
state *state.StateDB
|
||||||
|
blockCtx vm.BlockContext
|
||||||
|
|
||||||
|
// pMu lock is used to protect Proofs' read and write mutual exclusion,
|
||||||
|
// since txs are executed in parallel, so this lock is required.
|
||||||
|
pMu sync.Mutex
|
||||||
|
// sMu is required because of txs are executed in parallel,
|
||||||
|
// this lock is used to protect StorageTrace's read and write mutual exclusion.
|
||||||
|
sMu sync.Mutex
|
||||||
|
*types.StorageTrace
|
||||||
|
TxStorageTraces []*types.StorageTrace
|
||||||
|
// zktrie tracer is used for zktrie storage to build additional deletion proof
|
||||||
|
ZkTrieTracer map[string]state.ZktrieProofTracer
|
||||||
|
ExecutionResults []*types.ExecutionResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context is the same as Context in eth/tracers/tracers.go
|
||||||
|
type Context struct {
|
||||||
|
BlockHash common.Hash
|
||||||
|
TxIndex int
|
||||||
|
TxHash common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
// txTraceTask is the same as txTraceTask in eth/tracers/api.go
|
||||||
|
type txTraceTask struct {
|
||||||
|
statedb *state.StateDB
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTraceEnv(chainConfig *params.ChainConfig, chainContext ChainContext, engine consensus.Engine, statedb *state.StateDB, parent *types.Block, block *types.Block) (*TraceEnv, error) {
|
||||||
|
var coinbase common.Address
|
||||||
|
var err error
|
||||||
|
if chainConfig.Scroll.FeeVaultEnabled() {
|
||||||
|
coinbase = *chainConfig.Scroll.FeeVaultAddress
|
||||||
|
} else {
|
||||||
|
coinbase, err = engine.Author(block.Header())
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("recover coinbase in CreateTraceEnv fail. using zero-address", "err", err, "blockNumber", block.Header().Number, "headerHash", block.Header().Hash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env := &TraceEnv{
|
||||||
|
logConfig: &vm.LogConfig{
|
||||||
|
EnableMemory: false,
|
||||||
|
EnableReturnData: true,
|
||||||
|
},
|
||||||
|
chainConfig: chainConfig,
|
||||||
|
coinbase: coinbase,
|
||||||
|
signer: types.MakeSigner(chainConfig, block.Number()),
|
||||||
|
state: statedb,
|
||||||
|
blockCtx: NewEVMBlockContext(block.Header(), chainContext, nil),
|
||||||
|
StorageTrace: &types.StorageTrace{
|
||||||
|
RootBefore: parent.Root(),
|
||||||
|
RootAfter: block.Root(),
|
||||||
|
Proofs: make(map[string][]hexutil.Bytes),
|
||||||
|
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
|
||||||
|
},
|
||||||
|
ZkTrieTracer: make(map[string]state.ZktrieProofTracer),
|
||||||
|
ExecutionResults: make([]*types.ExecutionResult, block.Transactions().Len()),
|
||||||
|
TxStorageTraces: make([]*types.StorageTrace, block.Transactions().Len()),
|
||||||
|
}
|
||||||
|
|
||||||
|
key := coinbase.String()
|
||||||
|
if _, exist := env.Proofs[key]; !exist {
|
||||||
|
proof, err := env.state.GetProof(coinbase)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Proof for coinbase not available", "coinbase", coinbase, "error", err)
|
||||||
|
// but we still mark the proofs map with nil array
|
||||||
|
}
|
||||||
|
wrappedProof := make([]hexutil.Bytes, len(proof))
|
||||||
|
for i, bt := range proof {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
env.Proofs[key] = wrappedProof
|
||||||
|
}
|
||||||
|
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *TraceEnv) GetBlockTrace(block *types.Block) (*types.BlockTrace, error) {
|
||||||
|
// Execute all the transaction contained within the block concurrently
|
||||||
|
var (
|
||||||
|
txs = block.Transactions()
|
||||||
|
pend = new(sync.WaitGroup)
|
||||||
|
jobs = make(chan *txTraceTask, len(txs))
|
||||||
|
errCh = make(chan error, 1)
|
||||||
|
)
|
||||||
|
threads := runtime.NumCPU()
|
||||||
|
if threads > len(txs) {
|
||||||
|
threads = len(txs)
|
||||||
|
}
|
||||||
|
for th := 0; th < threads; th++ {
|
||||||
|
pend.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer pend.Done()
|
||||||
|
// Fetch and execute the next transaction trace tasks
|
||||||
|
for task := range jobs {
|
||||||
|
if err := env.getTxResult(task.statedb, task.index, block); err != nil {
|
||||||
|
select {
|
||||||
|
case errCh <- err:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
log.Error("failed to trace tx", "txHash", txs[task.index].Hash().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed the transactions into the tracers and return
|
||||||
|
var failed error
|
||||||
|
for i, tx := range txs {
|
||||||
|
// Send the trace task over for execution
|
||||||
|
jobs <- &txTraceTask{statedb: env.state.Copy(), index: i}
|
||||||
|
|
||||||
|
// Generate the next state snapshot fast without tracing
|
||||||
|
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
||||||
|
env.state.Prepare(tx.Hash(), i)
|
||||||
|
vmenv := vm.NewEVM(env.blockCtx, NewEVMTxContext(msg), env.state, env.chainConfig, vm.Config{})
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state)
|
||||||
|
if err != nil {
|
||||||
|
failed = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err = ApplyMessage(vmenv, msg, new(GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
|
||||||
|
failed = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// we'd better don't finalise
|
||||||
|
// env.state.Finalise(vmenv.chainConfig().IsEIP158(block.Number()))
|
||||||
|
}
|
||||||
|
close(jobs)
|
||||||
|
pend.Wait()
|
||||||
|
|
||||||
|
// after all tx has been traced, collect "deletion proof" for zktrie
|
||||||
|
for _, tracer := range env.ZkTrieTracer {
|
||||||
|
delProofs, err := tracer.GetDeletionProofs()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("deletion proof failure", "error", err)
|
||||||
|
} else {
|
||||||
|
for _, proof := range delProofs {
|
||||||
|
env.DeletionProofs = append(env.DeletionProofs, proof)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build dummy per-tx deletion proof
|
||||||
|
for _, txStorageTrace := range env.TxStorageTraces {
|
||||||
|
if txStorageTrace != nil {
|
||||||
|
txStorageTrace.DeletionProofs = env.DeletionProofs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If execution failed in between, abort
|
||||||
|
select {
|
||||||
|
case err := <-errCh:
|
||||||
|
return nil, err
|
||||||
|
default:
|
||||||
|
if failed != nil {
|
||||||
|
return nil, failed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return env.fillBlockTrace(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (env *TraceEnv) getTxResult(state *state.StateDB, index int, block *types.Block) error {
|
||||||
|
tx := block.Transactions()[index]
|
||||||
|
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
||||||
|
from, _ := types.Sender(env.signer, tx)
|
||||||
|
to := tx.To()
|
||||||
|
|
||||||
|
txctx := &Context{
|
||||||
|
BlockHash: block.TxHash(),
|
||||||
|
TxIndex: index,
|
||||||
|
TxHash: tx.Hash(),
|
||||||
|
}
|
||||||
|
|
||||||
|
sender := &types.AccountWrapper{
|
||||||
|
Address: from,
|
||||||
|
Nonce: state.GetNonce(from),
|
||||||
|
Balance: (*hexutil.Big)(state.GetBalance(from)),
|
||||||
|
KeccakCodeHash: state.GetKeccakCodeHash(from),
|
||||||
|
PoseidonCodeHash: state.GetPoseidonCodeHash(from),
|
||||||
|
CodeSize: state.GetCodeSize(from),
|
||||||
|
}
|
||||||
|
var receiver *types.AccountWrapper
|
||||||
|
if to != nil {
|
||||||
|
receiver = &types.AccountWrapper{
|
||||||
|
Address: *to,
|
||||||
|
Nonce: state.GetNonce(*to),
|
||||||
|
Balance: (*hexutil.Big)(state.GetBalance(*to)),
|
||||||
|
KeccakCodeHash: state.GetKeccakCodeHash(*to),
|
||||||
|
PoseidonCodeHash: state.GetPoseidonCodeHash(*to),
|
||||||
|
CodeSize: state.GetCodeSize(*to),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracer := vm.NewStructLogger(env.logConfig)
|
||||||
|
// Run the transaction with tracing enabled.
|
||||||
|
vmenv := vm.NewEVM(env.blockCtx, NewEVMTxContext(msg), state, env.chainConfig, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
||||||
|
|
||||||
|
// Call Prepare to clear out the statedb access list
|
||||||
|
state.Prepare(txctx.TxHash, txctx.TxIndex)
|
||||||
|
|
||||||
|
// Computes the new state by applying the given message.
|
||||||
|
l1DataFee, err := fees.CalculateL1DataFee(tx, state)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("tracing failed: %w", err)
|
||||||
|
}
|
||||||
|
result, err := ApplyMessage(vmenv, msg, new(GasPool).AddGas(msg.Gas()), l1DataFee)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("tracing failed: %w", err)
|
||||||
|
}
|
||||||
|
// If the result contains a revert reason, return it.
|
||||||
|
returnVal := result.Return()
|
||||||
|
if len(result.Revert()) > 0 {
|
||||||
|
returnVal = result.Revert()
|
||||||
|
}
|
||||||
|
|
||||||
|
createdAcc := tracer.CreatedAccount()
|
||||||
|
var after []*types.AccountWrapper
|
||||||
|
if to == nil {
|
||||||
|
if createdAcc == nil {
|
||||||
|
return errors.New("unexpected tx: address for created contract unavailable")
|
||||||
|
}
|
||||||
|
to = &createdAcc.Address
|
||||||
|
}
|
||||||
|
// collect affected account after tx being applied
|
||||||
|
for _, acc := range []common.Address{from, *to, env.coinbase} {
|
||||||
|
after = append(after, &types.AccountWrapper{
|
||||||
|
Address: acc,
|
||||||
|
Nonce: state.GetNonce(acc),
|
||||||
|
Balance: (*hexutil.Big)(state.GetBalance(acc)),
|
||||||
|
KeccakCodeHash: state.GetKeccakCodeHash(acc),
|
||||||
|
PoseidonCodeHash: state.GetPoseidonCodeHash(acc),
|
||||||
|
CodeSize: state.GetCodeSize(acc),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
txStorageTrace := &types.StorageTrace{
|
||||||
|
Proofs: make(map[string][]hexutil.Bytes),
|
||||||
|
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
|
||||||
|
}
|
||||||
|
// still we have no state root for per tx, only set the head and tail
|
||||||
|
if index == 0 {
|
||||||
|
txStorageTrace.RootBefore = state.GetRootHash()
|
||||||
|
} else if index == len(block.Transactions())-1 {
|
||||||
|
txStorageTrace.RootAfter = block.Root()
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge required proof data
|
||||||
|
proofAccounts := tracer.UpdatedAccounts()
|
||||||
|
proofAccounts[vmenv.FeeRecipient()] = struct{}{}
|
||||||
|
for addr := range proofAccounts {
|
||||||
|
addrStr := addr.String()
|
||||||
|
|
||||||
|
env.pMu.Lock()
|
||||||
|
checkedProof, existed := env.Proofs[addrStr]
|
||||||
|
if existed {
|
||||||
|
txStorageTrace.Proofs[addrStr] = checkedProof
|
||||||
|
}
|
||||||
|
env.pMu.Unlock()
|
||||||
|
if existed {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
proof, err := state.GetProof(addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Proof not available", "address", addrStr, "error", err)
|
||||||
|
// but we still mark the proofs map with nil array
|
||||||
|
}
|
||||||
|
wrappedProof := make([]hexutil.Bytes, len(proof))
|
||||||
|
for i, bt := range proof {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
env.pMu.Lock()
|
||||||
|
env.Proofs[addrStr] = wrappedProof
|
||||||
|
txStorageTrace.Proofs[addrStr] = wrappedProof
|
||||||
|
env.pMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
proofStorages := tracer.UpdatedStorages()
|
||||||
|
for addr, keys := range proofStorages {
|
||||||
|
if _, existed := txStorageTrace.StorageProofs[addr.String()]; !existed {
|
||||||
|
txStorageTrace.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
env.sMu.Lock()
|
||||||
|
trie, err := state.GetStorageTrieForProof(addr)
|
||||||
|
if err != nil {
|
||||||
|
// but we still continue to next address
|
||||||
|
log.Error("Storage trie not available", "error", err, "address", addr)
|
||||||
|
env.sMu.Unlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
zktrieTracer := state.NewProofTracer(trie)
|
||||||
|
env.sMu.Unlock()
|
||||||
|
|
||||||
|
for key, values := range keys {
|
||||||
|
addrStr := addr.String()
|
||||||
|
keyStr := key.String()
|
||||||
|
isDelete := bytes.Equal(values.Bytes(), common.Hash{}.Bytes())
|
||||||
|
|
||||||
|
txm := txStorageTrace.StorageProofs[addrStr]
|
||||||
|
env.sMu.Lock()
|
||||||
|
m, existed := env.StorageProofs[addrStr]
|
||||||
|
if !existed {
|
||||||
|
m = make(map[string][]hexutil.Bytes)
|
||||||
|
env.StorageProofs[addrStr] = m
|
||||||
|
if zktrieTracer.Available() {
|
||||||
|
env.ZkTrieTracer[addrStr] = state.NewProofTracer(trie)
|
||||||
|
}
|
||||||
|
} else if proof, existed := m[keyStr]; existed {
|
||||||
|
txm[keyStr] = proof
|
||||||
|
// still need to touch tracer for deletion
|
||||||
|
if isDelete && zktrieTracer.Available() {
|
||||||
|
env.ZkTrieTracer[addrStr].MarkDeletion(key)
|
||||||
|
}
|
||||||
|
env.sMu.Unlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
env.sMu.Unlock()
|
||||||
|
|
||||||
|
var proof [][]byte
|
||||||
|
var err error
|
||||||
|
if zktrieTracer.Available() {
|
||||||
|
proof, err = state.GetSecureTrieProof(zktrieTracer, key)
|
||||||
|
} else {
|
||||||
|
proof, err = state.GetSecureTrieProof(trie, key)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr)
|
||||||
|
// but we still mark the proofs map with nil array
|
||||||
|
}
|
||||||
|
wrappedProof := make([]hexutil.Bytes, len(proof))
|
||||||
|
for i, bt := range proof {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
env.sMu.Lock()
|
||||||
|
txm[keyStr] = wrappedProof
|
||||||
|
m[keyStr] = wrappedProof
|
||||||
|
if zktrieTracer.Available() {
|
||||||
|
if isDelete {
|
||||||
|
zktrieTracer.MarkDeletion(key)
|
||||||
|
}
|
||||||
|
env.ZkTrieTracer[addrStr].Merge(zktrieTracer)
|
||||||
|
}
|
||||||
|
env.sMu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
env.ExecutionResults[index] = &types.ExecutionResult{
|
||||||
|
From: sender,
|
||||||
|
To: receiver,
|
||||||
|
AccountCreated: createdAcc,
|
||||||
|
AccountsAfter: after,
|
||||||
|
L1DataFee: (*hexutil.Big)(result.L1DataFee),
|
||||||
|
Gas: result.UsedGas,
|
||||||
|
Failed: result.Failed(),
|
||||||
|
ReturnValue: fmt.Sprintf("%x", returnVal),
|
||||||
|
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
||||||
|
}
|
||||||
|
env.TxStorageTraces[index] = txStorageTrace
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fillBlockTrace content after all the txs are finished running.
|
||||||
|
func (env *TraceEnv) fillBlockTrace(block *types.Block) (*types.BlockTrace, error) {
|
||||||
|
statedb := env.state
|
||||||
|
|
||||||
|
txs := make([]*types.TransactionData, block.Transactions().Len())
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
txs[i] = types.NewTransactionData(tx, block.NumberU64(), env.chainConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
intrinsicStorageProofs := map[common.Address][]common.Hash{
|
||||||
|
rcfg.L2MessageQueueAddress: {rcfg.WithdrawTrieRootSlot},
|
||||||
|
rcfg.L1GasPriceOracleAddress: {
|
||||||
|
rcfg.L1BaseFeeSlot,
|
||||||
|
rcfg.OverheadSlot,
|
||||||
|
rcfg.ScalarSlot,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for addr, storages := range intrinsicStorageProofs {
|
||||||
|
if _, existed := env.Proofs[addr.String()]; !existed {
|
||||||
|
if proof, err := statedb.GetProof(addr); err != nil {
|
||||||
|
log.Error("Proof for intrinstic address not available", "error", err, "address", addr)
|
||||||
|
} else {
|
||||||
|
wrappedProof := make([]hexutil.Bytes, len(proof))
|
||||||
|
for i, bt := range proof {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
env.Proofs[addr.String()] = wrappedProof
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, existed := env.StorageProofs[addr.String()]; !existed {
|
||||||
|
env.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, slot := range storages {
|
||||||
|
if _, existed := env.StorageProofs[addr.String()][slot.String()]; !existed {
|
||||||
|
if trie, err := statedb.GetStorageTrieForProof(addr); err != nil {
|
||||||
|
log.Error("Storage proof for intrinstic address not available", "error", err, "address", addr)
|
||||||
|
} else if proof, _ := statedb.GetSecureTrieProof(trie, slot); err != nil {
|
||||||
|
log.Error("Get storage proof for intrinstic address failed", "error", err, "address", addr, "slot", slot)
|
||||||
|
} else {
|
||||||
|
wrappedProof := make([]hexutil.Bytes, len(proof))
|
||||||
|
for i, bt := range proof {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
env.StorageProofs[addr.String()][slot.String()] = wrappedProof
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockTrace := &types.BlockTrace{
|
||||||
|
ChainID: env.chainConfig.ChainID.Uint64(),
|
||||||
|
Version: params.ArchiveVersion(params.CommitHash),
|
||||||
|
Coinbase: &types.AccountWrapper{
|
||||||
|
Address: env.coinbase,
|
||||||
|
Nonce: statedb.GetNonce(env.coinbase),
|
||||||
|
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
|
||||||
|
KeccakCodeHash: statedb.GetKeccakCodeHash(env.coinbase),
|
||||||
|
PoseidonCodeHash: statedb.GetPoseidonCodeHash(env.coinbase),
|
||||||
|
CodeSize: statedb.GetCodeSize(env.coinbase),
|
||||||
|
},
|
||||||
|
Header: block.Header(),
|
||||||
|
StorageTrace: env.StorageTrace,
|
||||||
|
ExecutionResults: env.ExecutionResults,
|
||||||
|
TxStorageTraces: env.TxStorageTraces,
|
||||||
|
Transactions: txs,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
evmTrace := env.ExecutionResults[i]
|
||||||
|
// probably a Contract Call
|
||||||
|
if len(tx.Data()) != 0 && tx.To() != nil {
|
||||||
|
evmTrace.ByteCode = hexutil.Encode(statedb.GetCode(*tx.To()))
|
||||||
|
// Get tx.to address's code hash.
|
||||||
|
codeHash := statedb.GetPoseidonCodeHash(*tx.To())
|
||||||
|
evmTrace.PoseidonCodeHash = &codeHash
|
||||||
|
} else if tx.To() == nil { // Contract is created.
|
||||||
|
evmTrace.ByteCode = hexutil.Encode(tx.Data())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only zktrie model has the ability to get `mptwitness`.
|
||||||
|
if env.chainConfig.Scroll.ZktrieEnabled() {
|
||||||
|
// we use MPTWitnessNothing by default and do not allow switch among MPTWitnessType atm.
|
||||||
|
// MPTWitness will be removed from traces in the future.
|
||||||
|
if err := zkproof.FillBlockTraceForMPTWitness(zkproof.MPTWitnessNothing, blockTrace); err != nil {
|
||||||
|
log.Error("fill mpt witness fail", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockTrace.WithdrawTrieRoot = withdrawtrie.ReadWTRSlot(rcfg.L2MessageQueueAddress, env.state)
|
||||||
|
|
||||||
|
return blockTrace, nil
|
||||||
|
}
|
||||||
|
|
@ -397,16 +397,39 @@ func (b *Block) Hash() common.Hash {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// L1MessageCount returns the number of L1 messages in this block.
|
// ContainsL1Messages returns true if this block contains at least one L1 message.
|
||||||
func (b *Block) L1MessageCount() int {
|
func (b *Block) ContainsL1Messages() bool {
|
||||||
|
for _, tx := range b.transactions {
|
||||||
|
if tx.IsL1MessageTx() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumL1MessagesProcessed returns the number of L1 messages processed in this block.
|
||||||
|
// This count includes both skipped and included messages.
|
||||||
|
// `firstQueueIndex` is the first queue index available for this block to process.
|
||||||
|
func (b *Block) NumL1MessagesProcessed(firstQueueIndex uint64) int {
|
||||||
if l1MsgCount := b.l1MsgCount.Load(); l1MsgCount != nil {
|
if l1MsgCount := b.l1MsgCount.Load(); l1MsgCount != nil {
|
||||||
return l1MsgCount.(int)
|
return l1MsgCount.(int)
|
||||||
}
|
}
|
||||||
count := 0
|
|
||||||
for _, tx := range b.transactions {
|
// find first and last queue index in block
|
||||||
if tx.IsL1MessageTx() {
|
var lastQueueIndex *uint64
|
||||||
count += 1
|
|
||||||
|
for ii, tx := range b.transactions {
|
||||||
|
if !tx.IsL1MessageTx() {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
lastQueueIndex = &b.transactions[ii].AsL1MessageTx().QueueIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate and cache L1 message count
|
||||||
|
count := 0
|
||||||
|
if lastQueueIndex != nil {
|
||||||
|
// lastQueueIndex is guaranteed to be non-nil in this case
|
||||||
|
count = int(*lastQueueIndex - firstQueueIndex + 1)
|
||||||
}
|
}
|
||||||
b.l1MsgCount.Store(count)
|
b.l1MsgCount.Store(count)
|
||||||
return count
|
return count
|
||||||
|
|
@ -414,7 +437,13 @@ func (b *Block) L1MessageCount() int {
|
||||||
|
|
||||||
// CountL2Tx returns the number of L2 transactions in this block.
|
// CountL2Tx returns the number of L2 transactions in this block.
|
||||||
func (b *Block) CountL2Tx() int {
|
func (b *Block) CountL2Tx() int {
|
||||||
return len(b.transactions) - b.L1MessageCount()
|
count := 0
|
||||||
|
for _, tx := range b.transactions {
|
||||||
|
if !tx.IsL1MessageTx() {
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
type Blocks []*Block
|
type Blocks []*Block
|
||||||
|
|
|
||||||
|
|
@ -9,37 +9,37 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = (*subCircuitRowConsumptionMarshaling)(nil)
|
var _ = (*subCircuitRowUsageMarshaling)(nil)
|
||||||
|
|
||||||
// MarshalJSON marshals as JSON.
|
// MarshalJSON marshals as JSON.
|
||||||
func (s SubCircuitRowConsumption) MarshalJSON() ([]byte, error) {
|
func (s SubCircuitRowUsage) MarshalJSON() ([]byte, error) {
|
||||||
type SubCircuitRowConsumption struct {
|
type SubCircuitRowUsage struct {
|
||||||
CircuitName string `json:"circuitName" gencodec:"required"`
|
Name string `json:"name" gencodec:"required"`
|
||||||
Rows hexutil.Uint64 `json:"rows" gencodec:"required"`
|
RowNumber hexutil.Uint64 `json:"row_number" gencodec:"required"`
|
||||||
}
|
}
|
||||||
var enc SubCircuitRowConsumption
|
var enc SubCircuitRowUsage
|
||||||
enc.CircuitName = s.CircuitName
|
enc.Name = s.Name
|
||||||
enc.Rows = hexutil.Uint64(s.Rows)
|
enc.RowNumber = hexutil.Uint64(s.RowNumber)
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON unmarshals from JSON.
|
// UnmarshalJSON unmarshals from JSON.
|
||||||
func (s *SubCircuitRowConsumption) UnmarshalJSON(input []byte) error {
|
func (s *SubCircuitRowUsage) UnmarshalJSON(input []byte) error {
|
||||||
type SubCircuitRowConsumption struct {
|
type SubCircuitRowUsage struct {
|
||||||
CircuitName *string `json:"circuitName" gencodec:"required"`
|
Name *string `json:"name" gencodec:"required"`
|
||||||
Rows *hexutil.Uint64 `json:"rows" gencodec:"required"`
|
RowNumber *hexutil.Uint64 `json:"row_number" gencodec:"required"`
|
||||||
}
|
}
|
||||||
var dec SubCircuitRowConsumption
|
var dec SubCircuitRowUsage
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if dec.CircuitName == nil {
|
if dec.Name == nil {
|
||||||
return errors.New("missing required field 'circuitName' for SubCircuitRowConsumption")
|
return errors.New("missing required field 'name' for SubCircuitRowUsage")
|
||||||
}
|
}
|
||||||
s.CircuitName = *dec.CircuitName
|
s.Name = *dec.Name
|
||||||
if dec.Rows == nil {
|
if dec.RowNumber == nil {
|
||||||
return errors.New("missing required field 'rows' for SubCircuitRowConsumption")
|
return errors.New("missing required field 'row_number' for SubCircuitRowUsage")
|
||||||
}
|
}
|
||||||
s.Rows = uint64(*dec.Rows)
|
s.RowNumber = uint64(*dec.RowNumber)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,3 +191,12 @@ func NewTransactionData(tx *Transaction, blockNumber uint64, config *params.Chai
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WrapProof turn the bytes array into proof type (array of hexutil.Bytes)
|
||||||
|
func WrapProof(proofBytes [][]byte) (wrappedProof []hexutil.Bytes) {
|
||||||
|
wrappedProof = make([]hexutil.Bytes, len(proofBytes))
|
||||||
|
for i, bt := range proofBytes {
|
||||||
|
wrappedProof[i] = bt
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,21 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate gencodec -type SubCircuitRowConsumption -field-override subCircuitRowConsumptionMarshaling -out gen_row_consumption_json.go
|
type RowUsage struct {
|
||||||
type SubCircuitRowConsumption struct {
|
IsOk bool `json:"is_ok"`
|
||||||
CircuitName string `json:"circuitName" gencodec:"required"`
|
RowNumber uint64 `json:"row_number"`
|
||||||
Rows uint64 `json:"rows" gencodec:"required"`
|
RowUsageDetails []SubCircuitRowUsage `json:"row_usage_details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RowConsumption []SubCircuitRowConsumption
|
//go:generate gencodec -type SubCircuitRowUsage -field-override subCircuitRowUsageMarshaling -out gen_row_consumption_json.go
|
||||||
|
type SubCircuitRowUsage struct {
|
||||||
|
Name string `json:"name" gencodec:"required"`
|
||||||
|
RowNumber uint64 `json:"row_number" gencodec:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RowConsumption []SubCircuitRowUsage
|
||||||
|
|
||||||
// field type overrides for gencodec
|
// field type overrides for gencodec
|
||||||
type subCircuitRowConsumptionMarshaling struct {
|
type subCircuitRowUsageMarshaling struct {
|
||||||
Rows hexutil.Uint64
|
RowNumber hexutil.Uint64
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
|
||||||
MPTWitness: config.MPTWitness,
|
MPTWitness: config.MPTWitness,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit)
|
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, config.CheckCircuitCapacity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,9 @@ type Config struct {
|
||||||
|
|
||||||
// Trace option
|
// Trace option
|
||||||
MPTWitness int
|
MPTWitness int
|
||||||
|
|
||||||
|
// Check circuit capacity in block validator
|
||||||
|
CheckCircuitCapacity bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
// CreateConsensusEngine creates a consensus engine for the given chain configuration.
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
|
||||||
// Construct testing chain
|
// Construct testing chain
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.Commit(diskdb)
|
gspec.Commit(diskdb)
|
||||||
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, &config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(diskdb, &core.CacheConfig{TrieCleanNoPrefetch: true}, &config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create local chain, %v", err)
|
t.Fatalf("Failed to create local chain, %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,8 @@ func testForkIDSplit(t *testing.T, protocol uint) {
|
||||||
genesisNoFork = gspecNoFork.MustCommit(dbNoFork)
|
genesisNoFork = gspecNoFork.MustCommit(dbNoFork)
|
||||||
genesisProFork = gspecProFork.MustCommit(dbProFork)
|
genesisProFork = gspecProFork.MustCommit(dbProFork)
|
||||||
|
|
||||||
chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil)
|
chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil, false)
|
||||||
chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil)
|
chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil, false)
|
||||||
|
|
||||||
blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil)
|
blocksNoFork, _ = core.GenerateChain(configNoFork, genesisNoFork, engine, dbNoFork, 2, nil)
|
||||||
blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil)
|
blocksProFork, _ = core.GenerateChain(configProFork, genesisProFork, engine, dbProFork, 2, nil)
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler {
|
||||||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
|
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
|
||||||
}).MustCommit(db)
|
}).MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
|
|
||||||
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil)
|
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, nil)
|
||||||
if _, err := chain.InsertChain(bs); err != nil {
|
if _, err := chain.InsertChain(bs); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func newTestBackendWithGenerator(blocks int, generator func(int, *core.BlockGen)
|
||||||
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
||||||
}).MustCommit(db)
|
}).MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
|
|
||||||
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator)
|
bs, _ := core.GenerateChain(params.TestChainConfig, chain.Genesis(), ethash.NewFaker(), db, blocks, generator)
|
||||||
if _, err := chain.InsertChain(bs); err != nil {
|
if _, err := chain.InsertChain(bs); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,20 @@
|
||||||
package tracers
|
package tracers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/scroll-tech/go-ethereum/common"
|
|
||||||
"github.com/scroll-tech/go-ethereum/common/hexutil"
|
|
||||||
"github.com/scroll-tech/go-ethereum/core"
|
"github.com/scroll-tech/go-ethereum/core"
|
||||||
"github.com/scroll-tech/go-ethereum/core/state"
|
|
||||||
"github.com/scroll-tech/go-ethereum/core/types"
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
"github.com/scroll-tech/go-ethereum/core/vm"
|
"github.com/scroll-tech/go-ethereum/core/vm"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/fees"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/rcfg"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rollup/withdrawtrie"
|
|
||||||
"github.com/scroll-tech/go-ethereum/rpc"
|
"github.com/scroll-tech/go-ethereum/rpc"
|
||||||
"github.com/scroll-tech/go-ethereum/trie/zkproof"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TraceBlock interface {
|
type TraceBlock interface {
|
||||||
GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error)
|
GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type traceEnv struct {
|
|
||||||
config *TraceConfig
|
|
||||||
|
|
||||||
coinbase common.Address
|
|
||||||
|
|
||||||
// rMu lock is used to protect txs executed in parallel.
|
|
||||||
signer types.Signer
|
|
||||||
state *state.StateDB
|
|
||||||
blockCtx vm.BlockContext
|
|
||||||
|
|
||||||
// pMu lock is used to protect Proofs' read and write mutual exclusion,
|
|
||||||
// since txs are executed in parallel, so this lock is required.
|
|
||||||
pMu sync.Mutex
|
|
||||||
// sMu is required because of txs are executed in parallel,
|
|
||||||
// this lock is used to protect StorageTrace's read and write mutual exclusion.
|
|
||||||
sMu sync.Mutex
|
|
||||||
*types.StorageTrace
|
|
||||||
txStorageTraces []*types.StorageTrace
|
|
||||||
// zktrie tracer is used for zktrie storage to build additional deletion proof
|
|
||||||
zkTrieTracer map[string]state.ZktrieProofTracer
|
|
||||||
executionResults []*types.ExecutionResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBlockTraceByNumberOrHash replays the block and returns the structured BlockTrace by hash or number.
|
// GetBlockTraceByNumberOrHash replays the block and returns the structured BlockTrace by hash or number.
|
||||||
func (api *API) GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error) {
|
func (api *API) GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, config *TraceConfig) (trace *types.BlockTrace, err error) {
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
|
|
@ -83,11 +48,11 @@ func (api *API) GetBlockTraceByNumberOrHash(ctx context.Context, blockNrOrHash r
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return api.getBlockTrace(block, env)
|
return env.GetBlockTrace(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make trace environment for current block.
|
// Make trace environment for current block.
|
||||||
func (api *API) createTraceEnv(ctx context.Context, config *TraceConfig, block *types.Block) (*traceEnv, error) {
|
func (api *API) createTraceEnv(ctx context.Context, config *TraceConfig, block *types.Block) (*core.TraceEnv, error) {
|
||||||
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -100,431 +65,5 @@ func (api *API) createTraceEnv(ctx context.Context, config *TraceConfig, block *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return core.CreateTraceEnv(api.backend.ChainConfig(), api.chainContext(ctx), api.backend.Engine(), statedb, parent, block)
|
||||||
// get coinbase
|
|
||||||
var coinbase common.Address
|
|
||||||
if api.backend.ChainConfig().Scroll.FeeVaultEnabled() {
|
|
||||||
coinbase = *api.backend.ChainConfig().Scroll.FeeVaultAddress
|
|
||||||
} else {
|
|
||||||
coinbase, err = api.backend.Engine().Author(block.Header())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env := &traceEnv{
|
|
||||||
config: config,
|
|
||||||
coinbase: coinbase,
|
|
||||||
signer: types.MakeSigner(api.backend.ChainConfig(), block.Number()),
|
|
||||||
state: statedb,
|
|
||||||
blockCtx: core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil),
|
|
||||||
StorageTrace: &types.StorageTrace{
|
|
||||||
RootBefore: parent.Root(),
|
|
||||||
RootAfter: block.Root(),
|
|
||||||
Proofs: make(map[string][]hexutil.Bytes),
|
|
||||||
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
|
|
||||||
},
|
|
||||||
zkTrieTracer: make(map[string]state.ZktrieProofTracer),
|
|
||||||
executionResults: make([]*types.ExecutionResult, block.Transactions().Len()),
|
|
||||||
txStorageTraces: make([]*types.StorageTrace, block.Transactions().Len()),
|
|
||||||
}
|
|
||||||
|
|
||||||
key := coinbase.String()
|
|
||||||
if _, exist := env.Proofs[key]; !exist {
|
|
||||||
proof, err := env.state.GetProof(coinbase)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Proof for coinbase not available", "coinbase", coinbase, "error", err)
|
|
||||||
// but we still mark the proofs map with nil array
|
|
||||||
}
|
|
||||||
wrappedProof := make([]hexutil.Bytes, len(proof))
|
|
||||||
for i, bt := range proof {
|
|
||||||
wrappedProof[i] = bt
|
|
||||||
}
|
|
||||||
env.Proofs[key] = wrappedProof
|
|
||||||
}
|
|
||||||
|
|
||||||
return env, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) getBlockTrace(block *types.Block, env *traceEnv) (*types.BlockTrace, error) {
|
|
||||||
// Execute all the transaction contained within the block concurrently
|
|
||||||
var (
|
|
||||||
txs = block.Transactions()
|
|
||||||
pend = new(sync.WaitGroup)
|
|
||||||
jobs = make(chan *txTraceTask, len(txs))
|
|
||||||
errCh = make(chan error, 1)
|
|
||||||
)
|
|
||||||
threads := runtime.NumCPU()
|
|
||||||
if threads > len(txs) {
|
|
||||||
threads = len(txs)
|
|
||||||
}
|
|
||||||
for th := 0; th < threads; th++ {
|
|
||||||
pend.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer pend.Done()
|
|
||||||
// Fetch and execute the next transaction trace tasks
|
|
||||||
for task := range jobs {
|
|
||||||
if err := api.getTxResult(env, task.statedb, task.index, block); err != nil {
|
|
||||||
select {
|
|
||||||
case errCh <- err:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
log.Error("failed to trace tx", "txHash", txs[task.index].Hash().String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feed the transactions into the tracers and return
|
|
||||||
var failed error
|
|
||||||
for i, tx := range txs {
|
|
||||||
// Send the trace task over for execution
|
|
||||||
jobs <- &txTraceTask{statedb: env.state.Copy(), index: i}
|
|
||||||
|
|
||||||
// Generate the next state snapshot fast without tracing
|
|
||||||
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
|
||||||
env.state.Prepare(tx.Hash(), i)
|
|
||||||
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), env.state, api.backend.ChainConfig(), vm.Config{})
|
|
||||||
l1DataFee, err := fees.CalculateL1DataFee(tx, env.state)
|
|
||||||
if err != nil {
|
|
||||||
failed = err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee); err != nil {
|
|
||||||
failed = err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Finalize the state so any modifications are written to the trie
|
|
||||||
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
|
|
||||||
env.state.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
|
|
||||||
}
|
|
||||||
close(jobs)
|
|
||||||
pend.Wait()
|
|
||||||
|
|
||||||
// after all tx has been traced, collect "deletion proof" for zktrie
|
|
||||||
for _, tracer := range env.zkTrieTracer {
|
|
||||||
delProofs, err := tracer.GetDeletionProofs()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("deletion proof failure", "error", err)
|
|
||||||
} else {
|
|
||||||
for _, proof := range delProofs {
|
|
||||||
env.DeletionProofs = append(env.DeletionProofs, proof)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// build dummy per-tx deletion proof
|
|
||||||
for _, txStorageTrace := range env.txStorageTraces {
|
|
||||||
if txStorageTrace != nil {
|
|
||||||
txStorageTrace.DeletionProofs = env.DeletionProofs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If execution failed in between, abort
|
|
||||||
select {
|
|
||||||
case err := <-errCh:
|
|
||||||
return nil, err
|
|
||||||
default:
|
|
||||||
if failed != nil {
|
|
||||||
return nil, failed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.fillBlockTrace(env, block)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (api *API) getTxResult(env *traceEnv, state *state.StateDB, index int, block *types.Block) error {
|
|
||||||
tx := block.Transactions()[index]
|
|
||||||
msg, _ := tx.AsMessage(env.signer, block.BaseFee())
|
|
||||||
from, _ := types.Sender(env.signer, tx)
|
|
||||||
to := tx.To()
|
|
||||||
|
|
||||||
txctx := &Context{
|
|
||||||
BlockHash: block.TxHash(),
|
|
||||||
TxIndex: index,
|
|
||||||
TxHash: tx.Hash(),
|
|
||||||
}
|
|
||||||
|
|
||||||
sender := &types.AccountWrapper{
|
|
||||||
Address: from,
|
|
||||||
Nonce: state.GetNonce(from),
|
|
||||||
Balance: (*hexutil.Big)(state.GetBalance(from)),
|
|
||||||
KeccakCodeHash: state.GetKeccakCodeHash(from),
|
|
||||||
PoseidonCodeHash: state.GetPoseidonCodeHash(from),
|
|
||||||
CodeSize: state.GetCodeSize(from),
|
|
||||||
}
|
|
||||||
var receiver *types.AccountWrapper
|
|
||||||
if to != nil {
|
|
||||||
receiver = &types.AccountWrapper{
|
|
||||||
Address: *to,
|
|
||||||
Nonce: state.GetNonce(*to),
|
|
||||||
Balance: (*hexutil.Big)(state.GetBalance(*to)),
|
|
||||||
KeccakCodeHash: state.GetKeccakCodeHash(*to),
|
|
||||||
PoseidonCodeHash: state.GetPoseidonCodeHash(*to),
|
|
||||||
CodeSize: state.GetCodeSize(*to),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracer := vm.NewStructLogger(env.config.LogConfig)
|
|
||||||
// Run the transaction with tracing enabled.
|
|
||||||
vmenv := vm.NewEVM(env.blockCtx, core.NewEVMTxContext(msg), state, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
|
||||||
state.Prepare(txctx.TxHash, txctx.TxIndex)
|
|
||||||
|
|
||||||
// Computes the new state by applying the given message.
|
|
||||||
l1DataFee, err := fees.CalculateL1DataFee(tx, state)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("tracing failed: %w", err)
|
|
||||||
}
|
|
||||||
result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), l1DataFee)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("tracing failed: %w", err)
|
|
||||||
}
|
|
||||||
// If the result contains a revert reason, return it.
|
|
||||||
returnVal := result.Return()
|
|
||||||
if len(result.Revert()) > 0 {
|
|
||||||
returnVal = result.Revert()
|
|
||||||
}
|
|
||||||
|
|
||||||
createdAcc := tracer.CreatedAccount()
|
|
||||||
var after []*types.AccountWrapper
|
|
||||||
if to == nil {
|
|
||||||
if createdAcc == nil {
|
|
||||||
return errors.New("unexpected tx: address for created contract unavailable")
|
|
||||||
}
|
|
||||||
to = &createdAcc.Address
|
|
||||||
}
|
|
||||||
// collect affected account after tx being applied
|
|
||||||
for _, acc := range []common.Address{from, *to, env.coinbase} {
|
|
||||||
after = append(after, &types.AccountWrapper{
|
|
||||||
Address: acc,
|
|
||||||
Nonce: state.GetNonce(acc),
|
|
||||||
Balance: (*hexutil.Big)(state.GetBalance(acc)),
|
|
||||||
KeccakCodeHash: state.GetKeccakCodeHash(acc),
|
|
||||||
PoseidonCodeHash: state.GetPoseidonCodeHash(acc),
|
|
||||||
CodeSize: state.GetCodeSize(acc),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
txStorageTrace := &types.StorageTrace{
|
|
||||||
Proofs: make(map[string][]hexutil.Bytes),
|
|
||||||
StorageProofs: make(map[string]map[string][]hexutil.Bytes),
|
|
||||||
}
|
|
||||||
// still we have no state root for per tx, only set the head and tail
|
|
||||||
if index == 0 {
|
|
||||||
txStorageTrace.RootBefore = state.GetRootHash()
|
|
||||||
} else if index == len(block.Transactions())-1 {
|
|
||||||
txStorageTrace.RootAfter = block.Root()
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge required proof data
|
|
||||||
proofAccounts := tracer.UpdatedAccounts()
|
|
||||||
proofAccounts[vmenv.FeeRecipient()] = struct{}{}
|
|
||||||
for addr := range proofAccounts {
|
|
||||||
addrStr := addr.String()
|
|
||||||
|
|
||||||
env.pMu.Lock()
|
|
||||||
checkedProof, existed := env.Proofs[addrStr]
|
|
||||||
if existed {
|
|
||||||
txStorageTrace.Proofs[addrStr] = checkedProof
|
|
||||||
}
|
|
||||||
env.pMu.Unlock()
|
|
||||||
if existed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
proof, err := state.GetProof(addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Proof not available", "address", addrStr, "error", err)
|
|
||||||
// but we still mark the proofs map with nil array
|
|
||||||
}
|
|
||||||
wrappedProof := make([]hexutil.Bytes, len(proof))
|
|
||||||
for i, bt := range proof {
|
|
||||||
wrappedProof[i] = bt
|
|
||||||
}
|
|
||||||
env.pMu.Lock()
|
|
||||||
env.Proofs[addrStr] = wrappedProof
|
|
||||||
txStorageTrace.Proofs[addrStr] = wrappedProof
|
|
||||||
env.pMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
proofStorages := tracer.UpdatedStorages()
|
|
||||||
for addr, keys := range proofStorages {
|
|
||||||
if _, existed := txStorageTrace.StorageProofs[addr.String()]; !existed {
|
|
||||||
txStorageTrace.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
env.sMu.Lock()
|
|
||||||
trie, err := state.GetStorageTrieForProof(addr)
|
|
||||||
if err != nil {
|
|
||||||
// but we still continue to next address
|
|
||||||
log.Error("Storage trie not available", "error", err, "address", addr)
|
|
||||||
env.sMu.Unlock()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
zktrieTracer := state.NewProofTracer(trie)
|
|
||||||
env.sMu.Unlock()
|
|
||||||
|
|
||||||
for key, values := range keys {
|
|
||||||
addrStr := addr.String()
|
|
||||||
keyStr := key.String()
|
|
||||||
isDelete := bytes.Equal(values.Bytes(), common.Hash{}.Bytes())
|
|
||||||
|
|
||||||
txm := txStorageTrace.StorageProofs[addrStr]
|
|
||||||
env.sMu.Lock()
|
|
||||||
m, existed := env.StorageProofs[addrStr]
|
|
||||||
if !existed {
|
|
||||||
m = make(map[string][]hexutil.Bytes)
|
|
||||||
env.StorageProofs[addrStr] = m
|
|
||||||
if zktrieTracer.Available() {
|
|
||||||
env.zkTrieTracer[addrStr] = state.NewProofTracer(trie)
|
|
||||||
}
|
|
||||||
} else if proof, existed := m[keyStr]; existed {
|
|
||||||
txm[keyStr] = proof
|
|
||||||
// still need to touch tracer for deletion
|
|
||||||
if isDelete && zktrieTracer.Available() {
|
|
||||||
env.zkTrieTracer[addrStr].MarkDeletion(key)
|
|
||||||
}
|
|
||||||
env.sMu.Unlock()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
env.sMu.Unlock()
|
|
||||||
|
|
||||||
var proof [][]byte
|
|
||||||
var err error
|
|
||||||
if zktrieTracer.Available() {
|
|
||||||
proof, err = state.GetSecureTrieProof(zktrieTracer, key)
|
|
||||||
} else {
|
|
||||||
proof, err = state.GetSecureTrieProof(trie, key)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Storage proof not available", "error", err, "address", addrStr, "key", keyStr)
|
|
||||||
// but we still mark the proofs map with nil array
|
|
||||||
}
|
|
||||||
wrappedProof := make([]hexutil.Bytes, len(proof))
|
|
||||||
for i, bt := range proof {
|
|
||||||
wrappedProof[i] = bt
|
|
||||||
}
|
|
||||||
env.sMu.Lock()
|
|
||||||
txm[keyStr] = wrappedProof
|
|
||||||
m[keyStr] = wrappedProof
|
|
||||||
if zktrieTracer.Available() {
|
|
||||||
if isDelete {
|
|
||||||
zktrieTracer.MarkDeletion(key)
|
|
||||||
}
|
|
||||||
env.zkTrieTracer[addrStr].Merge(zktrieTracer)
|
|
||||||
}
|
|
||||||
env.sMu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
env.executionResults[index] = &types.ExecutionResult{
|
|
||||||
From: sender,
|
|
||||||
To: receiver,
|
|
||||||
AccountCreated: createdAcc,
|
|
||||||
AccountsAfter: after,
|
|
||||||
L1DataFee: (*hexutil.Big)(result.L1DataFee),
|
|
||||||
Gas: result.UsedGas,
|
|
||||||
Failed: result.Failed(),
|
|
||||||
ReturnValue: fmt.Sprintf("%x", returnVal),
|
|
||||||
StructLogs: vm.FormatLogs(tracer.StructLogs()),
|
|
||||||
}
|
|
||||||
env.txStorageTraces[index] = txStorageTrace
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill blockTrace content after all the txs are finished running.
|
|
||||||
func (api *API) fillBlockTrace(env *traceEnv, block *types.Block) (*types.BlockTrace, error) {
|
|
||||||
statedb := env.state
|
|
||||||
|
|
||||||
txs := make([]*types.TransactionData, block.Transactions().Len())
|
|
||||||
for i, tx := range block.Transactions() {
|
|
||||||
txs[i] = types.NewTransactionData(tx, block.NumberU64(), api.backend.ChainConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
intrinsicStorageProofs := map[common.Address][]common.Hash{
|
|
||||||
rcfg.L2MessageQueueAddress: {rcfg.WithdrawTrieRootSlot},
|
|
||||||
rcfg.L1GasPriceOracleAddress: {
|
|
||||||
rcfg.L1BaseFeeSlot,
|
|
||||||
rcfg.OverheadSlot,
|
|
||||||
rcfg.ScalarSlot,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for addr, storages := range intrinsicStorageProofs {
|
|
||||||
if _, existed := env.Proofs[addr.String()]; !existed {
|
|
||||||
if proof, err := statedb.GetProof(addr); err != nil {
|
|
||||||
log.Error("Proof for intrinstic address not available", "error", err, "address", addr)
|
|
||||||
} else {
|
|
||||||
wrappedProof := make([]hexutil.Bytes, len(proof))
|
|
||||||
for i, bt := range proof {
|
|
||||||
wrappedProof[i] = bt
|
|
||||||
}
|
|
||||||
env.Proofs[addr.String()] = wrappedProof
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, existed := env.StorageProofs[addr.String()]; !existed {
|
|
||||||
env.StorageProofs[addr.String()] = make(map[string][]hexutil.Bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, slot := range storages {
|
|
||||||
if _, existed := env.StorageProofs[addr.String()][slot.String()]; !existed {
|
|
||||||
if trie, err := statedb.GetStorageTrieForProof(addr); err != nil {
|
|
||||||
log.Error("Storage proof for intrinstic address not available", "error", err, "address", addr)
|
|
||||||
} else if proof, _ := statedb.GetSecureTrieProof(trie, slot); err != nil {
|
|
||||||
log.Error("Get storage proof for intrinstic address failed", "error", err, "address", addr, "slot", slot)
|
|
||||||
} else {
|
|
||||||
wrappedProof := make([]hexutil.Bytes, len(proof))
|
|
||||||
for i, bt := range proof {
|
|
||||||
wrappedProof[i] = bt
|
|
||||||
}
|
|
||||||
env.StorageProofs[addr.String()][slot.String()] = wrappedProof
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockTrace := &types.BlockTrace{
|
|
||||||
ChainID: api.backend.ChainConfig().ChainID.Uint64(),
|
|
||||||
Version: params.ArchiveVersion(params.CommitHash),
|
|
||||||
Coinbase: &types.AccountWrapper{
|
|
||||||
Address: env.coinbase,
|
|
||||||
Nonce: statedb.GetNonce(env.coinbase),
|
|
||||||
Balance: (*hexutil.Big)(statedb.GetBalance(env.coinbase)),
|
|
||||||
KeccakCodeHash: statedb.GetKeccakCodeHash(env.coinbase),
|
|
||||||
PoseidonCodeHash: statedb.GetPoseidonCodeHash(env.coinbase),
|
|
||||||
CodeSize: statedb.GetCodeSize(env.coinbase),
|
|
||||||
},
|
|
||||||
Header: block.Header(),
|
|
||||||
StorageTrace: env.StorageTrace,
|
|
||||||
ExecutionResults: env.executionResults,
|
|
||||||
TxStorageTraces: env.txStorageTraces,
|
|
||||||
Transactions: txs,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
|
||||||
evmTrace := env.executionResults[i]
|
|
||||||
// probably a Contract Call
|
|
||||||
if len(tx.Data()) != 0 && tx.To() != nil {
|
|
||||||
evmTrace.ByteCode = hexutil.Encode(statedb.GetCode(*tx.To()))
|
|
||||||
// Get tx.to address's code hash.
|
|
||||||
codeHash := statedb.GetPoseidonCodeHash(*tx.To())
|
|
||||||
evmTrace.PoseidonCodeHash = &codeHash
|
|
||||||
} else if tx.To() == nil { // Contract is created.
|
|
||||||
evmTrace.ByteCode = hexutil.Encode(tx.Data())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// only zktrie model has the ability to get `mptwitness`.
|
|
||||||
if api.backend.ChainConfig().Scroll.ZktrieEnabled() {
|
|
||||||
if err := zkproof.FillBlockTraceForMPTWitness(zkproof.MPTWitnessType(api.backend.CacheConfig().MPTWitness), blockTrace); err != nil {
|
|
||||||
log.Error("fill mpt witness fail", "error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockTrace.WithdrawTrieRoot = withdrawtrie.ReadWTRSlot(rcfg.L2MessageQueueAddress, env.state)
|
|
||||||
|
|
||||||
return blockTrace, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i
|
||||||
SnapshotLimit: 0,
|
SnapshotLimit: 0,
|
||||||
TrieDirtyDisabled: true, // Archive mode
|
TrieDirtyDisabled: true, // Archive mode
|
||||||
}
|
}
|
||||||
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, false)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestNodeIterator(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(fulldb)
|
genesis = gspec.MustCommit(fulldb)
|
||||||
)
|
)
|
||||||
gspec.MustCommit(lightdb)
|
gspec.MustCommit(lightdb)
|
||||||
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, false)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ func TestTxPool(t *testing.T) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil, false)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ func createMiner(t *testing.T) (*Miner, *event.TypeMux) {
|
||||||
// Create consensus engine
|
// Create consensus engine
|
||||||
engine := clique.New(chainConfig.Clique, chainDB)
|
engine := clique.New(chainConfig.Clique, chainDB)
|
||||||
// Create Ethereum backend
|
// Create Ethereum backend
|
||||||
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil)
|
bc, err := core.NewBlockChain(chainDB, nil, chainConfig, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("can't create new chain %v", err)
|
t.Fatalf("can't create new chain %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
172
miner/worker.go
172
miner/worker.go
|
|
@ -36,6 +36,7 @@ import (
|
||||||
"github.com/scroll-tech/go-ethereum/event"
|
"github.com/scroll-tech/go-ethereum/event"
|
||||||
"github.com/scroll-tech/go-ethereum/log"
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
"github.com/scroll-tech/go-ethereum/params"
|
"github.com/scroll-tech/go-ethereum/params"
|
||||||
|
"github.com/scroll-tech/go-ethereum/rollup/circuitcapacitychecker"
|
||||||
"github.com/scroll-tech/go-ethereum/trie"
|
"github.com/scroll-tech/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -95,14 +96,21 @@ type environment struct {
|
||||||
header *types.Header
|
header *types.Header
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
receipts []*types.Receipt
|
receipts []*types.Receipt
|
||||||
|
|
||||||
|
// circuit capacity check related fields
|
||||||
|
traceEnv *core.TraceEnv // env for tracing
|
||||||
|
accRows *types.RowConsumption // accumulated row consumption for a block
|
||||||
|
maxL1Index uint64 // maximum L1 index included or skipped
|
||||||
}
|
}
|
||||||
|
|
||||||
// task contains all information for consensus engine sealing and result submitting.
|
// task contains all information for consensus engine sealing and result submitting.
|
||||||
type task struct {
|
type task struct {
|
||||||
receipts []*types.Receipt
|
receipts []*types.Receipt
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
block *types.Block
|
block *types.Block
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
|
accRows *types.RowConsumption // accumulated row consumption in the circuit side
|
||||||
|
maxL1Index uint64 // maximum L1 index included or skipped
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -190,6 +198,8 @@ type worker struct {
|
||||||
// External functions
|
// External functions
|
||||||
isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner.
|
isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner.
|
||||||
|
|
||||||
|
circuitCapacityChecker *circuitcapacitychecker.CircuitCapacityChecker
|
||||||
|
|
||||||
// Test hooks
|
// Test hooks
|
||||||
newTaskHook func(*task) // Method to call upon receiving a new sealing task.
|
newTaskHook func(*task) // Method to call upon receiving a new sealing task.
|
||||||
skipSealHook func(*task) bool // Method to decide whether skipping the sealing.
|
skipSealHook func(*task) bool // Method to decide whether skipping the sealing.
|
||||||
|
|
@ -199,29 +209,31 @@ type worker struct {
|
||||||
|
|
||||||
func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool, init bool) *worker {
|
func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool, init bool) *worker {
|
||||||
worker := &worker{
|
worker := &worker{
|
||||||
config: config,
|
config: config,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
eth: eth,
|
eth: eth,
|
||||||
mux: mux,
|
mux: mux,
|
||||||
chain: eth.BlockChain(),
|
chain: eth.BlockChain(),
|
||||||
isLocalBlock: isLocalBlock,
|
isLocalBlock: isLocalBlock,
|
||||||
localUncles: make(map[common.Hash]*types.Block),
|
localUncles: make(map[common.Hash]*types.Block),
|
||||||
remoteUncles: make(map[common.Hash]*types.Block),
|
remoteUncles: make(map[common.Hash]*types.Block),
|
||||||
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth),
|
unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth),
|
||||||
pendingTasks: make(map[common.Hash]*task),
|
pendingTasks: make(map[common.Hash]*task),
|
||||||
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
txsCh: make(chan core.NewTxsEvent, txChanSize),
|
||||||
l1MsgsCh: make(chan core.NewL1MsgsEvent, txChanSize),
|
l1MsgsCh: make(chan core.NewL1MsgsEvent, txChanSize),
|
||||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
||||||
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
|
||||||
newWorkCh: make(chan *newWorkReq),
|
newWorkCh: make(chan *newWorkReq),
|
||||||
taskCh: make(chan *task),
|
taskCh: make(chan *task),
|
||||||
resultCh: make(chan *types.Block, resultQueueSize),
|
resultCh: make(chan *types.Block, resultQueueSize),
|
||||||
exitCh: make(chan struct{}),
|
exitCh: make(chan struct{}),
|
||||||
startCh: make(chan struct{}, 1),
|
startCh: make(chan struct{}, 1),
|
||||||
resubmitIntervalCh: make(chan time.Duration),
|
resubmitIntervalCh: make(chan time.Duration),
|
||||||
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
|
||||||
|
circuitCapacityChecker: circuitcapacitychecker.NewCircuitCapacityChecker(),
|
||||||
}
|
}
|
||||||
|
log.Info("created new worker", "CircuitCapacityChecker ID", worker.circuitCapacityChecker.ID)
|
||||||
|
|
||||||
// Subscribe NewTxsEvent for tx pool
|
// Subscribe NewTxsEvent for tx pool
|
||||||
worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh)
|
worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh)
|
||||||
|
|
@ -625,6 +637,14 @@ func (w *worker) taskLoop() {
|
||||||
w.pendingMu.Lock()
|
w.pendingMu.Lock()
|
||||||
delete(w.pendingTasks, sealHash)
|
delete(w.pendingTasks, sealHash)
|
||||||
w.pendingMu.Unlock()
|
w.pendingMu.Unlock()
|
||||||
|
} else {
|
||||||
|
// Store highest L1 queue index processed by this block. This includes both
|
||||||
|
// included and skipped messages. This way, if a block only skips messages,
|
||||||
|
// we won't reprocess the same messages from the next block.
|
||||||
|
rawdb.WriteFirstQueueIndexNotInL2Block(w.eth.ChainDb(), sealHash, task.maxL1Index+1)
|
||||||
|
|
||||||
|
// Store circuit row consumption.
|
||||||
|
rawdb.WriteBlockRowConsumption(w.eth.ChainDb(), sealHash, task.accRows)
|
||||||
}
|
}
|
||||||
case <-w.exitCh:
|
case <-w.exitCh:
|
||||||
interrupt()
|
interrupt()
|
||||||
|
|
@ -714,6 +734,15 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
traceEnv, err := core.CreateTraceEnv(w.chainConfig, w.chain, w.engine, state, parent,
|
||||||
|
// new block with a placeholder tx, for traceEnv's ExecutionResults length & TxStorageTraces length
|
||||||
|
types.NewBlockWithHeader(header).WithBody([]*types.Transaction{types.NewTx(&types.LegacyTx{})}, nil),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
state.StartPrefetcher("miner")
|
state.StartPrefetcher("miner")
|
||||||
|
|
||||||
env := &environment{
|
env := &environment{
|
||||||
|
|
@ -723,6 +752,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
|
||||||
family: mapset.NewSet(),
|
family: mapset.NewSet(),
|
||||||
uncles: mapset.NewSet(),
|
uncles: mapset.NewSet(),
|
||||||
header: header,
|
header: header,
|
||||||
|
traceEnv: traceEnv,
|
||||||
}
|
}
|
||||||
// when 08 is processed ancestors contain 07 (quick block)
|
// when 08 is processed ancestors contain 07 (quick block)
|
||||||
for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) {
|
||||||
|
|
@ -736,6 +766,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
|
||||||
env.tcount = 0
|
env.tcount = 0
|
||||||
env.blockSize = 0
|
env.blockSize = 0
|
||||||
env.l1TxCount = 0
|
env.l1TxCount = 0
|
||||||
|
env.maxL1Index = 0
|
||||||
|
|
||||||
// Swap out the old work with the new one, terminating any leftover prefetcher
|
// Swap out the old work with the new one, terminating any leftover prefetcher
|
||||||
// processes in the mean time and starting a new one.
|
// processes in the mean time and starting a new one.
|
||||||
|
|
@ -802,21 +833,44 @@ func (w *worker) updateSnapshot() {
|
||||||
func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
|
func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
|
||||||
snap := w.current.state.Snapshot()
|
snap := w.current.state.Snapshot()
|
||||||
|
|
||||||
|
// has to check circuit capacity before `core.ApplyTransaction`,
|
||||||
|
// because if the tx can be successfully executed but circuit capacity overflows, it will be inconvenient to revert
|
||||||
|
traces, err := w.current.traceEnv.GetBlockTrace(
|
||||||
|
types.NewBlockWithHeader(w.current.header).WithBody([]*types.Transaction{tx}, nil),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
// `w.current.traceEnv.State` & `w.current.state` share a same pointer to the state, so only need to revert `w.current.state`
|
||||||
|
w.current.state.RevertToSnapshot(snap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
accRows, err := w.circuitCapacityChecker.ApplyTransaction(traces)
|
||||||
|
if err != nil {
|
||||||
|
// `w.current.traceEnv.State` & `w.current.state` share a same pointer to the state, so only need to revert `w.current.state`
|
||||||
|
w.current.state.RevertToSnapshot(snap)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert to snapshot for calling `core.ApplyMessage` again, (both `traceEnv.GetBlockTrace` & `core.ApplyTransaction` will call `core.ApplyMessage`)
|
||||||
|
w.current.state.RevertToSnapshot(snap)
|
||||||
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig())
|
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.current.state.RevertToSnapshot(snap)
|
w.current.state.RevertToSnapshot(snap)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.current.txs = append(w.current.txs, tx)
|
w.current.txs = append(w.current.txs, tx)
|
||||||
w.current.receipts = append(w.current.receipts, receipt)
|
w.current.receipts = append(w.current.receipts, receipt)
|
||||||
|
w.current.accRows = accRows
|
||||||
|
|
||||||
return receipt.Logs, nil
|
return receipt.Logs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool {
|
func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) (bool, bool) {
|
||||||
|
var circuitCapacityReached bool
|
||||||
|
|
||||||
// Short circuit if current is nil
|
// Short circuit if current is nil
|
||||||
if w.current == nil {
|
if w.current == nil {
|
||||||
return true
|
return true, circuitCapacityReached
|
||||||
}
|
}
|
||||||
|
|
||||||
gasLimit := w.current.header.GasLimit
|
gasLimit := w.current.header.GasLimit
|
||||||
|
|
@ -826,6 +880,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
||||||
|
|
||||||
var coalescedLogs []*types.Log
|
var coalescedLogs []*types.Log
|
||||||
|
|
||||||
|
loop:
|
||||||
for {
|
for {
|
||||||
// In the following three cases, we will interrupt the execution of the transaction.
|
// In the following three cases, we will interrupt the execution of the transaction.
|
||||||
// (1) new head block event arrival, the interrupt signal is 1
|
// (1) new head block event arrival, the interrupt signal is 1
|
||||||
|
|
@ -845,7 +900,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
||||||
inc: true,
|
inc: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return atomic.LoadInt32(interrupt) == commitInterruptNewHead
|
return atomic.LoadInt32(interrupt) == commitInterruptNewHead, circuitCapacityReached
|
||||||
}
|
}
|
||||||
// If we have collected enough transactions then we're done
|
// If we have collected enough transactions then we're done
|
||||||
if !w.chainConfig.Scroll.IsValidL2TxCount(w.current.tcount - w.current.l1TxCount + 1) {
|
if !w.chainConfig.Scroll.IsValidL2TxCount(w.current.tcount - w.current.l1TxCount + 1) {
|
||||||
|
|
@ -905,6 +960,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
||||||
coalescedLogs = append(coalescedLogs, logs...)
|
coalescedLogs = append(coalescedLogs, logs...)
|
||||||
if tx.IsL1MessageTx() {
|
if tx.IsL1MessageTx() {
|
||||||
w.current.l1TxCount++
|
w.current.l1TxCount++
|
||||||
|
w.current.maxL1Index = tx.AsL1MessageTx().QueueIndex
|
||||||
}
|
}
|
||||||
w.current.tcount++
|
w.current.tcount++
|
||||||
w.current.blockSize += tx.Size()
|
w.current.blockSize += tx.Size()
|
||||||
|
|
@ -915,6 +971,43 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
||||||
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
|
log.Trace("Skipping unsupported transaction type", "sender", from, "type", tx.Type())
|
||||||
txs.Pop()
|
txs.Pop()
|
||||||
|
|
||||||
|
case errors.Is(err, circuitcapacitychecker.ErrBlockRowConsumptionOverflow):
|
||||||
|
// Circuit capacity check: circuit capacity limit reached in a block,
|
||||||
|
// don't pop or shift, just quit the loop immediately;
|
||||||
|
// though it might still be possible to add some "smaller" txs,
|
||||||
|
// but it's a trade-off between tracing overhead & block usage rate
|
||||||
|
log.Trace("Circuit capacity limit reached in a block", "acc_rows", w.current.accRows, "tx", tx.Hash())
|
||||||
|
circuitCapacityReached = true
|
||||||
|
break loop
|
||||||
|
|
||||||
|
case (errors.Is(err, circuitcapacitychecker.ErrTxRowConsumptionOverflow) && tx.IsL1MessageTx()):
|
||||||
|
// Circuit capacity check: L1MessageTx row consumption too high, shift to the next from the account,
|
||||||
|
// because we shouldn't skip the entire txs from the same account.
|
||||||
|
// This is also useful for skipping "problematic" L1MessageTxs.
|
||||||
|
queueIndex := tx.AsL1MessageTx().QueueIndex
|
||||||
|
log.Trace("Circuit capacity limit reached for a single tx", "tx", tx.Hash(), "queueIndex", queueIndex)
|
||||||
|
w.current.maxL1Index = queueIndex
|
||||||
|
txs.Shift()
|
||||||
|
|
||||||
|
case (errors.Is(err, circuitcapacitychecker.ErrTxRowConsumptionOverflow) && !tx.IsL1MessageTx()):
|
||||||
|
// Circuit capacity check: L2MessageTx row consumption too high, skip the account.
|
||||||
|
// This is also useful for skipping "problematic" L2MessageTxs.
|
||||||
|
log.Trace("Circuit capacity limit reached for a single tx", "tx", tx.Hash())
|
||||||
|
txs.Pop()
|
||||||
|
|
||||||
|
case (errors.Is(err, circuitcapacitychecker.ErrUnknown) && tx.IsL1MessageTx()):
|
||||||
|
// Circuit capacity check: unknown circuit capacity checker error for L1MessageTx,
|
||||||
|
// shift to the next from the account because we shouldn't skip the entire txs from the same account
|
||||||
|
queueIndex := tx.AsL1MessageTx().QueueIndex
|
||||||
|
log.Trace("Unknown circuit capacity checker error for L1MessageTx", "tx", tx.Hash(), "queueIndex", queueIndex)
|
||||||
|
w.current.maxL1Index = queueIndex
|
||||||
|
txs.Shift()
|
||||||
|
|
||||||
|
case (errors.Is(err, circuitcapacitychecker.ErrUnknown) && !tx.IsL1MessageTx()):
|
||||||
|
// Circuit capacity check: unknown circuit capacity checker error for L2MessageTx, skip the account
|
||||||
|
log.Trace("Unknown circuit capacity checker error for L2MessageTx", "tx", tx.Hash())
|
||||||
|
txs.Pop()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Strange error, discard the transaction and get the next in line (note, the
|
// Strange error, discard the transaction and get the next in line (note, the
|
||||||
// nonce-too-high clause will prevent us from executing in vain).
|
// nonce-too-high clause will prevent us from executing in vain).
|
||||||
|
|
@ -943,7 +1036,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin
|
||||||
if interrupt != nil {
|
if interrupt != nil {
|
||||||
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
w.resubmitAdjustCh <- &intervalAdjust{inc: false}
|
||||||
}
|
}
|
||||||
return false
|
return false, circuitCapacityReached
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) collectPendingL1Messages() []types.L1MessageTx {
|
func (w *worker) collectPendingL1Messages() []types.L1MessageTx {
|
||||||
|
|
@ -964,6 +1057,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
|
||||||
|
|
||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
parent := w.chain.CurrentBlock()
|
parent := w.chain.CurrentBlock()
|
||||||
|
w.circuitCapacityChecker.Reset()
|
||||||
|
|
||||||
if parent.Time() >= uint64(timestamp) {
|
if parent.Time() >= uint64(timestamp) {
|
||||||
timestamp = int64(parent.Time() + 1)
|
timestamp = int64(parent.Time() + 1)
|
||||||
|
|
@ -1092,22 +1186,28 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
|
||||||
localTxs[account] = txs
|
localTxs[account] = txs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var skipCommit, circuitCapacityReached bool
|
||||||
if w.chainConfig.Scroll.ShouldIncludeL1Messages() && len(l1Txs) > 0 {
|
if w.chainConfig.Scroll.ShouldIncludeL1Messages() && len(l1Txs) > 0 {
|
||||||
log.Trace("Processing L1 messages for inclusion", "count", pendingL1Txs)
|
log.Trace("Processing L1 messages for inclusion", "count", pendingL1Txs)
|
||||||
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, l1Txs, header.BaseFee)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, l1Txs, header.BaseFee)
|
||||||
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
skipCommit, circuitCapacityReached = w.commitTransactions(txs, w.coinbase, interrupt)
|
||||||
|
if skipCommit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(localTxs) > 0 {
|
if len(localTxs) > 0 && !circuitCapacityReached {
|
||||||
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs, header.BaseFee)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs, header.BaseFee)
|
||||||
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
skipCommit, circuitCapacityReached = w.commitTransactions(txs, w.coinbase, interrupt)
|
||||||
|
if skipCommit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(remoteTxs) > 0 {
|
if len(remoteTxs) > 0 && !circuitCapacityReached {
|
||||||
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs, header.BaseFee)
|
txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs, header.BaseFee)
|
||||||
if w.commitTransactions(txs, w.coinbase, interrupt) {
|
// don't need to get `circuitCapacityReached` here because we don't have further `commitTransactions`
|
||||||
|
// after this one, and if we assign it won't take effect (`ineffassign`)
|
||||||
|
skipCommit, _ = w.commitTransactions(txs, w.coinbase, interrupt)
|
||||||
|
if skipCommit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1135,7 +1235,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st
|
||||||
interval()
|
interval()
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}:
|
case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now(), accRows: w.current.accRows, maxL1Index: w.current.maxL1Index}:
|
||||||
w.unconfirmed.Shift(block.NumberU64() - 1)
|
w.unconfirmed.Shift(block.NumberU64() - 1)
|
||||||
log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()),
|
log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()),
|
||||||
"uncles", len(uncles), "txs", w.current.tcount,
|
"uncles", len(uncles), "txs", w.current.tcount,
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{
|
chain, _ := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec.Config, engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true})}, nil, nil, false)
|
||||||
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
||||||
|
|
||||||
// Generate a small n-block chain and an uncle block for it
|
// Generate a small n-block chain and an uncle block for it
|
||||||
|
|
@ -241,7 +241,7 @@ func testGenerateBlockAndImport(t *testing.T, isClique bool) {
|
||||||
b.genesis.MustCommit(db2)
|
b.genesis.MustCommit(db2)
|
||||||
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{
|
chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
@ -571,7 +571,7 @@ func testGenerateBlockWithL1Msg(t *testing.T, isClique bool) {
|
||||||
b.genesis.MustCommit(db)
|
b.genesis.MustCommit(db)
|
||||||
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
@ -637,7 +637,7 @@ func TestExcludeL1MsgFromTxlimit(t *testing.T) {
|
||||||
b.genesis.MustCommit(db)
|
b.genesis.MustCommit(db)
|
||||||
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
@ -698,7 +698,7 @@ func TestL1MsgCorrectOrder(t *testing.T) {
|
||||||
b.genesis.MustCommit(db)
|
b.genesis.MustCommit(db)
|
||||||
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
chain, _ := core.NewBlockChain(db, nil, b.chain.Config(), engine, vm.Config{
|
||||||
Debug: true,
|
Debug: true,
|
||||||
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil)
|
Tracer: vm.NewStructLogger(&vm.LogConfig{EnableMemory: true, EnableReturnData: true})}, nil, nil, false)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Ignore empty commit here for less noise.
|
// Ignore empty commit here for less noise.
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 4 // Major version component of the current release
|
VersionMajor = 4 // Major version component of the current release
|
||||||
VersionMinor = 3 // Minor version component of the current release
|
VersionMinor = 3 // Minor version component of the current release
|
||||||
VersionPatch = 0 // Patch version component of the current release
|
VersionPatch = 1 // Patch version component of the current release
|
||||||
VersionMeta = "sepolia" // Version metadata to append to the version string
|
VersionMeta = "sepolia" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
141
rollup/circuitcapacitychecker/impl.go
Normal file
141
rollup/circuitcapacitychecker/impl.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
//go:build circuit_capacity_checker
|
||||||
|
|
||||||
|
package circuitcapacitychecker
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -lm -ldl -lzkp -lzktrie
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "./libzkp/libzkp.h"
|
||||||
|
*/
|
||||||
|
import "C" //nolint:typecheck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
"github.com/scroll-tech/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mutex for concurrent CircuitCapacityChecker creations
|
||||||
|
var creationMu sync.Mutex
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
C.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
type CircuitCapacityChecker struct {
|
||||||
|
// mutex for each CircuitCapacityChecker itself
|
||||||
|
sync.Mutex
|
||||||
|
ID uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCircuitCapacityChecker() *CircuitCapacityChecker {
|
||||||
|
creationMu.Lock()
|
||||||
|
defer creationMu.Unlock()
|
||||||
|
|
||||||
|
id := C.new_circuit_capacity_checker()
|
||||||
|
return &CircuitCapacityChecker{ID: uint64(id)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) Reset() {
|
||||||
|
ccc.Lock()
|
||||||
|
defer ccc.Unlock()
|
||||||
|
|
||||||
|
C.reset_circuit_capacity_checker(C.uint64_t(ccc.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||||
|
ccc.Lock()
|
||||||
|
defer ccc.Unlock()
|
||||||
|
|
||||||
|
if len(traces.Transactions) != 1 || len(traces.ExecutionResults) != 1 || len(traces.TxStorageTraces) != 1 {
|
||||||
|
log.Error("malformatted BlockTrace in ApplyTransaction", "id", ccc.ID,
|
||||||
|
"len(traces.Transactions)", len(traces.Transactions),
|
||||||
|
"len(traces.ExecutionResults)", len(traces.ExecutionResults),
|
||||||
|
"len(traces.TxStorageTraces)", len(traces.TxStorageTraces),
|
||||||
|
"err", "length of Transactions, or ExecutionResults, or TxStorageTraces, is not equal to 1")
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
tracesByt, err := json.Marshal(traces)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("fail to json marshal traces in ApplyTransaction", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", err)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
tracesStr := C.CString(string(tracesByt))
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(tracesStr))
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Debug("start to check circuit capacity for tx", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash)
|
||||||
|
rawResult := C.apply_tx(C.uint64_t(ccc.ID), tracesStr)
|
||||||
|
log.Debug("check circuit capacity for tx done", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash)
|
||||||
|
|
||||||
|
result := &WrappedRowUsage{}
|
||||||
|
if err = json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
|
||||||
|
log.Error("fail to json unmarshal apply_tx result", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", err)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Error != "" {
|
||||||
|
log.Error("fail to apply_tx in CircuitCapacityChecker", "id", ccc.ID, "TxHash", traces.Transactions[0].TxHash, "err", result.Error)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
if result.TxRowUsage == nil || result.AccRowUsage == nil {
|
||||||
|
log.Error("fail to apply_tx in CircuitCapacityChecker",
|
||||||
|
"id", ccc.ID, "TxHash", traces.Transactions[0].TxHash,
|
||||||
|
"len(result.TxRowUsage)", len(result.TxRowUsage),
|
||||||
|
"len(result.AccRowUsage)", len(result.AccRowUsage),
|
||||||
|
"err", "TxRowUsage or AccRowUsage is empty unexpectedly")
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
if !result.TxRowUsage.IsOk {
|
||||||
|
return nil, ErrTxRowConsumptionOverflow
|
||||||
|
}
|
||||||
|
if !result.AccRowUsage.IsOk {
|
||||||
|
return nil, ErrBlockRowConsumptionOverflow
|
||||||
|
}
|
||||||
|
return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||||
|
ccc.Lock()
|
||||||
|
defer ccc.Unlock()
|
||||||
|
|
||||||
|
tracesByt, err := json.Marshal(traces)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("fail to json marshal traces in ApplyBlock", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", err)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
tracesStr := C.CString(string(tracesByt))
|
||||||
|
defer func() {
|
||||||
|
C.free(unsafe.Pointer(tracesStr))
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Debug("start to check circuit capacity for block", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash())
|
||||||
|
rawResult := C.apply_block(C.uint64_t(ccc.ID), tracesStr)
|
||||||
|
log.Debug("check circuit capacity for block done", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash())
|
||||||
|
|
||||||
|
result := &WrappedRowUsage{}
|
||||||
|
if err = json.Unmarshal([]byte(C.GoString(rawResult)), result); err != nil {
|
||||||
|
log.Error("fail to json unmarshal apply_block result", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", err)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Error != "" {
|
||||||
|
log.Error("fail to apply_block in CircuitCapacityChecker", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", result.Error)
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
if result.AccRowUsage == nil {
|
||||||
|
log.Error("fail to apply_block in CircuitCapacityChecker", "id", ccc.ID, "blockNumber", traces.Header.Number, "blockHash", traces.Header.Hash(), "err", "AccRowUsage is empty unexpectedly")
|
||||||
|
return nil, ErrUnknown
|
||||||
|
}
|
||||||
|
if !result.AccRowUsage.IsOk {
|
||||||
|
return nil, ErrBlockRowConsumptionOverflow
|
||||||
|
}
|
||||||
|
return (*types.RowConsumption)(&result.AccRowUsage.RowUsageDetails), nil
|
||||||
|
}
|
||||||
3
rollup/circuitcapacitychecker/libzkp/.gitignore
vendored
Normal file
3
rollup/circuitcapacitychecker/libzkp/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
target/
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
4504
rollup/circuitcapacitychecker/libzkp/Cargo.lock
generated
Normal file
4504
rollup/circuitcapacitychecker/libzkp/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
39
rollup/circuitcapacitychecker/libzkp/Cargo.toml
Normal file
39
rollup/circuitcapacitychecker/libzkp/Cargo.toml
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
[package]
|
||||||
|
name = "zkp"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
|
[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
|
||||||
|
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
|
||||||
|
[patch."https://github.com/privacy-scaling-explorations/poseidon.git"]
|
||||||
|
poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "scroll-dev-0220" }
|
||||||
|
[patch."https://github.com/privacy-scaling-explorations/halo2wrong.git"]
|
||||||
|
halo2wrong = { git = "https://github.com/scroll-tech/halo2wrong.git", branch = "halo2-ecc-snark-verifier-0323" }
|
||||||
|
maingate = { git = "https://github.com/scroll-tech/halo2wrong", branch = "halo2-ecc-snark-verifier-0323" }
|
||||||
|
[patch."https://github.com/privacy-scaling-explorations/halo2curves.git"]
|
||||||
|
halo2curves = { git = "https://github.com/scroll-tech/halo2curves.git", branch = "0.3.1-derive-serde" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
prover = { git = "https://github.com/scroll-tech/scroll-prover", rev="26e9cf7" }
|
||||||
|
types = { git = "https://github.com/scroll-tech/scroll-prover", rev="26e9cf7" }
|
||||||
|
|
||||||
|
log = "0.4"
|
||||||
|
env_logger = "0.9.0"
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0.66"
|
||||||
|
libc = "0.2"
|
||||||
|
once_cell = "1.8.0"
|
||||||
|
|
||||||
|
|
||||||
|
[profile.test]
|
||||||
|
opt-level = 3
|
||||||
|
debug-assertions = true
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
debug-assertions = true
|
||||||
10
rollup/circuitcapacitychecker/libzkp/Makefile
Normal file
10
rollup/circuitcapacitychecker/libzkp/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
.PHONY: clean libzkp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.a *.so
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
libzkp:
|
||||||
|
cargo build --release
|
||||||
|
cp $(PWD)/target/release/libzkp.so $(PWD)/
|
||||||
|
find $(PWD)/target | grep libzktrie.so | xargs -I{} cp {} $(PWD)/
|
||||||
6
rollup/circuitcapacitychecker/libzkp/libzkp.h
Normal file
6
rollup/circuitcapacitychecker/libzkp/libzkp.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include<stdint.h>
|
||||||
|
void init();
|
||||||
|
uint64_t new_circuit_capacity_checker();
|
||||||
|
void reset_circuit_capacity_checker(uint64_t id);
|
||||||
|
char* apply_tx(uint64_t id, char *tx_traces);
|
||||||
|
char* apply_block(uint64_t id, char *block_trace);
|
||||||
1
rollup/circuitcapacitychecker/libzkp/rust-toolchain
Normal file
1
rollup/circuitcapacitychecker/libzkp/rust-toolchain
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
nightly-2022-12-10
|
||||||
190
rollup/circuitcapacitychecker/libzkp/src/lib.rs
Normal file
190
rollup/circuitcapacitychecker/libzkp/src/lib.rs
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
#![feature(once_cell)]
|
||||||
|
|
||||||
|
pub mod checker {
|
||||||
|
use crate::utils::{c_char_to_vec, vec_to_c_char};
|
||||||
|
use libc::c_char;
|
||||||
|
use prover::zkevm::{CircuitCapacityChecker, RowUsage};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::panic;
|
||||||
|
use std::ptr::null;
|
||||||
|
use types::eth::BlockTrace;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
|
pub struct RowUsageResult {
|
||||||
|
pub acc_row_usage: Option<RowUsage>,
|
||||||
|
pub tx_row_usage: Option<RowUsage>,
|
||||||
|
pub error: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut CHECKERS: OnceCell<HashMap<u64, CircuitCapacityChecker>> = OnceCell::new();
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn init() {
|
||||||
|
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
|
||||||
|
.format_timestamp_millis()
|
||||||
|
.init();
|
||||||
|
let checkers = HashMap::new();
|
||||||
|
CHECKERS
|
||||||
|
.set(checkers)
|
||||||
|
.expect("circuit capacity checker initialized twice");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn new_circuit_capacity_checker() -> u64 {
|
||||||
|
let checkers = CHECKERS
|
||||||
|
.get_mut()
|
||||||
|
.expect("fail to get circuit capacity checkers map in new_circuit_capacity_checker");
|
||||||
|
let id = checkers.len() as u64;
|
||||||
|
let checker = CircuitCapacityChecker::new();
|
||||||
|
checkers.insert(id, checker);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn reset_circuit_capacity_checker(id: u64) {
|
||||||
|
CHECKERS
|
||||||
|
.get_mut()
|
||||||
|
.expect("fail to get circuit capacity checkers map in reset_circuit_capacity_checker")
|
||||||
|
.get_mut(&id)
|
||||||
|
.unwrap_or_else(|| panic!("fail to get circuit capacity checker (id: {id:?}) in reset_circuit_capacity_checker"))
|
||||||
|
.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn apply_tx(id: u64, tx_traces: *const c_char) -> *const c_char {
|
||||||
|
let result = panic::catch_unwind(|| {
|
||||||
|
let tx_traces_vec = c_char_to_vec(tx_traces);
|
||||||
|
let traces = serde_json::from_slice::<BlockTrace>(&tx_traces_vec)
|
||||||
|
.unwrap_or_else(|_| panic!("id: {id:?}, fail to deserialize tx_traces"));
|
||||||
|
if traces.transactions.len() != 1 {
|
||||||
|
panic!("traces.transactions.len() != 1")
|
||||||
|
} else if traces.execution_results.len() != 1 {
|
||||||
|
panic!("traces.execution_results.len() != 1")
|
||||||
|
} else if traces.tx_storage_trace.len() != 1 {
|
||||||
|
panic!("traces.tx_storage_trace.len() != 1")
|
||||||
|
}
|
||||||
|
CHECKERS
|
||||||
|
.get_mut()
|
||||||
|
.expect("fail to get circuit capacity checkers map in apply_tx")
|
||||||
|
.get_mut(&id)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"fail to get circuit capacity checker (id: {id:?}) in apply_tx"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.estimate_circuit_capacity(&[traces.clone()])
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
panic!(
|
||||||
|
"id: {:?}, fail to estimate_circuit_capacity in apply_tx, block_hash: {:?}, tx_hash: {:?}",
|
||||||
|
id, traces.header.hash, traces.transactions[0].tx_hash
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let r = match result {
|
||||||
|
Ok((acc_row_usage, tx_row_usage)) => {
|
||||||
|
log::debug!(
|
||||||
|
"id: {:?}, acc_row_usage: {:?}, tx_row_usage: {:?}",
|
||||||
|
id,
|
||||||
|
acc_row_usage.row_number,
|
||||||
|
tx_row_usage.row_number
|
||||||
|
);
|
||||||
|
RowUsageResult {
|
||||||
|
acc_row_usage: Some(acc_row_usage),
|
||||||
|
tx_row_usage: Some(tx_row_usage),
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => RowUsageResult {
|
||||||
|
acc_row_usage: None,
|
||||||
|
tx_row_usage: None,
|
||||||
|
error: Some(format!("{e:?}")),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
serde_json::to_vec(&r).map_or(null(), vec_to_c_char)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn apply_block(id: u64, block_trace: *const c_char) -> *const c_char {
|
||||||
|
let result = panic::catch_unwind(|| {
|
||||||
|
let block_trace = c_char_to_vec(block_trace);
|
||||||
|
let traces = serde_json::from_slice::<BlockTrace>(&block_trace)
|
||||||
|
.unwrap_or_else(|_| panic!("id: {id:?}, fail to deserialize block_trace"));
|
||||||
|
CHECKERS
|
||||||
|
.get_mut()
|
||||||
|
.expect("fail to get circuit capacity checkers map in apply_block")
|
||||||
|
.get_mut(&id)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"fail to get circuit capacity checker (id: {id:?}) in apply_block"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.estimate_circuit_capacity(&[traces.clone()])
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
panic!(
|
||||||
|
"id: {:?}, fail to estimate_circuit_capacity in apply_block, block_hash: {:?}",
|
||||||
|
id, traces.header.hash
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
let r = match result {
|
||||||
|
Ok((acc_row_usage, tx_row_usage)) => {
|
||||||
|
log::debug!(
|
||||||
|
"id: {:?}, acc_row_usage: {:?}, tx_row_usage: {:?}",
|
||||||
|
id,
|
||||||
|
acc_row_usage.row_number,
|
||||||
|
tx_row_usage.row_number
|
||||||
|
);
|
||||||
|
RowUsageResult {
|
||||||
|
acc_row_usage: Some(acc_row_usage),
|
||||||
|
tx_row_usage: Some(tx_row_usage),
|
||||||
|
error: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => RowUsageResult {
|
||||||
|
acc_row_usage: None,
|
||||||
|
tx_row_usage: None,
|
||||||
|
error: Some(format!("{e:?}")),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
serde_json::to_vec(&r).map_or(null(), vec_to_c_char)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) mod utils {
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn c_char_to_str(c: *const c_char) -> &'static str {
|
||||||
|
let cstr = unsafe { CStr::from_ptr(c) };
|
||||||
|
cstr.to_str().expect("fail to cast cstr to str")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn c_char_to_vec(c: *const c_char) -> Vec<u8> {
|
||||||
|
let cstr = unsafe { CStr::from_ptr(c) };
|
||||||
|
cstr.to_bytes().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn vec_to_c_char(bytes: Vec<u8>) -> *const c_char {
|
||||||
|
CString::new(bytes)
|
||||||
|
.expect("fail to create new CString from bytes")
|
||||||
|
.into_raw()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn bool_to_int(b: bool) -> u8 {
|
||||||
|
match b {
|
||||||
|
true => 1,
|
||||||
|
false => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
rollup/circuitcapacitychecker/mock.go
Normal file
28
rollup/circuitcapacitychecker/mock.go
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
//go:build !circuit_capacity_checker
|
||||||
|
|
||||||
|
package circuitcapacitychecker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CircuitCapacityChecker struct {
|
||||||
|
ID uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCircuitCapacityChecker() *CircuitCapacityChecker {
|
||||||
|
return &CircuitCapacityChecker{ID: rand.Uint64()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) Reset() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) ApplyTransaction(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ccc *CircuitCapacityChecker) ApplyBlock(traces *types.BlockTrace) (*types.RowConsumption, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
19
rollup/circuitcapacitychecker/types.go
Normal file
19
rollup/circuitcapacitychecker/types.go
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
package circuitcapacitychecker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/scroll-tech/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnknown = errors.New("unknown circuit capacity checker error")
|
||||||
|
ErrTxRowConsumptionOverflow = errors.New("tx row consumption oveflow")
|
||||||
|
ErrBlockRowConsumptionOverflow = errors.New("block row consumption oveflow")
|
||||||
|
)
|
||||||
|
|
||||||
|
type WrappedRowUsage struct {
|
||||||
|
AccRowUsage *types.RowUsage `json:"acc_row_usage,omitempty"`
|
||||||
|
TxRowUsage *types.RowUsage `json:"tx_row_usage,omitempty"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
@ -127,7 +127,7 @@ func (t *BlockTest) Run(snapshotter bool) error {
|
||||||
cache.SnapshotLimit = 1
|
cache.SnapshotLimit = 1
|
||||||
cache.SnapshotWait = true
|
cache.SnapshotWait = true
|
||||||
}
|
}
|
||||||
chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil)
|
chain, err := core.NewBlockChain(db, cache, config, engine, vm.Config{}, nil, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func makechain() (bc *core.BlockChain, addrHashes, txHashes []common.Hash) {
|
||||||
addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:]))
|
addrHashes = append(addrHashes, crypto.Keccak256Hash(addr[:]))
|
||||||
txHashes = append(txHashes, tx.Hash())
|
txHashes = append(txHashes, tx.Hash())
|
||||||
})
|
})
|
||||||
bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil)
|
bc, _ = core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, false)
|
||||||
if _, err := bc.InsertChain(blocks); err != nil {
|
if _, err := bc.InsertChain(blocks); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue