mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 05:36:46 +00:00
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 <omerfirmak@gmail.com> Co-authored-by: Thegaram <Thegaram@users.noreply.github.com> Co-authored-by: jonastheis <jonastheis@users.noreply.github.com> Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
This commit is contained in:
parent
65a0d4e87d
commit
3d3032c0e1
7 changed files with 61 additions and 31 deletions
|
|
@ -183,6 +183,7 @@ var (
|
||||||
utils.DARecoveryInitialBatchFlag,
|
utils.DARecoveryInitialBatchFlag,
|
||||||
utils.DARecoverySignBlocksFlag,
|
utils.DARecoverySignBlocksFlag,
|
||||||
utils.DARecoveryL2EndBlockFlag,
|
utils.DARecoveryL2EndBlockFlag,
|
||||||
|
utils.DARecoveryProduceBlocksFlag,
|
||||||
}
|
}
|
||||||
|
|
||||||
rpcFlags = []cli.Flag{
|
rpcFlags = []cli.Flag{
|
||||||
|
|
|
||||||
|
|
@ -926,6 +926,10 @@ var (
|
||||||
Name: "da.recovery.l2endblock",
|
Name: "da.recovery.l2endblock",
|
||||||
Usage: "End L2 block to recover to",
|
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",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// MakeDataDir retrieves the currently requested data directory, terminating
|
// MakeDataDir retrieves the currently requested data directory, terminating
|
||||||
|
|
@ -1693,6 +1697,9 @@ func setDA(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
if ctx.IsSet(DARecoveryL2EndBlockFlag.Name) {
|
if ctx.IsSet(DARecoveryL2EndBlockFlag.Name) {
|
||||||
cfg.DA.L2EndBlock = ctx.Uint64(DARecoveryL2EndBlockFlag.Name)
|
cfg.DA.L2EndBlock = ctx.Uint64(DARecoveryL2EndBlockFlag.Name)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(DARecoveryProduceBlocksFlag.Name) {
|
||||||
|
cfg.DA.ProduceBlocks = ctx.Bool(DARecoveryProduceBlocksFlag.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {
|
func setMaxBlockRange(ctx *cli.Context, cfg *ethconfig.Config) {
|
||||||
|
|
|
||||||
|
|
@ -229,11 +229,15 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
|
||||||
// simply let them run simultaneously. If messages are missing in DA syncing, it will be handled by the syncing pipeline
|
// simply let them run simultaneously. If messages are missing in DA syncing, it will be handled by the syncing pipeline
|
||||||
// by waiting and retrying.
|
// by waiting and retrying.
|
||||||
if config.EnableDASyncing {
|
if config.EnableDASyncing {
|
||||||
eth.syncingPipeline, err = da_syncer.NewSyncingPipeline(context.Background(), eth.blockchain, chainConfig, eth.chainDb, l1Client, stack.Config().L1DeploymentBlock, config.DA)
|
// Do not start syncing pipeline if we are producing blocks for permissionless batches.
|
||||||
if err != nil {
|
if !config.DA.ProduceBlocks {
|
||||||
return nil, fmt.Errorf("cannot initialize da syncer: %w", err)
|
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
|
// initialize and start L1 message sync service
|
||||||
|
|
@ -273,7 +277,8 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client l1.Client) (*Ether
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
eth.miner = miner.New(eth, &config.Miner, chainConfig, 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.miner.SetExtra(makeExtraData(config.Miner.ExtraData))
|
||||||
|
|
||||||
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
|
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
|
||||||
|
|
@ -632,7 +637,7 @@ func (s *Ethereum) Stop() error {
|
||||||
if s.config.EnableRollupVerify {
|
if s.config.EnableRollupVerify {
|
||||||
s.rollupSyncService.Stop()
|
s.rollupSyncService.Stop()
|
||||||
}
|
}
|
||||||
if s.config.EnableDASyncing {
|
if s.config.EnableDASyncing && s.syncingPipeline != nil {
|
||||||
s.syncingPipeline.Stop()
|
s.syncingPipeline.Stop()
|
||||||
}
|
}
|
||||||
s.miner.Close()
|
s.miner.Close()
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ type Config struct {
|
||||||
StoreSkippedTxTraces bool // Whether store the wrapped traces when storing a skipped tx
|
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
|
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
|
CCCMaxWorkers int // Maximum number of workers to use for async CCC tasks
|
||||||
|
|
||||||
|
SigningDisabled bool // Whether to disable signing blocks with consensus enginek
|
||||||
}
|
}
|
||||||
|
|
||||||
// Miner creates blocks and searches for proof-of-work values.
|
// Miner creates blocks and searches for proof-of-work values.
|
||||||
|
|
|
||||||
|
|
@ -502,11 +502,19 @@ func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, r
|
||||||
header.Coinbase = w.coinbase
|
header.Coinbase = w.coinbase
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareStart := time.Now()
|
if w.config.SigningDisabled {
|
||||||
if err := w.engine.Prepare(w.chain, header); err != nil {
|
// Need to make sure to set difficulty so that a new canonical chain is detected in Blockchain
|
||||||
return fmt.Errorf("failed to prepare header for mining: %w", err)
|
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
|
var nextL1MsgIndex uint64
|
||||||
if dbVal := rawdb.ReadFirstQueueIndexNotInL2Block(w.eth.ChainDb(), header.ParentHash); dbVal != nil {
|
if dbVal := rawdb.ReadFirstQueueIndexNotInL2Block(w.eth.ChainDb(), header.ParentHash); dbVal != nil {
|
||||||
|
|
@ -853,28 +861,33 @@ func (w *worker) commit() (common.Hash, error) {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sealHash := w.engine.SealHash(block.Header())
|
var sealHash common.Hash
|
||||||
log.Info("Committing new mining work", "number", block.Number(), "sealhash", sealHash,
|
if w.config.SigningDisabled {
|
||||||
"txs", w.current.txs.Len(),
|
sealHash = block.Hash()
|
||||||
"gas", block.GasUsed(), "fees", totalFees(block, w.current.receipts))
|
} 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{})
|
resultCh, stopCh := make(chan *types.Block), make(chan struct{})
|
||||||
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
|
if err := w.engine.Seal(w.chain, block, resultCh, stopCh); err != nil {
|
||||||
return common.Hash{}, err
|
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
|
// 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
|
// 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().
|
// that artificially added delay and subtract it from overall runtime of commit().
|
||||||
sealStart := time.Now()
|
sealStart := time.Now()
|
||||||
block = <-resultCh
|
block = <-resultCh
|
||||||
sealDelay = time.Since(sealStart)
|
sealDelay = time.Since(sealStart)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
return common.Hash{}, errors.New("missed seal response from consensus engine")
|
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
|
// verify the generated block with local consensus engine to make sure everything is as expected
|
||||||
if err = w.engine.VerifyHeader(w.chain, block.Header(), true); err != nil {
|
if err = w.engine.VerifyHeader(w.chain, block.Header(), true); err != nil {
|
||||||
return common.Hash{}, retryableCommitError{inner: err}
|
return common.Hash{}, retryableCommitError{inner: err}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockHash := block.Hash()
|
blockHash := block.Hash()
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 8 // Minor version component of the current release
|
VersionMinor = 8 // Minor version component of the current release
|
||||||
VersionPatch = 11 // Patch version component of the current release
|
VersionPatch = 12 // Patch version component of the current release
|
||||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ type Config struct {
|
||||||
InitialBatch uint64 // Batch number from which to start syncing and overriding blocks
|
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
|
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
|
L2EndBlock uint64 // L2 block number to sync until
|
||||||
|
|
||||||
|
ProduceBlocks bool // Whether to produce blocks in DA recovery mode. The pipeline will be disabled when starting the node with this flag.
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncingPipeline is a derivation pipeline for syncing data from L1 and DA and transform it into
|
// SyncingPipeline is a derivation pipeline for syncing data from L1 and DA and transform it into
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue