diff --git a/eth/api_backend.go b/eth/api_backend.go index 38846c2efaa4..96bd55f6db30 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) @@ -104,8 +105,36 @@ func (b *EthAPIBackend) GetDiff(block *big.Int) (diffdb.Diff, error) { } func (b *EthAPIBackend) SetHead(number uint64) { - b.eth.protocolManager.downloader.Cancel() + if number == 0 { + log.Info("Cannot reset to genesis") + return + } + if !b.UsingOVM { + b.eth.protocolManager.downloader.Cancel() + } b.eth.blockchain.SetHead(number) + + // Make sure to reset the LatestL1{Timestamp,BlockNumber} + block := b.eth.blockchain.CurrentBlock() + txs := block.Transactions() + if len(txs) == 0 { + log.Error("No transactions found in block", "number", number) + return + } + + tx := txs[0] + blockNumber := tx.L1BlockNumber() + if blockNumber == nil { + log.Error("No L1BlockNumber found in transaction", "number", number) + return + } + + b.eth.syncService.SetLatestL1Timestamp(tx.L1Timestamp()) + b.eth.syncService.SetLatestL1BlockNumber(blockNumber.Uint64()) +} + +func (b *EthAPIBackend) SetL1Head(number uint64) error { + return b.eth.syncService.SetL1Head(number) } func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index f3ad6ef8ddbb..81bd66fa3642 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1966,6 +1966,10 @@ func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) { api.b.SetHead(uint64(number)) } +func (api *PrivateDebugAPI) SetL1Head(number hexutil.Uint64) { + api.b.SetL1Head(uint64(number)) +} + // PublicNetAPI offers network related RPC methods type PublicNetAPI struct { net *p2p.Server diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 95dd576d24ab..fa6c7ac86009 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -92,6 +92,7 @@ type Backend interface { GetRollupContractAddresses() map[string]*common.Address GetLatestL1BlockNumber() uint64 GetLatestL1Timestamp() uint64 + SetL1Head(number uint64) error ChainConfig() *params.ChainConfig CurrentBlock() *types.Block diff --git a/les/api_backend.go b/les/api_backend.go index a79fb0f9e010..5de9044873b4 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -91,6 +91,10 @@ func (b *LesApiBackend) SetHead(number uint64) { b.eth.blockchain.SetHead(number) } +func (b *LesApiBackend) SetL1Head(number uint64) error { + panic("unimplemented") +} + func (b *LesApiBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) { if number == rpc.LatestBlockNumber || number == rpc.PendingBlockNumber { return b.eth.blockchain.CurrentHeader(), nil diff --git a/rollup/sync_service.go b/rollup/sync_service.go index 07f18fe508a7..bed7addc41fa 100644 --- a/rollup/sync_service.go +++ b/rollup/sync_service.go @@ -1286,6 +1286,31 @@ func (s *SyncService) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Sub return s.scope.Track(s.txFeed.Subscribe(ch)) } +// SetL1Head resets the Eth1Data +// and the LatestL1BlockNumber and LatestL1Timestamp +func (s *SyncService) SetL1Head(number uint64) error { + header, err := s.ethclient.HeaderByNumber(s.ctx, new(big.Int).SetUint64(number)) + if err != nil { + return fmt.Errorf("Cannot fetch block in SetL1Head: %w", err) + } + + // Reset the header cache + for i := 0; i < len(s.HeaderCache); i++ { + s.HeaderCache[i] = nil + } + + // Reset the last synced L1 heights + rawdb.WriteHeadEth1HeaderHash(s.db, header.Hash()) + rawdb.WriteHeadEth1HeaderHeight(s.db, header.Number.Uint64()) + s.HeaderCache[number%headerCacheSize] = header + + s.Eth1Data = Eth1Data{ + BlockHeight: header.Number.Uint64(), + BlockHash: header.Hash(), + } + return nil +} + // Adds the transaction to the mempool so that downstream services // can apply it to the state. This should directly play against // the state eventually, skipping the mempool.