Skip to content

Commit a2cb3d1

Browse files
committed
port changes from #1073
1 parent d4cc897 commit a2cb3d1

File tree

7 files changed

+191
-50
lines changed

7 files changed

+191
-50
lines changed

cmd/geth/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ var (
177177
utils.DABlockNativeAPIEndpointFlag,
178178
utils.DABlobScanAPIEndpointFlag,
179179
utils.DABeaconNodeAPIEndpointFlag,
180+
utils.DARecoveryModeFlag,
181+
utils.DARecoveryInitialL1BlockFlag,
182+
utils.DARecoveryInitialBatchFlag,
183+
utils.DARecoverySignBlocksFlag,
184+
utils.DARecoveryL2EndBlockFlag,
180185
}
181186

182187
rpcFlags = []cli.Flag{

cmd/utils/flags.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -886,22 +886,42 @@ var (
886886
}
887887

888888
// DA syncing settings
889-
DASyncEnabledFlag = &cli.BoolFlag{
889+
DASyncEnabledFlag = cli.BoolFlag{
890890
Name: "da.sync",
891891
Usage: "Enable node syncing from DA",
892892
}
893-
DABlobScanAPIEndpointFlag = &cli.StringFlag{
893+
DABlobScanAPIEndpointFlag = cli.StringFlag{
894894
Name: "da.blob.blobscan",
895895
Usage: "BlobScan blob API endpoint",
896896
}
897-
DABlockNativeAPIEndpointFlag = &cli.StringFlag{
897+
DABlockNativeAPIEndpointFlag = cli.StringFlag{
898898
Name: "da.blob.blocknative",
899899
Usage: "BlockNative blob API endpoint",
900900
}
901-
DABeaconNodeAPIEndpointFlag = &cli.StringFlag{
901+
DABeaconNodeAPIEndpointFlag = cli.StringFlag{
902902
Name: "da.blob.beaconnode",
903903
Usage: "Beacon node API endpoint",
904904
}
905+
DARecoveryModeFlag = cli.BoolFlag{
906+
Name: "da.recovery",
907+
Usage: "Enable recovery mode for DA syncing",
908+
}
909+
DARecoveryInitialL1BlockFlag = cli.Uint64Flag{
910+
Name: "da.recovery.initiall1block",
911+
Usage: "Initial L1 block to start recovery from",
912+
}
913+
DARecoveryInitialBatchFlag = cli.Uint64Flag{
914+
Name: "da.recovery.initialbatch",
915+
Usage: "Initial batch to start recovery from",
916+
}
917+
DARecoverySignBlocksFlag = cli.BoolFlag{
918+
Name: "da.recovery.signblocks",
919+
Usage: "Sign blocks during recovery (requires correct Clique signer key and history of blocks with Clique signatures)",
920+
}
921+
DARecoveryL2EndBlockFlag = cli.Uint64Flag{
922+
Name: "da.recovery.l2endblock",
923+
Usage: "End L2 block to recover to",
924+
}
905925
)
906926

907927
// MakeDataDir retrieves the currently requested data directory, terminating
@@ -1651,6 +1671,21 @@ func setDA(ctx *cli.Context, cfg *ethconfig.Config) {
16511671
if ctx.IsSet(DABeaconNodeAPIEndpointFlag.Name) {
16521672
cfg.DA.BeaconNodeAPIEndpoint = ctx.String(DABeaconNodeAPIEndpointFlag.Name)
16531673
}
1674+
if ctx.IsSet(DARecoveryModeFlag.Name) {
1675+
cfg.DA.RecoveryMode = ctx.Bool(DARecoveryModeFlag.Name)
1676+
}
1677+
if ctx.IsSet(DARecoveryInitialL1BlockFlag.Name) {
1678+
cfg.DA.InitialL1Block = ctx.Uint64(DARecoveryInitialL1BlockFlag.Name)
1679+
}
1680+
if ctx.IsSet(DARecoveryInitialBatchFlag.Name) {
1681+
cfg.DA.InitialBatch = ctx.Uint64(DARecoveryInitialBatchFlag.Name)
1682+
}
1683+
if ctx.IsSet(DARecoverySignBlocksFlag.Name) {
1684+
cfg.DA.SignBlocks = ctx.Bool(DARecoverySignBlocksFlag.Name)
1685+
}
1686+
if ctx.IsSet(DARecoveryL2EndBlockFlag.Name) {
1687+
cfg.DA.L2EndBlock = ctx.Uint64(DARecoveryL2EndBlockFlag.Name)
1688+
}
16541689
}
16551690

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

core/blockchain.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,15 +1806,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
18061806
return it.index, err
18071807
}
18081808

1809-
func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types.Header, txs types.Transactions) (WriteStatus, error) {
1809+
func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types.Header, txs types.Transactions, sign bool) (*types.Block, WriteStatus, error) {
18101810
if !bc.chainmu.TryLock() {
1811-
return NonStatTy, errInsertionInterrupted
1811+
return nil, NonStatTy, errInsertionInterrupted
18121812
}
18131813
defer bc.chainmu.Unlock()
18141814

18151815
statedb, err := state.New(parentBlock.Root(), bc.stateCache, bc.snaps)
18161816
if err != nil {
1817-
return NonStatTy, err
1817+
return nil, NonStatTy, err
18181818
}
18191819

18201820
statedb.StartPrefetcher("l1sync", nil)
@@ -1825,18 +1825,51 @@ func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types
18251825
tempBlock := types.NewBlockWithHeader(header).WithBody(txs, nil)
18261826
receipts, logs, gasUsed, err := bc.processor.Process(tempBlock, statedb, bc.vmConfig)
18271827
if err != nil {
1828-
return NonStatTy, fmt.Errorf("error processing block: %w", err)
1828+
return nil, NonStatTy, fmt.Errorf("error processing block: %w", err)
18291829
}
18301830

18311831
// TODO: once we have the extra and difficulty we need to verify the signature of the block with Clique
18321832
// This should be done with https://github.com/scroll-tech/go-ethereum/pull/913.
18331833

1834-
// finalize and assemble block as fullBlock
1834+
if sign {
1835+
// remember the time as Clique will override it
1836+
originalTime := header.Time
1837+
1838+
err = bc.engine.Prepare(bc, header)
1839+
if err != nil {
1840+
return nil, NonStatTy, fmt.Errorf("error preparing block %d: %w", tempBlock.Number().Uint64(), err)
1841+
}
1842+
1843+
// we want to re-sign the block: set time to original value again.
1844+
header.Time = originalTime
1845+
}
1846+
1847+
// finalize and assemble block as fullBlock: replicates consensus.FinalizeAndAssemble()
18351848
header.GasUsed = gasUsed
18361849
header.Root = statedb.IntermediateRoot(bc.chainConfig.IsEIP158(header.Number))
18371850

18381851
fullBlock := types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil))
18391852

1853+
// Sign the block if requested
1854+
if sign {
1855+
resultCh, stopCh := make(chan *types.Block), make(chan struct{})
1856+
if err = bc.engine.Seal(bc, fullBlock, resultCh, stopCh); err != nil {
1857+
return nil, NonStatTy, fmt.Errorf("error sealing block %d: %w", fullBlock.Number().Uint64(), err)
1858+
}
1859+
// Clique.Seal() will only wait for a second before giving up on us. So make sure there is nothing computational heavy
1860+
// or a call that blocks between the call to Seal and the line below. Seal might introduce some delay, so we keep track of
1861+
// that artificially added delay and subtract it from overall runtime of commit().
1862+
fullBlock = <-resultCh
1863+
if fullBlock == nil {
1864+
return nil, NonStatTy, fmt.Errorf("sealing block failed %d: block is nil", header.Number.Uint64())
1865+
}
1866+
1867+
// verify the generated block with local consensus engine to make sure everything is as expected
1868+
if err = bc.engine.VerifyHeader(bc, fullBlock.Header(), true); err != nil {
1869+
return nil, NonStatTy, fmt.Errorf("error verifying signed block %d: %w", fullBlock.Number().Uint64(), err)
1870+
}
1871+
}
1872+
18401873
blockHash := fullBlock.Hash()
18411874
// manually replace the block hash in the receipts
18421875
for i, receipt := range receipts {
@@ -1853,7 +1886,18 @@ func (bc *BlockChain) BuildAndWriteBlock(parentBlock *types.Block, header *types
18531886
l.BlockHash = blockHash
18541887
}
18551888

1856-
return bc.writeBlockWithState(fullBlock, receipts, logs, statedb, false)
1889+
// Double check: even though we just built the block, make sure it is valid.
1890+
if err = bc.validator.ValidateBody(fullBlock); err != nil {
1891+
bc.reportBlock(fullBlock, receipts, err)
1892+
return nil, NonStatTy, fmt.Errorf("error validating block %d: %w", fullBlock.Number().Uint64(), err)
1893+
}
1894+
if err = bc.validator.ValidateState(fullBlock, statedb, receipts, gasUsed); err != nil {
1895+
bc.reportBlock(fullBlock, receipts, err)
1896+
return nil, NonStatTy, fmt.Errorf("error validating block %d: %w", fullBlock.Number().Uint64(), err)
1897+
}
1898+
1899+
writeStatus, err := bc.writeBlockWithState(fullBlock, receipts, logs, statedb, false)
1900+
return fullBlock, writeStatus, err
18571901
}
18581902

18591903
// insertSideChain is called when an import batch hits upon a pruned ancestor

rollup/da_syncer/da_queue.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,50 @@ import (
44
"context"
55
"errors"
66

7+
"github.com/scroll-tech/go-ethereum/log"
78
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
89
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/serrors"
910
)
1011

1112
// DAQueue is a pipeline stage that reads DA entries from a DataSource and provides them to the next stage.
1213
type DAQueue struct {
13-
l1height uint64
14+
l1height uint64
15+
initialBatch uint64
16+
1417
dataSourceFactory *DataSourceFactory
1518
dataSource DataSource
1619
da da.Entries
1720
}
1821

19-
func NewDAQueue(l1height uint64, dataSourceFactory *DataSourceFactory) *DAQueue {
22+
func NewDAQueue(l1height uint64, initialBatch uint64, dataSourceFactory *DataSourceFactory) *DAQueue {
2023
return &DAQueue{
2124
l1height: l1height,
25+
initialBatch: initialBatch,
2226
dataSourceFactory: dataSourceFactory,
2327
dataSource: nil,
2428
da: make(da.Entries, 0),
2529
}
2630
}
2731

2832
func (dq *DAQueue) NextDA(ctx context.Context) (da.Entry, error) {
29-
for len(dq.da) == 0 {
30-
select {
31-
case <-ctx.Done():
32-
return nil, ctx.Err()
33-
default:
33+
for {
34+
for len(dq.da) == 0 {
35+
err := dq.getNextData(ctx)
36+
if err != nil {
37+
return nil, err
38+
}
3439
}
3540

36-
err := dq.getNextData(ctx)
37-
if err != nil {
38-
return nil, err
41+
daEntry := dq.da[0]
42+
dq.da = dq.da[1:]
43+
44+
if daEntry.BatchIndex() < dq.initialBatch {
45+
log.Debug("Skipping DA entry due to initial batch requirement", "batchIndex", daEntry.BatchIndex(), "initialBatch", dq.initialBatch)
46+
continue
3947
}
48+
49+
return daEntry, nil
4050
}
41-
daEntry := dq.da[0]
42-
dq.da = dq.da[1:]
43-
return daEntry, nil
4451
}
4552

4653
func (dq *DAQueue) getNextData(ctx context.Context) error {

rollup/da_syncer/da_syncer.go

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/scroll-tech/go-ethereum/core"
77
"github.com/scroll-tech/go-ethereum/log"
88
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/da"
9+
"github.com/scroll-tech/go-ethereum/rollup/da_syncer/serrors"
910
)
1011

1112
var (
@@ -14,39 +15,60 @@ var (
1415
)
1516

1617
type DASyncer struct {
18+
l2EndBlock uint64
1719
blockchain *core.BlockChain
1820
}
1921

20-
func NewDASyncer(blockchain *core.BlockChain) *DASyncer {
22+
func NewDASyncer(blockchain *core.BlockChain, l2EndBlock uint64) *DASyncer {
2123
return &DASyncer{
24+
l2EndBlock: l2EndBlock,
2225
blockchain: blockchain,
2326
}
2427
}
2528

2629
// SyncOneBlock receives a PartialBlock, makes sure it's the next block in the chain, executes it and inserts it to the blockchain.
27-
func (s *DASyncer) SyncOneBlock(block *da.PartialBlock) error {
30+
func (s *DASyncer) SyncOneBlock(block *da.PartialBlock, override bool, sign bool) error {
2831
currentBlock := s.blockchain.CurrentBlock()
2932

3033
// we expect blocks to be consecutive. block.PartialHeader.Number == parentBlock.Number+1.
31-
if block.PartialHeader.Number <= currentBlock.Number().Uint64() {
34+
// if override is true, we allow blocks to be lower than the current block number and replace the blocks.
35+
if !override && block.PartialHeader.Number <= currentBlock.Number().Uint64() {
3236
log.Debug("block number is too low", "block number", block.PartialHeader.Number, "parent block number", currentBlock.Number().Uint64())
3337
return ErrBlockTooLow
3438
} else if block.PartialHeader.Number > currentBlock.Number().Uint64()+1 {
3539
log.Debug("block number is too high", "block number", block.PartialHeader.Number, "parent block number", currentBlock.Number().Uint64())
3640
return ErrBlockTooHigh
3741
}
3842

39-
parentBlock := s.blockchain.GetBlockByNumber(currentBlock.Number().Uint64())
43+
parentBlockNumber := currentBlock.Number().Uint64()
44+
if override {
45+
// TODO: does this work when we do a reorg and actually overwrite the existing chain?
46+
parentBlockNumber = block.PartialHeader.Number - 1
47+
}
48+
49+
parentBlock := s.blockchain.GetBlockByNumber(parentBlockNumber)
4050
if parentBlock == nil {
41-
return fmt.Errorf("parent block not found at height %d", currentBlock.Number().Uint64())
51+
return fmt.Errorf("failed getting parent block, number: %d", parentBlockNumber)
4252
}
4353

44-
if _, err := s.blockchain.BuildAndWriteBlock(parentBlock, block.PartialHeader.ToHeader(), block.Transactions); err != nil {
54+
_, _, err := s.blockchain.BuildAndWriteBlock(parentBlock, block.PartialHeader.ToHeader(), block.Transactions, sign)
55+
if err != nil {
4556
return fmt.Errorf("failed building and writing block, number: %d, error: %v", block.PartialHeader.Number, err)
4657
}
4758

48-
if s.blockchain.CurrentBlock().Number().Uint64()%1000 == 0 {
49-
log.Info("L1 sync progress", "blockchain height", s.blockchain.CurrentBlock().Number().Uint64(), "block hash", s.blockchain.CurrentBlock().Hash().Hex(), "root", s.blockchain.CurrentBlock().Root().Hex())
59+
currentBlock = s.blockchain.CurrentBlock()
60+
if override && block.PartialHeader.Number != currentBlock.Number().Uint64() && block.PartialHeader.Number%100 == 0 {
61+
newBlock := s.blockchain.GetHeaderByNumber(block.PartialHeader.Number)
62+
log.Info("L1 sync progress", "processed block ", newBlock.Number.Uint64(), "block hash", newBlock.Hash(), "root", newBlock.Root)
63+
log.Info("L1 sync progress", "blockchain height", currentBlock.Number().Uint64(), "block hash", currentBlock.Hash(), "root", currentBlock.Root())
64+
} else if currentBlock.Number().Uint64()%100 == 0 {
65+
log.Info("L1 sync progress", "blockchain height", currentBlock.Number().Uint64(), "block hash", currentBlock.Hash(), "root", currentBlock.Root())
66+
}
67+
68+
if s.l2EndBlock > 0 && s.l2EndBlock == block.PartialHeader.Number {
69+
newBlock := s.blockchain.GetHeaderByNumber(block.PartialHeader.Number)
70+
log.Warn("L1 sync reached L2EndBlock: you can terminate recovery mode now", "L2EndBlock", newBlock.Number.Uint64(), "block hash", newBlock.Hash(), "root", newBlock.Root)
71+
return serrors.Terminated
5072
}
5173

5274
return nil

rollup/da_syncer/serrors/errors.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const (
1212
var (
1313
TemporaryError = NewTemporaryError(nil)
1414
EOFError = NewEOFError(nil)
15+
Terminated = fmt.Errorf("terminated")
1516
)
1617

1718
type Type uint8

0 commit comments

Comments
 (0)