From 7634b9fb090f8bb078bd0e4016773ca5e99157e7 Mon Sep 17 00:00:00 2001 From: IronGauntlets Date: Mon, 22 Apr 2024 21:16:22 +0100 Subject: [PATCH] Remove pending and empty pending from DB Pending Block is now only managed in memory this is to make sure that pending block in the DB and in memory do not become out of sync. Before the pending block was managed in memory as a cache, however, since there is only one pending block at a given time it doesn't make sense to keep track of pending block in both memory and DB. To reduce the number of block not found errors while simulating transactions it was decided to store empty pending block, using the latest header to fill in fields such as block number, parent block hash, etc. This meant that any time we didn't have a pending block this empty pending block would be served along with empty state diff and classes. Every time a new block was added to the blockchain a new empty pending block was also added to the DB. The unforeseen side effect of this change was when the --poll-pending-interval flag was disabled the rpc would still serve a pending block. This is incorrect behaviour. As the blocks changed per new versions of starknet the empty block also needed to be changed and a storage diff with a special contract "0x1" needed to be updated in the state diff. This overhead is unnecessary and incorrectly informs the user that there is a pending block when there isn't one. --- blockchain/blockchain.go | 157 ++++++++------------------------ blockchain/blockchain_test.go | 89 +----------------- blockchain/event_filter.go | 16 ++-- core/state_update.go | 11 --- db/buckets.go | 2 +- db/buckets_enumer.go | 40 ++++---- migration/migration.go | 5 + migration/migration_pkg_test.go | 24 +++++ rpc/helpers.go | 6 +- rpc/state_update.go | 2 +- 10 files changed, 104 insertions(+), 248 deletions(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 039cce280c..686641ccaf 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "sync/atomic" - "time" "github.com/Masterminds/semver/v3" "github.com/NethermindEth/juno/core" @@ -53,6 +52,7 @@ type Reader interface { var ( ErrParentDoesNotMatchHead = errors.New("block's parent hash does not match head block hash") + ErrPendingBlockNotFound = errors.New("pending block not found") SupportedStarknetVersion = semver.MustParse("0.13.3") ) @@ -81,14 +81,14 @@ func copyWithoutPatch(v *semver.Version) *semver.Version { var _ Reader = (*Blockchain)(nil) +// Todo: Remove after cachedPending is moved to sychcroniser +var cachedPending atomic.Pointer[Pending] + // Blockchain is responsible for keeping track of all things related to the Starknet blockchain type Blockchain struct { network *utils.Network database db.DB - listener EventListener - - cachedPending atomic.Pointer[Pending] } func New(database db.DB, network *utils.Network) *Blockchain { @@ -270,7 +270,7 @@ func (b *Blockchain) TransactionByHash(hash *felt.Felt) (core.Transaction, error // not found in the canonical blocks, try pending if errors.Is(err, db.ErrKeyNotFound) { var pending Pending - pending, err = b.pendingBlock(txn) + pending, err = pendingBlock(txn) if err != nil { return err } @@ -303,9 +303,12 @@ func (b *Blockchain) Receipt(hash *felt.Felt) (*core.TransactionReceipt, *felt.F // not found in the canonical blocks, try pending if errors.Is(err, db.ErrKeyNotFound) { var pending Pending - pending, err = b.pendingBlock(txn) + pending, err = pendingBlock(txn) if err != nil { - return err + if !errors.Is(err, ErrPendingBlockNotFound) { + return err + } + return db.ErrKeyNotFound } for i, t := range pending.Block.Transactions { @@ -389,10 +392,6 @@ func (b *Blockchain) Store(block *core.Block, blockCommitments *core.BlockCommit return err } - if err := b.storeEmptyPending(txn, block.Header); err != nil { - return err - } - // Head of the blockchain is maintained as follows: // [db.ChainHeight]() -> (BlockNumber) heightBin := core.MarshalBlockNumber(block.Number) @@ -866,7 +865,7 @@ func (b *Blockchain) EventFilter(from *felt.Felt, keys [][]felt.Felt) (EventFilt return nil, err } - return newEventFilter(txn, from, keys, 0, latest), nil + return newEventFilter(txn, from, keys, 0, latest, &cachedPending), nil } // RevertHead reverts the head block @@ -936,23 +935,11 @@ func (b *Blockchain) revertHead(txn db.Transaction) error { return err } - // Revert chain height and pending. + // Revert chain height. if genesisBlock { - if err = txn.Delete(db.Pending.Key()); err != nil { - return err - } return txn.Delete(db.ChainHeight.Key()) } - var newHeader *core.Header - newHeader, err = blockHeaderByNumber(txn, blockNumber-1) - if err != nil { - return err - } - if err := b.storeEmptyPending(txn, newHeader); err != nil { - return err - } - heightBin := core.MarshalBlockNumber(blockNumber - 1) return txn.Set(db.ChainHeight.Key(), heightBin) } @@ -989,42 +976,9 @@ func removeTxsAndReceipts(txn db.Transaction, blockNumber, numTxs uint64) error return nil } -func (b *Blockchain) storeEmptyPending(txn db.Transaction, 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(b, 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), - } - return b.storePending(txn, emptyPending) -} - // StorePending stores a pending block given that it is for the next height func (b *Blockchain) StorePending(pending *Pending) error { - return b.database.Update(func(txn db.Transaction) error { + return b.database.View(func(txn db.Transaction) error { expectedParentHash := new(felt.Felt) h, err := headsHeader(txn) if err != nil && !errors.Is(err, db.ErrKeyNotFound) { @@ -1037,57 +991,44 @@ func (b *Blockchain) StorePending(pending *Pending) error { return ErrParentDoesNotMatchHead } - if existingPending, err := b.pendingBlock(txn); err == nil { + if existingPending, err := pendingBlock(txn); err == nil { if existingPending.Block.TransactionCount >= pending.Block.TransactionCount { - return nil // ignore the incoming pending if it has fewer transactions than the one we already have + // ignore the incoming pending if it has fewer transactions than the one we already have + return nil } - pending.Block.Number = existingPending.Block.Number // Just in case the number is not set. - } else if !errors.Is(err, db.ErrKeyNotFound) { // Allow StorePending before block zero. + } else if !errors.Is(err, ErrPendingBlockNotFound) { return err } - return b.storePending(txn, pending) + if h != nil { + pending.Block.Number = h.Number + 1 + } + cachedPending.Store(pending) + + return nil }) } -func (b *Blockchain) storePending(txn db.Transaction, pending *Pending) error { - if err := storePending(txn, pending); err != nil { - return err +// Todo: +// 2. Consider returning reference to Pending instead of Pending +func pendingBlock(txn db.Transaction) (Pending, error) { + pending := cachedPending.Load() + if pending == nil { + return Pending{}, ErrPendingBlockNotFound } - b.cachedPending.Store(pending) - return nil -} -func storePending(txn db.Transaction, pending *Pending) error { - pendingBytes, err := encoder.Marshal(pending) - if err != nil { - return err + expectedParentHash := &felt.Zero + if head, err := headsHeader(txn); err == nil { + expectedParentHash = head.Hash } - return txn.Set(db.Pending.Key(), pendingBytes) -} - -func (b *Blockchain) pendingBlock(txn db.Transaction) (Pending, error) { - if cachedPending := b.cachedPending.Load(); cachedPending != nil { - expectedParentHash := &felt.Zero - if head, err := headsHeader(txn); err == nil { - expectedParentHash = head.Hash - } - if cachedPending.Block.ParentHash.Equal(expectedParentHash) { - return *cachedPending, nil - } + if pending.Block.ParentHash.Equal(expectedParentHash) { + return *pending, nil } - // Either cachedPending was nil or wasn't consistent with the HEAD we have - // in the database, so read it directly from the database - return pendingBlock(txn) -} + // Since the pending block in the cache is outdated remove it + cachedPending.Store(nil) -func pendingBlock(txn db.Transaction) (Pending, error) { - var pending Pending - err := txn.Get(db.Pending.Key(), func(bytes []byte) error { - return encoder.Unmarshal(bytes, &pending) - }) - return pending, err + return Pending{}, ErrPendingBlockNotFound } // Pending returns the pending block from the database @@ -1096,7 +1037,7 @@ func (b *Blockchain) Pending() (Pending, error) { var pending Pending return pending, b.database.View(func(txn db.Transaction) error { var err error - pending, err = b.pendingBlock(txn) + pending, err = pendingBlock(txn) return err }) } @@ -1109,7 +1050,7 @@ func (b *Blockchain) PendingState() (core.StateReader, StateCloser, error) { return nil, nil, err } - pending, err := b.pendingBlock(txn) + pending, err := pendingBlock(txn) if err != nil { return nil, nil, utils.RunAndWrapOnError(txn.Discard, err) } @@ -1120,23 +1061,3 @@ func (b *Blockchain) PendingState() (core.StateReader, StateCloser, error) { core.NewState(txn), ), txn.Discard, nil } - -func MakeStateDiffForEmptyBlock(bc Reader, blockNumber uint64) (*core.StateDiff, error) { - stateDiff := core.EmptyStateDiff() - - 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 -} diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 4c217c3ba1..cf5ce5c220 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "testing" - "time" "github.com/NethermindEth/juno/blockchain" "github.com/NethermindEth/juno/clients/feeder" @@ -12,13 +11,11 @@ import ( "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/db" "github.com/NethermindEth/juno/db/pebble" - "github.com/NethermindEth/juno/mocks" adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder" "github.com/NethermindEth/juno/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" ) var emptyCommitments = core.BlockCommitments{} @@ -356,7 +353,7 @@ func TestTransactionAndReceipt(t *testing.T) { t.Run("GetTransactionByHash returns error if transaction does not exist", func(t *testing.T) { tx, err := chain.TransactionByHash(new(felt.Felt).SetUint64(345)) assert.Nil(t, tx) - assert.EqualError(t, err, db.ErrKeyNotFound.Error()) + assert.EqualError(t, err, blockchain.ErrPendingBlockNotFound.Error()) }) t.Run("GetTransactionReceipt returns error if receipt does not exist", func(t *testing.T) { @@ -723,63 +720,6 @@ func TestPending(t *testing.T) { b.GasPriceSTRK = utils.HexToFelt(t, "0xDEADBEEF") require.NoError(t, chain.Store(b, &emptyCommitments, su, nil)) - t.Run("no pending block means pending state matches head state", func(t *testing.T) { - pending, pErr := chain.Pending() - require.NoError(t, pErr) - - require.LessOrEqual(t, pending.Block.Timestamp, uint64(time.Now().Unix())) - require.GreaterOrEqual(t, pending.Block.Timestamp, b.Timestamp) - receipts := make([]*core.TransactionReceipt, 0) - require.Equal(t, blockchain.Pending{ - Block: &core.Block{ - Header: &core.Header{ - ParentHash: b.Hash, - SequencerAddress: b.SequencerAddress, - Number: b.Number + 1, - Timestamp: pending.Block.Timestamp, // Tested above. - ProtocolVersion: b.ProtocolVersion, - EventsBloom: core.EventsBloom(receipts), - GasPrice: b.GasPrice, - GasPriceSTRK: b.GasPriceSTRK, - }, - Transactions: make([]core.Transaction, 0), - Receipts: receipts, - }, - StateUpdate: &core.StateUpdate{ - OldRoot: su.NewRoot, - StateDiff: core.EmptyStateDiff(), - }, - NewClasses: make(map[felt.Felt]core.Class, 0), - }, pending) - - // PendingState matches head state. - require.NoError(t, pErr) - reader, closer, pErr := chain.PendingState() - require.NoError(t, pErr) - t.Cleanup(func() { - require.NoError(t, closer()) - }) - - for addr, diff := range su.StateDiff.StorageDiffs { - for key, diffVal := range diff { - value, csErr := reader.ContractStorage(&addr, &key) - require.NoError(t, csErr) - require.Equal(t, diffVal, value) - } - } - - for address, nonce := range su.StateDiff.Nonces { - got, cnErr := reader.ContractNonce(&address) - require.NoError(t, cnErr) - require.Equal(t, nonce, got) - } - - for _, hash := range su.StateDiff.DeclaredV0Classes { - _, err = reader.Class(hash) - require.NoError(t, err) - } - }) - t.Run("storing a pending too far into the future should fail", func(t *testing.T) { b, err = gw.BlockByNumber(context.Background(), 2) require.NoError(t, err) @@ -871,30 +811,3 @@ func TestStorePendingIncludesNumber(t *testing.T) { require.NoError(t, err) require.Equal(t, uint64(1), pending.Block.Number) } - -func TestMakeStateDiffForEmptyBlock(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - - mockReader := mocks.NewMockReader(mockCtrl) - t.Run("earlier blocks shouldnt have block hash in state", func(t *testing.T) { - for i := uint64(0); i < 10; i++ { - sd, err := blockchain.MakeStateDiffForEmptyBlock(mockReader, i) - require.NoError(t, err) - assert.Equal(t, core.EmptyStateDiff(), sd) - } - }) - - t.Run("should have block hash in state", func(t *testing.T) { - blockHash := utils.HexToFelt(t, "0xDEADBEEF") - storageContractAddr := utils.HexToFelt(t, "0x1") - - mockReader.EXPECT().BlockHeaderByNumber(uint64(0)).Return(&core.Header{ - Number: 0, - Hash: blockHash, - }, nil) - sd, err := blockchain.MakeStateDiffForEmptyBlock(mockReader, 10) - require.NoError(t, err) - assert.Equal(t, blockHash, sd.StorageDiffs[*storageContractAddr][felt.Zero]) - }) -} diff --git a/blockchain/event_filter.go b/blockchain/event_filter.go index 37c79b5e00..f756e1ce5e 100644 --- a/blockchain/event_filter.go +++ b/blockchain/event_filter.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "math" + "sync/atomic" "github.com/NethermindEth/juno/core" "github.com/NethermindEth/juno/core/felt" @@ -32,6 +33,7 @@ type EventFilter struct { contractAddress *felt.Felt keys [][]felt.Felt maxScanned uint // maximum number of scanned blocks in single call. + pending *atomic.Pointer[Pending] } type EventFilterRange uint @@ -41,7 +43,9 @@ const ( EventFilterTo ) -func newEventFilter(txn db.Transaction, contractAddress *felt.Felt, keys [][]felt.Felt, fromBlock, toBlock uint64) *EventFilter { +func newEventFilter(txn db.Transaction, contractAddress *felt.Felt, keys [][]felt.Felt, fromBlock, toBlock uint64, + pending *atomic.Pointer[Pending], +) *EventFilter { return &EventFilter{ txn: txn, contractAddress: contractAddress, @@ -49,6 +53,7 @@ func newEventFilter(txn db.Transaction, contractAddress *felt.Felt, keys [][]fel fromBlock: fromBlock, toBlock: toBlock, maxScanned: math.MaxUint, + pending: pending, } } @@ -113,14 +118,13 @@ func (e *EventFilter) Events(cToken *ContinuationToken, chunkSize uint64) ([]*Fi return nil, nil, err } - var pending Pending + var pending *Pending if e.toBlock > latest { e.toBlock = latest + 1 - pending, err = pendingBlock(e.txn) - if errors.Is(err, db.ErrKeyNotFound) { + + pending = e.pending.Load() + if pending == nil { e.toBlock = latest - } else if err != nil { - return nil, nil, err } } diff --git a/core/state_update.go b/core/state_update.go index 45ceeb53a4..9780bbc643 100644 --- a/core/state_update.go +++ b/core/state_update.go @@ -24,17 +24,6 @@ type StateDiff struct { ReplacedClasses map[felt.Felt]*felt.Felt // addr -> class hash } -func EmptyStateDiff() *StateDiff { - return &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), - } -} - func (d *StateDiff) Length() uint64 { var length int diff --git a/db/buckets.go b/db/buckets.go index a3097d8512..2773773f5a 100644 --- a/db/buckets.go +++ b/db/buckets.go @@ -29,7 +29,7 @@ const ( ContractDeploymentHeight L1Height SchemaVersion - Pending + Unused // Previously used for storing Pending Block BlockCommitments Temporary // used temporarily for migrations SchemaIntermediateState diff --git a/db/buckets_enumer.go b/db/buckets_enumer.go index b835240f59..2e99c9258c 100644 --- a/db/buckets_enumer.go +++ b/db/buckets_enumer.go @@ -7,11 +7,11 @@ import ( "strings" ) -const _BucketName = "StateTriePeerContractClassHashContractStorageClassContractNonceChainHeightBlockHeaderNumbersByHashBlockHeadersByNumberTransactionBlockNumbersAndIndicesByHashTransactionsByBlockNumberAndIndexReceiptsByBlockNumberAndIndexStateUpdatesByBlockNumberClassesTrieContractStorageHistoryContractNonceHistoryContractClassHashHistoryContractDeploymentHeightL1HeightSchemaVersionPendingBlockCommitmentsTemporarySchemaIntermediateStateL1HandlerTxnHashByMsgHash" +const _BucketName = "StateTriePeerContractClassHashContractStorageClassContractNonceChainHeightBlockHeaderNumbersByHashBlockHeadersByNumberTransactionBlockNumbersAndIndicesByHashTransactionsByBlockNumberAndIndexReceiptsByBlockNumberAndIndexStateUpdatesByBlockNumberClassesTrieContractStorageHistoryContractNonceHistoryContractClassHashHistoryContractDeploymentHeightL1HeightSchemaVersionUnusedBlockCommitmentsTemporarySchemaIntermediateStateL1HandlerTxnHashByMsgHash" -var _BucketIndex = [...]uint16{0, 9, 13, 30, 45, 50, 63, 74, 98, 118, 157, 190, 219, 244, 255, 277, 297, 321, 345, 353, 366, 373, 389, 398, 421, 446} +var _BucketIndex = [...]uint16{0, 9, 13, 30, 45, 50, 63, 74, 98, 118, 157, 190, 219, 244, 255, 277, 297, 321, 345, 353, 366, 372, 388, 397, 420, 445} -const _BucketLowerName = "statetriepeercontractclasshashcontractstorageclasscontractnoncechainheightblockheadernumbersbyhashblockheadersbynumbertransactionblocknumbersandindicesbyhashtransactionsbyblocknumberandindexreceiptsbyblocknumberandindexstateupdatesbyblocknumberclassestriecontractstoragehistorycontractnoncehistorycontractclasshashhistorycontractdeploymentheightl1heightschemaversionpendingblockcommitmentstemporaryschemaintermediatestatel1handlertxnhashbymsghash" +const _BucketLowerName = "statetriepeercontractclasshashcontractstorageclasscontractnoncechainheightblockheadernumbersbyhashblockheadersbynumbertransactionblocknumbersandindicesbyhashtransactionsbyblocknumberandindexreceiptsbyblocknumberandindexstateupdatesbyblocknumberclassestriecontractstoragehistorycontractnoncehistorycontractclasshashhistorycontractdeploymentheightl1heightschemaversionunusedblockcommitmentstemporaryschemaintermediatestatel1handlertxnhashbymsghash" func (i Bucket) String() string { if i >= Bucket(len(_BucketIndex)-1) { @@ -44,14 +44,14 @@ func _BucketNoOp() { _ = x[ContractDeploymentHeight-(17)] _ = x[L1Height-(18)] _ = x[SchemaVersion-(19)] - _ = x[Pending-(20)] + _ = x[Unused-(20)] _ = x[BlockCommitments-(21)] _ = x[Temporary-(22)] _ = x[SchemaIntermediateState-(23)] _ = x[L1HandlerTxnHashByMsgHash-(24)] } -var _BucketValues = []Bucket{StateTrie, Peer, ContractClassHash, ContractStorage, Class, ContractNonce, ChainHeight, BlockHeaderNumbersByHash, BlockHeadersByNumber, TransactionBlockNumbersAndIndicesByHash, TransactionsByBlockNumberAndIndex, ReceiptsByBlockNumberAndIndex, StateUpdatesByBlockNumber, ClassesTrie, ContractStorageHistory, ContractNonceHistory, ContractClassHashHistory, ContractDeploymentHeight, L1Height, SchemaVersion, Pending, BlockCommitments, Temporary, SchemaIntermediateState, L1HandlerTxnHashByMsgHash} +var _BucketValues = []Bucket{StateTrie, Peer, ContractClassHash, ContractStorage, Class, ContractNonce, ChainHeight, BlockHeaderNumbersByHash, BlockHeadersByNumber, TransactionBlockNumbersAndIndicesByHash, TransactionsByBlockNumberAndIndex, ReceiptsByBlockNumberAndIndex, StateUpdatesByBlockNumber, ClassesTrie, ContractStorageHistory, ContractNonceHistory, ContractClassHashHistory, ContractDeploymentHeight, L1Height, SchemaVersion, Unused, BlockCommitments, Temporary, SchemaIntermediateState, L1HandlerTxnHashByMsgHash} var _BucketNameToValueMap = map[string]Bucket{ _BucketName[0:9]: StateTrie, @@ -94,16 +94,16 @@ var _BucketNameToValueMap = map[string]Bucket{ _BucketLowerName[345:353]: L1Height, _BucketName[353:366]: SchemaVersion, _BucketLowerName[353:366]: SchemaVersion, - _BucketName[366:373]: Pending, - _BucketLowerName[366:373]: Pending, - _BucketName[373:389]: BlockCommitments, - _BucketLowerName[373:389]: BlockCommitments, - _BucketName[389:398]: Temporary, - _BucketLowerName[389:398]: Temporary, - _BucketName[398:421]: SchemaIntermediateState, - _BucketLowerName[398:421]: SchemaIntermediateState, - _BucketName[421:446]: L1HandlerTxnHashByMsgHash, - _BucketLowerName[421:446]: L1HandlerTxnHashByMsgHash, + _BucketName[366:372]: Unused, + _BucketLowerName[366:372]: Unused, + _BucketName[372:388]: BlockCommitments, + _BucketLowerName[372:388]: BlockCommitments, + _BucketName[388:397]: Temporary, + _BucketLowerName[388:397]: Temporary, + _BucketName[397:420]: SchemaIntermediateState, + _BucketLowerName[397:420]: SchemaIntermediateState, + _BucketName[420:445]: L1HandlerTxnHashByMsgHash, + _BucketLowerName[420:445]: L1HandlerTxnHashByMsgHash, } var _BucketNames = []string{ @@ -127,11 +127,11 @@ var _BucketNames = []string{ _BucketName[321:345], _BucketName[345:353], _BucketName[353:366], - _BucketName[366:373], - _BucketName[373:389], - _BucketName[389:398], - _BucketName[398:421], - _BucketName[421:446], + _BucketName[366:372], + _BucketName[372:388], + _BucketName[388:397], + _BucketName[397:420], + _BucketName[420:445], } // BucketString retrieves an enum value from the enum constants string name. diff --git a/migration/migration.go b/migration/migration.go index b27a275887..e55fe3cfcb 100644 --- a/migration/migration.go +++ b/migration/migration.go @@ -67,6 +67,7 @@ var defaultMigrations = []Migration{ NewBucketMigrator(db.StateUpdatesByBlockNumber, changeStateDiffStruct).WithBatchSize(100), //nolint:mnd NewBucketMigrator(db.Class, migrateCairo1CompiledClass).WithBatchSize(1_000), //nolint:mnd MigrationFunc(calculateL1MsgHashes), + MigrationFunc(removePendingBlock), } var ErrCallWithNewTransaction = errors.New("call with new transaction") @@ -271,6 +272,10 @@ func recalculateBloomFilters(txn db.Transaction, _ *utils.Network) error { } } +func removePendingBlock(txn db.Transaction, _ *utils.Network) error { + return txn.Delete(db.Unused.Key()) +} + // changeTrieNodeEncoding migrates to using a custom encoding for trie nodes // that minimises memory allocations. Always use new(changeTrieNodeEncoding) // before calling Before(), otherwise it will panic. diff --git a/migration/migration_pkg_test.go b/migration/migration_pkg_test.go index cd26d59db6..24d092d9fc 100644 --- a/migration/migration_pkg_test.go +++ b/migration/migration_pkg_test.go @@ -106,6 +106,30 @@ func TestRecalculateBloomFilters(t *testing.T) { } } +func TestRemovePending(t *testing.T) { + testDB := pebble.NewMemTest(t) + pendingBlockBytes := []byte("some pending block bytes") + require.NoError(t, testDB.Update(func(txn db.Transaction) error { + if err := txn.Set(db.Unused.Key(), pendingBlockBytes); err != nil { + return err + } + + if err := txn.Get(db.Unused.Key(), func(_ []byte) error { return nil }); err != nil { + return err + } + + if err := removePendingBlock(txn, nil); err != nil { + return err + } + + assert.EqualError(t, db.ErrKeyNotFound, testDB.View(func(txn db.Transaction) error { + return txn.Get(db.Unused.Key(), nil) + }).Error()) + + return nil + })) +} + func TestChangeTrieNodeEncoding(t *testing.T) { testdb := pebble.NewMemTest(t) diff --git a/rpc/helpers.go b/rpc/helpers.go index dae08c5ff4..1dc3a5cbfb 100644 --- a/rpc/helpers.go +++ b/rpc/helpers.go @@ -46,7 +46,7 @@ func (h *Handler) blockByID(id *BlockID) (*core.Block, *jsonrpc.Error) { } if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { + if errors.Is(err, db.ErrKeyNotFound) || errors.Is(err, blockchain.ErrPendingBlockNotFound) { return nil, ErrBlockNotFound } return nil, ErrInternal.CloneWithData(err) @@ -76,7 +76,7 @@ func (h *Handler) blockHeaderByID(id *BlockID) (*core.Header, *jsonrpc.Error) { } if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { + if errors.Is(err, db.ErrKeyNotFound) || errors.Is(err, blockchain.ErrPendingBlockNotFound) { return nil, ErrBlockNotFound } return nil, ErrInternal.CloneWithData(err) @@ -164,7 +164,7 @@ func (h *Handler) stateByBlockID(id *BlockID) (core.StateReader, blockchain.Stat } if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { + if errors.Is(err, db.ErrKeyNotFound) || errors.Is(err, blockchain.ErrPendingBlockNotFound) { return nil, nil, ErrBlockNotFound } return nil, nil, ErrInternal.CloneWithData(err) diff --git a/rpc/state_update.go b/rpc/state_update.go index b16d2a1666..d9b2fb3199 100644 --- a/rpc/state_update.go +++ b/rpc/state_update.go @@ -86,7 +86,7 @@ func (h *Handler) StateUpdate(id BlockID) (*StateUpdate, *jsonrpc.Error) { update, err = h.bcReader.StateUpdateByNumber(id.Number) } if err != nil { - if errors.Is(err, db.ErrKeyNotFound) { + if errors.Is(err, db.ErrKeyNotFound) || errors.Is(err, blockchain.ErrPendingBlockNotFound) { return nil, ErrBlockNotFound } return nil, ErrInternal.CloneWithData(err)