Skip to content

Commit 233a6ad

Browse files
authored
feat: async ccc checker (#996)
1 parent 972fe8a commit 233a6ad

File tree

15 files changed

+371
-121
lines changed

15 files changed

+371
-121
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ var (
168168
utils.L1ConfirmationsFlag,
169169
utils.L1DeploymentBlockFlag,
170170
utils.CircuitCapacityCheckEnabledFlag,
171+
utils.CircuitCapacityCheckWorkersFlag,
171172
utils.RollupVerifyEnabledFlag,
172173
utils.ShadowforkPeersFlag,
173174
}

cmd/utils/flags.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"math/big"
2828
"os"
2929
"path/filepath"
30+
"runtime"
3031
godebug "runtime/debug"
3132
"strconv"
3233
"strings"
@@ -847,6 +848,12 @@ var (
847848
Usage: "Enable circuit capacity check during block validation",
848849
}
849850

851+
CircuitCapacityCheckWorkersFlag = cli.UintFlag{
852+
Name: "ccc.numworkers",
853+
Usage: "Set the number of workers that will be used for background CCC tasks",
854+
Value: uint(runtime.GOMAXPROCS(0)),
855+
}
856+
850857
// Rollup verify service settings
851858
RollupVerifyEnabledFlag = cli.BoolFlag{
852859
Name: "rollup.verify",
@@ -1572,6 +1579,10 @@ func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) {
15721579
func setCircuitCapacityCheck(ctx *cli.Context, cfg *ethconfig.Config) {
15731580
if ctx.GlobalIsSet(CircuitCapacityCheckEnabledFlag.Name) {
15741581
cfg.CheckCircuitCapacity = ctx.GlobalBool(CircuitCapacityCheckEnabledFlag.Name)
1582+
cfg.CCCMaxWorkers = runtime.GOMAXPROCS(0)
1583+
if ctx.GlobalIsSet(CircuitCapacityCheckWorkersFlag.Name) {
1584+
cfg.CCCMaxWorkers = int(ctx.GlobalUint(CircuitCapacityCheckWorkersFlag.Name))
1585+
}
15751586
}
15761587
}
15771588

core/block_validator.go

Lines changed: 15 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,33 @@
1717
package core
1818

1919
import (
20-
"errors"
2120
"fmt"
22-
"sync"
2321
"time"
2422

2523
"github.com/scroll-tech/go-ethereum/consensus"
2624
"github.com/scroll-tech/go-ethereum/core/rawdb"
2725
"github.com/scroll-tech/go-ethereum/core/state"
2826
"github.com/scroll-tech/go-ethereum/core/types"
29-
"github.com/scroll-tech/go-ethereum/ethdb"
3027
"github.com/scroll-tech/go-ethereum/log"
3128
"github.com/scroll-tech/go-ethereum/metrics"
3229
"github.com/scroll-tech/go-ethereum/params"
33-
"github.com/scroll-tech/go-ethereum/rollup/ccc"
3430
"github.com/scroll-tech/go-ethereum/trie"
3531
)
3632

3733
var (
38-
validateL1MessagesTimer = metrics.NewRegisteredTimer("validator/l1msg", nil)
39-
validateRowConsumptionTimer = metrics.NewRegisteredTimer("validator/rowconsumption", nil)
40-
validateTraceTimer = metrics.NewRegisteredTimer("validator/trace", nil)
41-
validateLockTimer = metrics.NewRegisteredTimer("validator/lock", nil)
42-
validateCccTimer = metrics.NewRegisteredTimer("validator/ccc", nil)
34+
validateL1MessagesTimer = metrics.NewRegisteredTimer("validator/l1msg", nil)
35+
asyncValidatorTimer = metrics.NewRegisteredTimer("validator/async", nil)
4336
)
4437

4538
// BlockValidator is responsible for validating block headers, uncles and
4639
// processed state.
4740
//
4841
// BlockValidator implements Validator.
4942
type BlockValidator struct {
50-
config *params.ChainConfig // Chain configuration options
51-
bc *BlockChain // Canonical block chain
52-
engine consensus.Engine // Consensus engine used for validating
53-
54-
// circuit capacity checker related fields
55-
checkCircuitCapacity bool // whether enable circuit capacity check
56-
cMu sync.Mutex // mutex for circuit capacity checker
57-
tracer tracerWrapper // scroll tracer wrapper
58-
circuitCapacityChecker *ccc.Checker // circuit capacity checker instance
43+
config *params.ChainConfig // Chain configuration options
44+
bc *BlockChain // Canonical block chain
45+
engine consensus.Engine // Consensus engine used for validating
46+
asyncValidator func(*types.Block) error // Asynchronously run a validation task
5947
}
6048

6149
// NewBlockValidator returns a new block validator which is safe for re-use
@@ -68,15 +56,10 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
6856
return validator
6957
}
7058

71-
type tracerWrapper interface {
72-
CreateTraceEnvAndGetBlockTrace(*params.ChainConfig, ChainContext, consensus.Engine, ethdb.Database, *state.StateDB, *types.Block, *types.Block, bool) (*types.BlockTrace, error)
73-
}
74-
75-
func (v *BlockValidator) SetupTracerAndCircuitCapacityChecker(tracer tracerWrapper) {
76-
v.checkCircuitCapacity = true
77-
v.tracer = tracer
78-
v.circuitCapacityChecker = ccc.NewChecker(true)
79-
log.Info("new CircuitCapacityChecker in BlockValidator", "ID", v.circuitCapacityChecker.ID)
59+
// WithAsyncValidator sets up an async validator to be triggered on each new block
60+
func (v *BlockValidator) WithAsyncValidator(asyncValidator func(*types.Block) error) Validator {
61+
v.asyncValidator = asyncValidator
62+
return v
8063
}
8164

8265
// ValidateBody validates the given block's uncles and verifies the block
@@ -114,25 +97,13 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
11497
if err := v.ValidateL1Messages(block); err != nil {
11598
return err
11699
}
117-
if v.checkCircuitCapacity {
118-
// if a block's RowConsumption has been stored, which means it has been processed before,
119-
// (e.g., in miner/worker.go or in insertChain),
120-
// we simply skip its calculation and validation
121-
if rawdb.ReadBlockRowConsumption(v.bc.db, block.Hash()) != nil {
122-
return nil
123-
}
124-
rowConsumption, err := v.validateCircuitRowConsumption(block)
125-
if err != nil {
100+
101+
if v.asyncValidator != nil {
102+
asyncStart := time.Now()
103+
if err := v.asyncValidator(block); err != nil {
126104
return err
127105
}
128-
log.Trace(
129-
"Validator write block row consumption",
130-
"id", v.circuitCapacityChecker.ID,
131-
"number", block.NumberU64(),
132-
"hash", block.Hash().String(),
133-
"rowConsumption", rowConsumption,
134-
)
135-
rawdb.WriteBlockRowConsumption(v.bc.db, block.Hash(), rowConsumption)
106+
asyncValidatorTimer.UpdateSince(asyncStart)
136107
}
137108
return nil
138109
}
@@ -286,61 +257,3 @@ func CalcGasLimit(parentGasLimit, desiredLimit uint64) uint64 {
286257
}
287258
return limit
288259
}
289-
290-
func (v *BlockValidator) createTraceEnvAndGetBlockTrace(block *types.Block) (*types.BlockTrace, error) {
291-
parent := v.bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
292-
if parent == nil {
293-
return nil, errors.New("validateCircuitRowConsumption: no parent block found")
294-
}
295-
296-
statedb, err := v.bc.StateAt(parent.Root())
297-
if err != nil {
298-
return nil, err
299-
}
300-
301-
return v.tracer.CreateTraceEnvAndGetBlockTrace(v.config, v.bc, v.engine, v.bc.db, statedb, parent, block, true)
302-
}
303-
304-
func (v *BlockValidator) validateCircuitRowConsumption(block *types.Block) (*types.RowConsumption, error) {
305-
defer func(t0 time.Time) {
306-
validateRowConsumptionTimer.Update(time.Since(t0))
307-
}(time.Now())
308-
309-
log.Trace(
310-
"Validator apply ccc for block",
311-
"id", v.circuitCapacityChecker.ID,
312-
"number", block.NumberU64(),
313-
"hash", block.Hash().String(),
314-
"len(txs)", block.Transactions().Len(),
315-
)
316-
317-
traceStartTime := time.Now()
318-
traces, err := v.createTraceEnvAndGetBlockTrace(block)
319-
if err != nil {
320-
return nil, err
321-
}
322-
validateTraceTimer.Update(time.Since(traceStartTime))
323-
324-
lockStartTime := time.Now()
325-
v.cMu.Lock()
326-
defer v.cMu.Unlock()
327-
validateLockTimer.Update(time.Since(lockStartTime))
328-
329-
cccStartTime := time.Now()
330-
v.circuitCapacityChecker.Reset()
331-
log.Trace("Validator reset ccc", "id", v.circuitCapacityChecker.ID)
332-
rc, err := v.circuitCapacityChecker.ApplyBlock(traces)
333-
validateCccTimer.Update(time.Since(cccStartTime))
334-
335-
log.Trace(
336-
"Validator apply ccc for block result",
337-
"id", v.circuitCapacityChecker.ID,
338-
"number", block.NumberU64(),
339-
"hash", block.Hash().String(),
340-
"len(txs)", block.Transactions().Len(),
341-
"rc", rc,
342-
"err", err,
343-
)
344-
345-
return rc, err
346-
}

core/types.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ type Validator interface {
3333
// gas used.
3434
ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error
3535

36-
// SetupTracerAndCircuitCapacityChecker sets up ScrollTracerWrapper and CircuitCapacityChecker for validator,
37-
// to get scroll-related traces and to validate the circuit row consumption
38-
SetupTracerAndCircuitCapacityChecker(tracer tracerWrapper)
36+
// WithAsyncValidator sets up an async validator to be triggered on each new block
37+
WithAsyncValidator(asyncValidator func(*types.Block) error) Validator
3938
}
4039

4140
// Prefetcher is an interface for pre-caching transaction signatures and state.

core/types/row_consumption.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@ package types
22

33
import "slices"
44

5-
type RowUsage struct {
6-
IsOk bool `json:"is_ok"`
7-
RowNumber uint64 `json:"row_number"`
8-
RowUsageDetails []SubCircuitRowUsage `json:"row_usage_details"`
9-
}
10-
115
//go:generate gencodec -type SubCircuitRowUsage -out gen_row_consumption_json.go
126
type SubCircuitRowUsage struct {
137
Name string `json:"name" gencodec:"required"`
148
RowNumber uint64 `json:"row_number" gencodec:"required"`
159
}
1610

1711
// RowConsumptionLimit is the max number of row we support per subcircuit
18-
const RowConsumptionLimit = 1_000_000
12+
// the actual limit is 1M but for safety we go with 950k
13+
const RowConsumptionLimit = 950_000
1914

2015
type RowConsumption []SubCircuitRowUsage
2116

eth/backend.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ import (
5555
"github.com/scroll-tech/go-ethereum/p2p/enode"
5656
"github.com/scroll-tech/go-ethereum/params"
5757
"github.com/scroll-tech/go-ethereum/rlp"
58+
"github.com/scroll-tech/go-ethereum/rollup/ccc"
5859
"github.com/scroll-tech/go-ethereum/rollup/rollup_sync_service"
5960
"github.com/scroll-tech/go-ethereum/rollup/sync_service"
60-
"github.com/scroll-tech/go-ethereum/rollup/tracing"
6161
"github.com/scroll-tech/go-ethereum/rpc"
6262
)
6363

@@ -73,6 +73,7 @@ type Ethereum struct {
7373
txPool *core.TxPool
7474
syncService *sync_service.SyncService
7575
rollupSyncService *rollup_sync_service.RollupSyncService
76+
asyncChecker *ccc.AsyncChecker
7677
blockchain *core.BlockChain
7778
handler *handler
7879
ethDialCandidates enode.Iterator
@@ -199,8 +200,11 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
199200
return nil, err
200201
}
201202
if config.CheckCircuitCapacity {
202-
tracer := tracing.NewTracerWrapper()
203-
eth.blockchain.Validator().SetupTracerAndCircuitCapacityChecker(tracer)
203+
eth.asyncChecker = ccc.NewAsyncChecker(eth.blockchain, config.CCCMaxWorkers, true)
204+
eth.asyncChecker.WithOnFailingBlock(func(b *types.Block, err error) {
205+
log.Warn("block failed CCC check, it will be reorged by the sequencer", "hash", b.Hash(), "err", err)
206+
})
207+
eth.blockchain.Validator().WithAsyncValidator(eth.asyncChecker.Check)
204208
}
205209

206210
// Rewind the chain in case of an incompatible config upgrade.
@@ -594,6 +598,9 @@ func (s *Ethereum) Stop() error {
594598
s.rollupSyncService.Stop()
595599
}
596600
s.miner.Close()
601+
if s.config.CheckCircuitCapacity {
602+
s.asyncChecker.Wait()
603+
}
597604
s.blockchain.Stop()
598605
s.engine.Close()
599606
rawdb.PopUncleanShutdownMarker(s.chainDb)

eth/ethconfig/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ type Config struct {
208208

209209
// Check circuit capacity in block validator
210210
CheckCircuitCapacity bool
211+
CCCMaxWorkers int
211212

212213
// Enable verification of batch consistency between L1 and L2 in rollup
213214
EnableRollupVerify bool

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ require (
5353
github.com/scroll-tech/da-codec v0.1.1-0.20240822151711-9e32313056ac
5454
github.com/scroll-tech/zktrie v0.8.4
5555
github.com/shirou/gopsutil v3.21.11+incompatible
56+
github.com/sourcegraph/conc v0.3.0
5657
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
5758
github.com/stretchr/testify v1.9.0
5859
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
@@ -99,6 +100,8 @@ require (
99100
github.com/tklauser/go-sysconf v0.3.12 // indirect
100101
github.com/tklauser/numcpus v0.6.1 // indirect
101102
github.com/yusufpapurcu/wmi v1.2.3 // indirect
103+
go.uber.org/atomic v1.7.0 // indirect
104+
go.uber.org/multierr v1.9.0 // indirect
102105
golang.org/x/net v0.16.0 // indirect
103106
golang.org/x/term v0.15.0 // indirect
104107
google.golang.org/protobuf v1.23.0 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
405405
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
406406
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
407407
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
408+
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
409+
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
408410
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
409411
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
410412
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
@@ -450,7 +452,11 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
450452
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
451453
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
452454
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
455+
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
456+
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
453457
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
458+
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
459+
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
454460
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
455461
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
456462
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

params/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
const (
2525
VersionMajor = 5 // Major version component of the current release
2626
VersionMinor = 6 // Minor version component of the current release
27-
VersionPatch = 3 // Patch version component of the current release
27+
VersionPatch = 4 // Patch version component of the current release
2828
VersionMeta = "mainnet" // Version metadata to append to the version string
2929
)
3030

0 commit comments

Comments
 (0)