From 0c6508c39a8ff04665ab499c837e5fe2c1183b5f Mon Sep 17 00:00:00 2001 From: Aneeque Date: Wed, 15 Jan 2025 11:26:40 +0000 Subject: [PATCH] Store empty pending block and state (#2372) In one of the previous commits empty pending block and state was removed as the spec allowed returning block not found error if pending didn't exist. However, `statknet.js` tests always expect a block or state to be returned when a pending block or state is requested; therefore, it is re-added. --- sync/sync.go | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/sync/sync.go b/sync/sync.go index 2b25ef03fe..06eb24d695 100644 --- a/sync/sync.go +++ b/sync/sync.go @@ -289,6 +289,7 @@ func (s *Synchronizer) handlePluginRevertBlock() { } } +//nolint:gocyclo func (s *Synchronizer) verifierTask(ctx context.Context, block *core.Block, stateUpdate *core.StateUpdate, newClasses map[felt.Felt]core.Class, resetStreams context.CancelFunc, ) stream.Callback { @@ -318,6 +319,18 @@ func (s *Synchronizer) verifierTask(ctx context.Context, block *core.Block, stat s.handlePluginRevertBlock() } s.revertHead(block) + + // The previous head has been reverted, hence, get the current head and store empty pending block + head, err := s.blockchain.HeadsHeader() + if err != nil { + s.log.Errorw("Failed to retrieve the head header", "err", err) + } + + if head != nil { + if err := s.storeEmptyPending(head); err != nil { + s.log.Errorw("Failed to store empty pending block", "number", block.Number) + } + } } else { s.log.Warnw("Failed storing Block", "number", block.Number, "hash", block.Hash.ShortString(), "err", err) @@ -325,6 +338,11 @@ func (s *Synchronizer) verifierTask(ctx context.Context, block *core.Block, stat resetStreams() return } + + if err := s.storeEmptyPending(block.Header); err != nil { + s.log.Errorw("Failed to store empty pending block", "number", block.Number) + } + s.listener.OnSyncStepDone(OpStore, block.Number, time.Since(storeTimer)) highestBlockHeader := s.highestBlockHeader.Load() @@ -628,9 +646,6 @@ func (s *Synchronizer) Pending() (*Pending, error) { return p, nil } - // Since the pending block in the cache is outdated remove it - s.pending.Store(nil) - return nil, ErrPendingBlockNotFound } @@ -656,3 +671,65 @@ func (s *Synchronizer) PendingState() (core.StateReader, func() error, error) { return NewPendingState(pending.StateUpdate.StateDiff, pending.NewClasses, core.NewState(txn)), txn.Discard, nil } + +func (s *Synchronizer) storeEmptyPending(latestHeader *core.Header) error { + receipts := make([]*core.TransactionReceipt, 0) + pendingBlock := &core.Block{ + Header: &core.Header{ + ParentHash: latestHeader.Hash, + SequencerAddress: latestHeader.SequencerAddress, + Number: latestHeader.Number + 1, + Timestamp: uint64(time.Now().Unix()), + ProtocolVersion: latestHeader.ProtocolVersion, + EventsBloom: core.EventsBloom(receipts), + GasPrice: latestHeader.GasPrice, + GasPriceSTRK: latestHeader.GasPriceSTRK, + }, + Transactions: make([]core.Transaction, 0), + Receipts: receipts, + } + + stateDiff, err := makeStateDiffForEmptyBlock(s.blockchain, latestHeader.Number+1) + if err != nil { + return err + } + + emptyPending := &Pending{ + Block: pendingBlock, + StateUpdate: &core.StateUpdate{ + OldRoot: latestHeader.GlobalStateRoot, + StateDiff: stateDiff, + }, + NewClasses: make(map[felt.Felt]core.Class, 0), + } + + s.pending.Store(emptyPending) + return nil +} + +func makeStateDiffForEmptyBlock(bc blockchain.Reader, blockNumber uint64) (*core.StateDiff, error) { + stateDiff := &core.StateDiff{ + StorageDiffs: make(map[felt.Felt]map[felt.Felt]*felt.Felt), + Nonces: make(map[felt.Felt]*felt.Felt), + DeployedContracts: make(map[felt.Felt]*felt.Felt), + DeclaredV0Classes: make([]*felt.Felt, 0), + DeclaredV1Classes: make(map[felt.Felt]*felt.Felt), + ReplacedClasses: make(map[felt.Felt]*felt.Felt), + } + + const blockHashLag = 10 + if blockNumber < blockHashLag { + return stateDiff, nil + } + + header, err := bc.BlockHeaderByNumber(blockNumber - blockHashLag) + if err != nil { + return nil, err + } + + blockHashStorageContract := new(felt.Felt).SetUint64(1) + stateDiff.StorageDiffs[*blockHashStorageContract] = map[felt.Felt]*felt.Felt{ + *new(felt.Felt).SetUint64(header.Number): header.Hash, + } + return stateDiff, nil +}