Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(permissionless batches): block production without signature #1087

Draft
wants to merge 5 commits into
base: jt/permissionless-batches-recovery
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ var (
utils.DARecoveryInitialBatchFlag,
utils.DARecoverySignBlocksFlag,
utils.DARecoveryL2EndBlockFlag,
utils.DARecoveryProduceBlocksFlag,
}, utils.NetworkFlags, utils.DatabaseFlags)

rpcFlags = []cli.Flag{
Expand Down
7 changes: 7 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,10 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
Name: "da.recovery.l2endblock",
Usage: "End L2 block to recover to",
}
DARecoveryProduceBlocksFlag = &cli.BoolFlag{
Name: "da.recovery.produceblocks",
Usage: "Produce unsigned blocks after L1 recovery for permissionless batch submission",
}
)

var (
Expand Down Expand Up @@ -1851,6 +1855,9 @@ func setDA(ctx *cli.Context, cfg *ethconfig.Config) {
if ctx.IsSet(DARecoveryL2EndBlockFlag.Name) {
cfg.DA.L2EndBlock = ctx.Uint64(DARecoveryL2EndBlockFlag.Name)
}
if ctx.IsSet(DARecoveryProduceBlocksFlag.Name) {
cfg.DA.ProduceBlocks = ctx.Bool(DARecoveryProduceBlocksFlag.Name)
}
}
}

Expand Down
28 changes: 18 additions & 10 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,18 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
// simply let them run simultaneously. If messages are missing in DA syncing, it will be handled by the syncing pipeline
// by waiting and retrying.
if config.EnableDASyncing {
// Enable CCC if flag is set so that row consumption can be generated.
config.DA.CCCEnable = config.CheckCircuitCapacity
config.DA.CCCNumWorkers = config.CCCMaxWorkers
eth.syncingPipeline, err = da_syncer.NewSyncingPipeline(context.Background(), eth.blockchain, chainConfig, eth.chainDb, l1Client, stack.Config().L1DeploymentBlock, config.DA)
if err != nil {
return nil, fmt.Errorf("cannot initialize da syncer: %w", err)
// Do not start syncing pipeline if we are producing blocks.
if !config.DA.ProduceBlocks {
// Enable CCC if flag is set so that row consumption can be generated.
config.DA.CCCEnable = config.CheckCircuitCapacity
config.DA.CCCNumWorkers = config.CCCMaxWorkers
eth.syncingPipeline, err = da_syncer.NewSyncingPipeline(context.Background(), eth.blockchain, chainConfig, eth.chainDb, l1Client, stack.Config().L1DeploymentBlock, config.DA)
if err != nil {
return nil, fmt.Errorf("cannot initialize da syncer: %w", err)
}

eth.syncingPipeline.Start()
}
eth.syncingPipeline.Start()
}

// initialize and start L1 message sync service
Expand Down Expand Up @@ -294,7 +298,8 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
return nil, err
}

eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock, config.EnableDASyncing)
config.Miner.SigningDisabled = config.DA.ProduceBlocks
eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock, config.EnableDASyncing && !config.DA.ProduceBlocks)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))

eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
Expand Down Expand Up @@ -562,7 +567,10 @@ func (s *Ethereum) Protocols() []p2p.Protocol {
// Start implements node.Lifecycle, starting all internal goroutines needed by the
// Ethereum protocol implementation.
func (s *Ethereum) Start() error {
eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
// handler is not enabled when DA syncing enabled
if !s.config.EnableDASyncing {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why disable when DA syncing

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a nil pointer downstream when mining blocks without the networking layer being initialized

eth.StartENRUpdater(s.blockchain, s.p2pServer.LocalNode())
}

// Start the bloom bits servicing goroutines
s.startBloomHandlers(params.BloomBitsBlocks)
Expand Down Expand Up @@ -605,7 +613,7 @@ func (s *Ethereum) Stop() error {
if s.config.EnableRollupVerify {
s.rollupSyncService.Stop()
}
if s.config.EnableDASyncing {
if s.config.EnableDASyncing && s.syncingPipeline != nil {
s.syncingPipeline.Stop()
}
s.miner.Close()
Expand Down
2 changes: 2 additions & 0 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type Config struct {
StoreSkippedTxTraces bool // Whether store the wrapped traces when storing a skipped tx
MaxAccountsNum int // Maximum number of accounts that miner will fetch the pending transactions of when building a new block
CCCMaxWorkers int // Maximum number of workers to use for async CCC tasks

SigningDisabled bool // Whether to disable signing blocks with Clique
}

// DefaultConfig contains default settings for miner.
Expand Down
63 changes: 38 additions & 25 deletions miner/scroll_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,19 @@ func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, r
header.Coinbase = w.coinbase
}

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

var nextL1MsgIndex uint64
if dbVal := rawdb.ReadFirstQueueIndexNotInL2Block(w.eth.ChainDb(), header.ParentHash); dbVal != nil {
Expand Down Expand Up @@ -767,28 +775,33 @@ func (w *worker) commit() (common.Hash, error) {
return common.Hash{}, err
}

sealHash := w.engine.SealHash(block.Header())
log.Info("Committing new mining work", "number", block.Number(), "sealhash", sealHash,
"txs", w.current.txs.Len(),
"gas", block.GasUsed(), "fees", totalFees(block, w.current.receipts))

resultCh, stopCh := make(chan *types.Block), make(chan struct{})
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
return common.Hash{}, err
}
// Clique.Seal() will only wait for a second before giving up on us. So make sure there is nothing computational heavy
// or a call that blocks between the call to Seal and the line below. Seal might introduce some delay, so we keep track of
// that artificially added delay and subtract it from overall runtime of commit().
sealStart := time.Now()
block = <-resultCh
sealDelay = time.Since(sealStart)
if block == nil {
return common.Hash{}, errors.New("missed seal response from consensus engine")
}
var sealHash common.Hash
if w.config.SigningDisabled {
sealHash = block.Hash()
} else {
sealHash = w.engine.SealHash(block.Header())
log.Info("Committing new mining work", "number", block.Number(), "sealhash", sealHash,
"txs", w.current.txs.Len(),
"gas", block.GasUsed(), "fees", totalFees(block, w.current.receipts))

resultCh, stopCh := make(chan *types.Block), make(chan struct{})
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
return common.Hash{}, err
}
// Clique.Seal() will only wait for a second before giving up on us. So make sure there is nothing computational heavy
// or a call that blocks between the call to Seal and the line below. Seal might introduce some delay, so we keep track of
// that artificially added delay and subtract it from overall runtime of commit().
sealStart := time.Now()
block = <-resultCh
sealDelay = time.Since(sealStart)
if block == nil {
return common.Hash{}, errors.New("missed seal response from consensus engine")
}

// verify the generated block with local consensus engine to make sure everything is as expected
if err = w.engine.VerifyHeader(w.chain, block.Header()); err != nil {
return common.Hash{}, retryableCommitError{inner: err}
// verify the generated block with local consensus engine to make sure everything is as expected
if err = w.engine.VerifyHeader(w.chain, block.Header()); err != nil {
return common.Hash{}, retryableCommitError{inner: err}
}
}

blockHash := block.Hash()
Expand Down
9 changes: 9 additions & 0 deletions rollup/da_syncer/syncing_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Config struct {
InitialBatch uint64 // Batch number from which to start syncing and overriding blocks
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
L2EndBlock uint64 // L2 block number to sync until
ProduceBlocks bool
}

// SyncingPipeline is a derivation pipeline for syncing data from L1 and DA and transform it into
Expand Down Expand Up @@ -87,6 +88,14 @@ func NewSyncingPipeline(ctx context.Context, blockchain *core.BlockChain, genesi

var initialL1Block uint64
if config.RecoveryMode {
// sanity check the config
if config.InitialL1Block == 0 {
return nil, fmt.Errorf("sync from DA: recovery mode requires initial L1 block to be set")
}
if config.InitialBatch == 0 {
return nil, fmt.Errorf("sync from DA: recovery mode requires initial batch to be set")
}

initialL1Block = config.InitialL1Block
if initialL1Block == 0 {
return nil, errors.New("sync from DA: initial L1 block must be set in recovery mode")
Expand Down
Loading