Skip to content

Commit 3d3032c

Browse files
jonastheisomerfirmakThegaram
authored
feat(permissionless batches): block production without signature (#1117)
* port changes from #1013 * port changes from #1068 * go.mod tidy * fix compile error * fix goimports * fix log * address review comments * upgrade golang.org/x/net to 0.23.0 * port changes from #1018 * fix tests and linter errors * address review comments * refactor rollup sync service / verifier to use CalldataBlobSource to retrieve data from L1 * add configuration and initialize blob clients * fix unit tests * remove unused code * address review comments * address more review comments * implement first version of new da-codec and to handle multiple batches submitted in one transaction * add CommitBatchDAV7 and handle multiple commit events submitted in a single transactions * fix bug due to previous batch being empty when processing the first batch within a set of batches * Allow using MPT * update to latest da-codec * add field to CommittedBatchMeta to store LastL1MessageQueueHash for CodecV7 batches * adjust rollup verifier to support CodecV7 batches * address review comments * fix issues after merge * go mod tidy * fix unit tests * update da-codec * add test TestValidateBatchCodecV7 * go mod tidy * do not log error on shutdown * add sanity check for version to deserialization of committedBatchMetaV7 * port changes from #1073 * chore: auto version bump [bot] * address review comments * add more logs * disable ENRUpdater if DA sync mode is enabled * exit pipeline if context is cancelled * correctly handle override by setting the head of the chain to the parent's height so that created blocks will always become part of canonical chain * fix error with genesis event being nil * rebase #1087 to new base branch * chore: auto version bump [bot] --------- Co-authored-by: Ömer Faruk Irmak <[email protected]> Co-authored-by: Thegaram <[email protected]> Co-authored-by: jonastheis <[email protected]> Co-authored-by: Péter Garamvölgyi <[email protected]>
1 parent 65a0d4e commit 3d3032c

File tree

7 files changed

+62
-32
lines changed

7 files changed

+62
-32
lines changed

cmd/geth/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ var (
183183
utils.DARecoveryInitialBatchFlag,
184184
utils.DARecoverySignBlocksFlag,
185185
utils.DARecoveryL2EndBlockFlag,
186+
utils.DARecoveryProduceBlocksFlag,
186187
}
187188

188189
rpcFlags = []cli.Flag{

cmd/utils/flags.go

+7
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,10 @@ var (
926926
Name: "da.recovery.l2endblock",
927927
Usage: "End L2 block to recover to",
928928
}
929+
DARecoveryProduceBlocksFlag = cli.BoolFlag{
930+
Name: "da.recovery.produceblocks",
931+
Usage: "Produce unsigned blocks after L1 recovery for permissionless batch submission",
932+
}
929933
)
930934

931935
// MakeDataDir retrieves the currently requested data directory, terminating
@@ -1693,6 +1697,9 @@ func setDA(ctx *cli.Context, cfg *ethconfig.Config) {
16931697
if ctx.IsSet(DARecoveryL2EndBlockFlag.Name) {
16941698
cfg.DA.L2EndBlock = ctx.Uint64(DARecoveryL2EndBlockFlag.Name)
16951699
}
1700+
if ctx.IsSet(DARecoveryProduceBlocksFlag.Name) {
1701+
cfg.DA.ProduceBlocks = ctx.Bool(DARecoveryProduceBlocksFlag.Name)
1702+
}
16961703
}
16971704

16981705
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {

eth/backend.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,15 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
229229
// simply let them run simultaneously. If messages are missing in DA syncing, it will be handled by the syncing pipeline
230230
// by waiting and retrying.
231231
if config.EnableDASyncing {
232-
eth.syncingPipeline, err = da_syncer.NewSyncingPipeline(context.Background(), eth.blockchain, chainConfig, eth.chainDb, l1Client, stack.Config().L1DeploymentBlock, config.DA)
233-
if err != nil {
234-
return nil, fmt.Errorf("cannot initialize da syncer: %w", err)
232+
// Do not start syncing pipeline if we are producing blocks for permissionless batches.
233+
if !config.DA.ProduceBlocks {
234+
eth.syncingPipeline, err = da_syncer.NewSyncingPipeline(context.Background(), eth.blockchain, chainConfig, eth.chainDb, l1Client, stack.Config().L1DeploymentBlock, config.DA)
235+
if err != nil {
236+
return nil, fmt.Errorf("cannot initialize da syncer: %w", err)
237+
}
238+
239+
eth.syncingPipeline.Start()
235240
}
236-
eth.syncingPipeline.Start()
237241
}
238242

239243
// initialize and start L1 message sync service
@@ -273,7 +277,8 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
273277
return nil, err
274278
}
275279

276-
eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock, config.EnableDASyncing)
280+
config.Miner.SigningDisabled = config.DA.ProduceBlocks
281+
eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock, config.EnableDASyncing && !config.DA.ProduceBlocks)
277282
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
278283

279284
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
@@ -632,7 +637,7 @@ func (s *Ethereum) Stop() error {
632637
if s.config.EnableRollupVerify {
633638
s.rollupSyncService.Stop()
634639
}
635-
if s.config.EnableDASyncing {
640+
if s.config.EnableDASyncing && s.syncingPipeline != nil {
636641
s.syncingPipeline.Stop()
637642
}
638643
s.miner.Close()

miner/miner.go

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ type Config struct {
6060
StoreSkippedTxTraces bool // Whether store the wrapped traces when storing a skipped tx
6161
MaxAccountsNum int // Maximum number of accounts that miner will fetch the pending transactions of when building a new block
6262
CCCMaxWorkers int // Maximum number of workers to use for async CCC tasks
63+
64+
SigningDisabled bool // Whether to disable signing blocks with consensus enginek
6365
}
6466

6567
// Miner creates blocks and searches for proof-of-work values.

miner/scroll_worker.go

+38-25
Original file line numberDiff line numberDiff line change
@@ -502,11 +502,19 @@ func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, r
502502
header.Coinbase = w.coinbase
503503
}
504504

505-
prepareStart := time.Now()
506-
if err := w.engine.Prepare(w.chain, header); err != nil {
507-
return fmt.Errorf("failed to prepare header for mining: %w", err)
505+
if w.config.SigningDisabled {
506+
// Need to make sure to set difficulty so that a new canonical chain is detected in Blockchain
507+
header.Difficulty = new(big.Int).SetUint64(1)
508+
header.MixDigest = common.Hash{}
509+
header.Coinbase = common.Address{}
510+
header.Nonce = types.BlockNonce{}
511+
} else {
512+
prepareStart := time.Now()
513+
if err := w.engine.Prepare(w.chain, header); err != nil {
514+
return fmt.Errorf("failed to prepare header for mining: %w", err)
515+
}
516+
prepareTimer.UpdateSince(prepareStart)
508517
}
509-
prepareTimer.UpdateSince(prepareStart)
510518

511519
var nextL1MsgIndex uint64
512520
if dbVal := rawdb.ReadFirstQueueIndexNotInL2Block(w.eth.ChainDb(), header.ParentHash); dbVal != nil {
@@ -853,28 +861,33 @@ func (w *worker) commit() (common.Hash, error) {
853861
return common.Hash{}, err
854862
}
855863

856-
sealHash := w.engine.SealHash(block.Header())
857-
log.Info("Committing new mining work", "number", block.Number(), "sealhash", sealHash,
858-
"txs", w.current.txs.Len(),
859-
"gas", block.GasUsed(), "fees", totalFees(block, w.current.receipts))
860-
861-
resultCh, stopCh := make(chan *types.Block), make(chan struct{})
862-
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
863-
return common.Hash{}, err
864-
}
865-
// Clique.Seal() will only wait for a second before giving up on us. So make sure there is nothing computational heavy
866-
// or a call that blocks between the call to Seal and the line below. Seal might introduce some delay, so we keep track of
867-
// that artificially added delay and subtract it from overall runtime of commit().
868-
sealStart := time.Now()
869-
block = <-resultCh
870-
sealDelay = time.Since(sealStart)
871-
if block == nil {
872-
return common.Hash{}, errors.New("missed seal response from consensus engine")
873-
}
864+
var sealHash common.Hash
865+
if w.config.SigningDisabled {
866+
sealHash = block.Hash()
867+
} else {
868+
sealHash = w.engine.SealHash(block.Header())
869+
log.Info("Committing new mining work", "number", block.Number(), "sealhash", sealHash,
870+
"txs", w.current.txs.Len(),
871+
"gas", block.GasUsed(), "fees", totalFees(block, w.current.receipts))
872+
873+
resultCh, stopCh := make(chan *types.Block), make(chan struct{})
874+
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
875+
return common.Hash{}, err
876+
}
877+
// Clique.Seal() will only wait for a second before giving up on us. So make sure there is nothing computational heavy
878+
// or a call that blocks between the call to Seal and the line below. Seal might introduce some delay, so we keep track of
879+
// that artificially added delay and subtract it from overall runtime of commit().
880+
sealStart := time.Now()
881+
block = <-resultCh
882+
sealDelay = time.Since(sealStart)
883+
if block == nil {
884+
return common.Hash{}, errors.New("missed seal response from consensus engine")
885+
}
874886

875-
// verify the generated block with local consensus engine to make sure everything is as expected
876-
if err = w.engine.VerifyHeader(w.chain, block.Header(), true); err != nil {
877-
return common.Hash{}, retryableCommitError{inner: err}
887+
// verify the generated block with local consensus engine to make sure everything is as expected
888+
if err = w.engine.VerifyHeader(w.chain, block.Header(), true); err != nil {
889+
return common.Hash{}, retryableCommitError{inner: err}
890+
}
878891
}
879892

880893
blockHash := block.Hash()

params/version.go

+1-1
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 = 8 // Minor version component of the current release
27-
VersionPatch = 11 // Patch version component of the current release
27+
VersionPatch = 12 // Patch version component of the current release
2828
VersionMeta = "mainnet" // Version metadata to append to the version string
2929
)
3030

rollup/da_syncer/syncing_pipeline.go

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type Config struct {
2929
InitialBatch uint64 // Batch number from which to start syncing and overriding blocks
3030
SignBlocks bool // Whether to sign the blocks after reading them from the pipeline (requires correct Clique signer key) and history of blocks with Clique signatures
3131
L2EndBlock uint64 // L2 block number to sync until
32+
33+
ProduceBlocks bool // Whether to produce blocks in DA recovery mode. The pipeline will be disabled when starting the node with this flag.
3234
}
3335

3436
// SyncingPipeline is a derivation pipeline for syncing data from L1 and DA and transform it into

0 commit comments

Comments
 (0)