From 5cb2899276f0d31a792c0828c03232f578075bcb Mon Sep 17 00:00:00 2001 From: 0xsamalt Date: Tue, 30 Jun 2026 15:51:48 +0000 Subject: [PATCH] refactor(starknet): change BlockIdentifier from string to typed uint64 --- adapters/sn2core/sn2core.go | 4 +- adapters/sn2core/sn2core_test.go | 14 +-- blockchain/blockchain_test.go | 4 +- clients/feeder/feeder.go | 18 ++-- clients/feeder/feeder_test.go | 16 +-- clients/feeder/test_feeder.go | 4 +- core/pending/pending.go | 4 +- mocks/mock_feeder.go | 6 +- mocks/mock_starknetdata.go | 6 +- rpc/rpccore/preconfirmed_deduper.go | 6 +- rpc/rpccore/preconfirmed_deduper_test.go | 4 +- rpc/v10/block_test.go | 4 +- rpc/v10/events_test.go | 2 +- rpc/v10/state_update_test.go | 10 +- rpc/v10/trace_test.go | 2 +- rpc/v10/transaction_test.go | 8 +- rpc/v8/subscriptions_test.go | 4 +- rpc/v9/block_test.go | 10 +- rpc/v9/events_test.go | 2 +- rpc/v9/state_update_test.go | 8 +- rpc/v9/trace_test.go | 2 +- rpc/v9/transaction_test.go | 10 +- sequencer/sequencer.go | 2 +- starknet/pre_confirmed_update.go | 91 ++++++++++++----- starknet/pre_confirmed_update_test.go | 18 ++-- starknetdata/feeder/feeder.go | 4 +- starknetdata/feeder/feeder_test.go | 4 +- starknetdata/starknetdata.go | 4 +- sync/data_source.go | 8 +- sync/helpers.go | 2 +- sync/preconfirmed/chain_storage.go | 2 +- sync/preconfirmed/chain_storage_test.go | 47 +++++---- sync/preconfirmed/poller.go | 12 +-- sync/preconfirmed/poller_test.go | 125 ++++++++++++----------- sync/reorg_test.go | 4 +- 35 files changed, 262 insertions(+), 209 deletions(-) diff --git a/adapters/sn2core/sn2core.go b/adapters/sn2core/sn2core.go index 989b8da4ce..d4195114f7 100644 --- a/adapters/sn2core/sn2core.go +++ b/adapters/sn2core/sn2core.go @@ -578,7 +578,7 @@ func AdaptPreConfirmedBlock( adaptedBlock, &stateUpdate, txStateDiffs, - response.BlockIdentifier, + uint64(response.BlockIdentifier), ) return preConfirmed, nil } @@ -592,7 +592,7 @@ func AdaptPreConfirmedWithDelta( current *pending.PreConfirmed, delta *starknet.PreConfirmedDeltaUpdate, ) (pending.PreConfirmed, error) { - if current.BlockIdentifier != delta.BlockIdentifier { + if current.BlockIdentifier != uint64(delta.BlockIdentifier) { return pending.PreConfirmed{}, ErrPreConfirmedIdentifierMismatch } diff --git a/adapters/sn2core/sn2core_test.go b/adapters/sn2core/sn2core_test.go index 2cc4ddc198..8210b23b15 100644 --- a/adapters/sn2core/sn2core_test.go +++ b/adapters/sn2core/sn2core_test.go @@ -664,7 +664,7 @@ func TestAdaptPreConfirmed(t *testing.T) { for _, test := range tests { t.Run(test.description, func(t *testing.T) { blockNumberStr := strconv.FormatUint(test.blockNumber, 10) - update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), blockNumberStr, "", 0) + update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), blockNumberStr, 0, 0) require.NoError(t, err) responseFull, ok := update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", update) @@ -708,7 +708,7 @@ func assertPreConfirmedBlockBasics( assert.Equal(t, response.Version, preConfirmed.Block.ProtocolVersion) assert.Equal(t, response.L1GasPrice.PriceInFri, preConfirmed.Block.L1GasPriceSTRK) assert.Equal(t, response.L1GasPrice.PriceInWei, preConfirmed.Block.L1GasPriceETH) - assert.Equal(t, response.BlockIdentifier, preConfirmed.BlockIdentifier) + assert.Equal(t, uint64(response.BlockIdentifier), preConfirmed.BlockIdentifier) } func assertStateDiffs( @@ -816,23 +816,23 @@ func TestAdaptPreConfirmedWithDelta(t *testing.T) { t.Run("returns ErrPreConfirmedIdentifierMismatch on identifier drift", func(t *testing.T) { current := &pending.PreConfirmed{ - BlockIdentifier: "round-a", + BlockIdentifier: 1, Block: &core.Block{Header: &core.Header{}}, StateUpdate: &core.StateUpdate{StateDiff: &core.StateDiff{}}, } - delta := &starknet.PreConfirmedDeltaUpdate{BlockIdentifier: "round-b"} + delta := &starknet.PreConfirmedDeltaUpdate{BlockIdentifier: 2} _, err := sn2core.AdaptPreConfirmedWithDelta(current, delta) require.ErrorIs(t, err, sn2core.ErrPreConfirmedIdentifierMismatch) }) t.Run("returns error on mismatched delta lengths", func(t *testing.T) { current := &pending.PreConfirmed{ - BlockIdentifier: "round-a", + BlockIdentifier: 1, Block: &core.Block{Header: &core.Header{}}, StateUpdate: &core.StateUpdate{StateDiff: &core.StateDiff{}}, } delta := &starknet.PreConfirmedDeltaUpdate{ - BlockIdentifier: "round-a", + BlockIdentifier: 1, Transactions: []starknet.Transaction{{}}, Receipts: []*starknet.TransactionReceipt{{}, {}}, TransactionStateDiffs: []*starknet.StateDiff{{}}, @@ -850,7 +850,7 @@ func mustFetchPreConfirmedBlock( ) *starknet.PreConfirmedBlock { t.Helper() update, err := client.PreConfirmedBlockWithIdentifier( - t.Context(), strconv.FormatUint(number, 10), "", 0, + t.Context(), strconv.FormatUint(number, 10), 0, 0, ) require.NoError(t, err) full, ok := update.(starknet.PreConfirmedBlock) diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index 821dc27faf..39cc885261 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -516,7 +516,7 @@ func TestState(t *testing.T) { func TestEvents(t *testing.T) { var pendingB *core.Block preConfirmedFunc := func() (blockchain.PreConfirmedReader, error) { //nolint:unparam // test stub - preConfirmed := pending.NewPreConfirmed(pendingB, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(pendingB, nil, nil, 0) chain, err := preconfirmed.NewChain(&preConfirmed) if err != nil { return nil, err @@ -771,7 +771,7 @@ func TestEventsMultiPreConfirmed(t *testing.T) { block, err := gw.BlockByNumber(t.Context(), i) require.NoError(t, err) - preconfirmed := pending.NewPreConfirmed(block, nil, nil, "") + preconfirmed := pending.NewPreConfirmed(block, nil, nil, 0) pcEntries[i-firstPreConfirmedBlock] = &preconfirmed } preconfChain, err := preconfirmed.NewChain(pcEntries...) diff --git a/clients/feeder/feeder.go b/clients/feeder/feeder.go index 593f3f4b2c..abdcca3805 100644 --- a/clients/feeder/feeder.go +++ b/clients/feeder/feeder.go @@ -23,7 +23,7 @@ const ( classHashArg = "classHash" trueStr = "true" - PreConfirmedBlankIdentifier = "0x0" + PreConfirmedBlankIdentifier starknet.BlockIdentifier = 0 ) var ErrDeprecatedCompiledClass = errors.New("deprecated compiled class") @@ -56,12 +56,12 @@ type Reader interface { PreConfirmedBlockWithIdentifier( ctx context.Context, blockNumber string, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) PublicKey(ctx context.Context) (felt.Felt, error) @@ -367,9 +367,10 @@ func (c *Client) StateUpdateWithBlockAndSignature( func (c *Client) PreConfirmedBlockWithIdentifier( ctx context.Context, blockNumber string, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) { + preConfirmedEnvelope, err := c.fetchPreConfirmedUpdate( ctx, blockNumber, @@ -388,7 +389,7 @@ func (c *Client) PreConfirmedBlockWithIdentifier( // Pass an empty identifier and zero txCount for a full reply. func (c *Client) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) { preConfirmedEnvelope, err := c.fetchPreConfirmedUpdate( @@ -414,15 +415,12 @@ func (c *Client) PreConfirmedBlockLatest( func (c *Client) fetchPreConfirmedUpdate( ctx context.Context, blockNumber string, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (*starknet.PreConfirmedUpdateEnvelope, error) { - if blockIdentifier == "" { - blockIdentifier = PreConfirmedBlankIdentifier - } queryURL := buildQueryString(c.url, "get_preconfirmed_block", map[string]string{ blockNumberArg: blockNumber, - "blockIdentifier": blockIdentifier, + "blockIdentifier": fmt.Sprintf("0x%x", blockIdentifier), "knownTransactionCount": strconv.FormatUint(knownTransactionCount, 10), }) diff --git a/clients/feeder/feeder_test.go b/clients/feeder/feeder_test.go index 2766652386..144d96ffcc 100644 --- a/clients/feeder/feeder_test.go +++ b/clients/feeder/feeder_test.go @@ -1248,7 +1248,7 @@ func TestFeederValidation(t *testing.T) { }` client := clientServingBody(t, body) - update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), "", "", 0) + update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), "", 0, 0) require.NoError(t, err) _, ok := update.(starknet.PreConfirmedDeltaUpdate) require.True(t, ok) @@ -1265,7 +1265,7 @@ func TestFeederValidation(t *testing.T) { }` client := clientServingBody(t, body) - update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), "", "", 0) + update, err := client.PreConfirmedBlockWithIdentifier(t.Context(), "", 0, 0) require.Error(t, err) require.Nil(t, update) assert.ErrorIs(t, err, feeder.ErrInvalidFeederResponse) @@ -1280,37 +1280,37 @@ func TestPreConfirmedBlockLatest(t *testing.T) { client := feeder.NewTestClient(t, &networks.Sepolia) t.Run("blank identifier returns the full block for a new round", func(t *testing.T) { - update, blockNumber, err := client.PreConfirmedBlockLatest(t.Context(), "", 0) + update, blockNumber, err := client.PreConfirmedBlockLatest(t.Context(), 0, 0) require.NoError(t, err) assert.Equal(t, uint64(10936237), blockNumber) full, ok := update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", update) - assert.Equal(t, "0x1cbe25d9", full.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1cbe25d9), full.BlockIdentifier) assert.Equal(t, "PRE_CONFIRMED", full.Status) assert.Equal(t, "0.14.2", full.Version) assert.Len(t, full.Transactions, 3) }) t.Run("matching identifier and txn count returns the appended delta", func(t *testing.T) { - update, blockNumber, err := client.PreConfirmedBlockLatest(t.Context(), "0x1cbe25d9", 3) + update, blockNumber, err := client.PreConfirmedBlockLatest(t.Context(), 0x1cbe25d9, 3) require.NoError(t, err) assert.Equal(t, uint64(10936237), blockNumber) delta, ok := update.(starknet.PreConfirmedDeltaUpdate) require.True(t, ok, "expected PreConfirmedDeltaUpdate, got %T", update) - assert.Equal(t, "0x1cbe25d9", delta.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1cbe25d9), delta.BlockIdentifier) assert.Len(t, delta.Transactions, 1) }) t.Run("matching identifier with no appended txns returns no change", func(t *testing.T) { - update, _, err := client.PreConfirmedBlockLatest(t.Context(), "0x1cbe25d9", 4) + update, _, err := client.PreConfirmedBlockLatest(t.Context(), 0x1cbe25d9, 4) require.NoError(t, err) assert.IsType(t, starknet.PreConfirmedNoChange{}, update) }) t.Run("full block response without block_number is rejected", func(t *testing.T) { - _, _, err := client.PreConfirmedBlockLatest(t.Context(), "0xbad", 0) + _, _, err := client.PreConfirmedBlockLatest(t.Context(), 0xbad, 0) require.ErrorContains(t, err, "missing block_number") }) } diff --git a/clients/feeder/test_feeder.go b/clients/feeder/test_feeder.go index d42509dd8d..16812ee4a0 100644 --- a/clients/feeder/test_feeder.go +++ b/clients/feeder/test_feeder.go @@ -2,6 +2,7 @@ package feeder import ( "errors" + "fmt" "net/http" "net/http/httptest" "net/url" @@ -160,7 +161,8 @@ func resolveDirAndQueryArg(t testing.TB, path string, queryMap url.Values) (stri // any other identifier selects the exact response fixture at // preconfirmed///. blockNumber := queryMap.Get(blockNumberArg) - if identifier := queryMap.Get("blockIdentifier"); identifier != PreConfirmedBlankIdentifier { + blankIdentifier := fmt.Sprintf("0x%x", PreConfirmedBlankIdentifier) + if identifier := queryMap.Get("blockIdentifier"); identifier != blankIdentifier { return filepath.Join("preconfirmed", blockNumber, identifier), "knownTransactionCount", nil } queryMap["preconfirmedFile"] = []string{"full"} diff --git a/core/pending/pending.go b/core/pending/pending.go index 73d9c3f64d..81c7ee883b 100644 --- a/core/pending/pending.go +++ b/core/pending/pending.go @@ -63,14 +63,14 @@ type PreConfirmed struct { // BlockIdentifier is an identifier returned by the feeder gateway // that uniquely identifies the current round of the pre_confirmed block. // It is used to negotiate delta-sync responses on subsequent polls. - BlockIdentifier string + BlockIdentifier uint64 } func NewPreConfirmed( block *core.Block, stateUpdate *core.StateUpdate, transactionStateDiffs []*core.StateDiff, - blockIdentifier string, + blockIdentifier uint64, ) PreConfirmed { return PreConfirmed{ Block: block, diff --git a/mocks/mock_feeder.go b/mocks/mock_feeder.go index 8da35fb9e1..9214e29231 100644 --- a/mocks/mock_feeder.go +++ b/mocks/mock_feeder.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -destination=../../mocks/mock_feeder.go -mock_names Reader=MockFeederReader -package=mocks github.com/NethermindEth/juno/clients/feeder Reader +// mockgen -destination=mocks/mock_feeder.go -mock_names Reader=MockFeederReader -package=mocks github.com/NethermindEth/juno/clients/feeder Reader // // Package mocks is a generated GoMock package. @@ -133,7 +133,7 @@ func (mr *MockFeederReaderMockRecorder) FeeTokenAddresses(ctx any) *gomock.Call } // PreConfirmedBlockLatest mocks base method. -func (m *MockFeederReader) PreConfirmedBlockLatest(ctx context.Context, blockIdentifier string, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, uint64, error) { +func (m *MockFeederReader) PreConfirmedBlockLatest(ctx context.Context, blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PreConfirmedBlockLatest", ctx, blockIdentifier, knownTransactionCount) ret0, _ := ret[0].(starknet.PreConfirmedUpdate) @@ -149,7 +149,7 @@ func (mr *MockFeederReaderMockRecorder) PreConfirmedBlockLatest(ctx, blockIdenti } // PreConfirmedBlockWithIdentifier mocks base method. -func (m *MockFeederReader) PreConfirmedBlockWithIdentifier(ctx context.Context, blockNumber, blockIdentifier string, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, error) { +func (m *MockFeederReader) PreConfirmedBlockWithIdentifier(ctx context.Context, blockNumber string, blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PreConfirmedBlockWithIdentifier", ctx, blockNumber, blockIdentifier, knownTransactionCount) ret0, _ := ret[0].(starknet.PreConfirmedUpdate) diff --git a/mocks/mock_starknetdata.go b/mocks/mock_starknetdata.go index 294f25b484..95b5caca40 100644 --- a/mocks/mock_starknetdata.go +++ b/mocks/mock_starknetdata.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -destination=../mocks/mock_starknetdata.go -package=mocks github.com/NethermindEth/juno/starknetdata StarknetData +// mockgen -destination=mocks/mock_starknetdata.go -package=mocks github.com/NethermindEth/juno/starknetdata StarknetData // // Package mocks is a generated GoMock package. @@ -104,7 +104,7 @@ func (mr *MockStarknetDataMockRecorder) Class(ctx, classHash any) *gomock.Call { } // PreConfirmedBlockByNumber mocks base method. -func (m *MockStarknetData) PreConfirmedBlockByNumber(ctx context.Context, blockNumber uint64, blockIdentifier string, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, error) { +func (m *MockStarknetData) PreConfirmedBlockByNumber(ctx context.Context, blockNumber uint64, blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PreConfirmedBlockByNumber", ctx, blockNumber, blockIdentifier, knownTransactionCount) ret0, _ := ret[0].(starknet.PreConfirmedUpdate) @@ -119,7 +119,7 @@ func (mr *MockStarknetDataMockRecorder) PreConfirmedBlockByNumber(ctx, blockNumb } // PreConfirmedBlockLatest mocks base method. -func (m *MockStarknetData) PreConfirmedBlockLatest(ctx context.Context, blockIdentifier string, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, uint64, error) { +func (m *MockStarknetData) PreConfirmedBlockLatest(ctx context.Context, blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64) (starknet.PreConfirmedUpdate, uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PreConfirmedBlockLatest", ctx, blockIdentifier, knownTransactionCount) ret0, _ := ret[0].(starknet.PreConfirmedUpdate) diff --git a/rpc/rpccore/preconfirmed_deduper.go b/rpc/rpccore/preconfirmed_deduper.go index a722e60ffe..4690e85482 100644 --- a/rpc/rpccore/preconfirmed_deduper.go +++ b/rpc/rpccore/preconfirmed_deduper.go @@ -10,7 +10,7 @@ package rpccore // synchronisation. type PreConfirmedDeduper[K comparable] struct { blockNum uint64 - identifier string + identifier uint64 seen map[K]struct{} } @@ -22,7 +22,7 @@ func NewPreConfirmedDeduper[K comparable]() *PreConfirmedDeduper[K] { // MarkSent records key for the given pre_confirmed round (blockNum + identifier) and // reports whether it was newly added — i.e. whether it should be sent. Advancing to a // different block number or round identifier discards the previous round's keys first. -func (c *PreConfirmedDeduper[K]) MarkSent(blockNum uint64, identifier string, key *K) bool { +func (c *PreConfirmedDeduper[K]) MarkSent(blockNum uint64, identifier uint64, key *K) bool { if blockNum != c.blockNum || identifier != c.identifier { clear(c.seen) c.blockNum = blockNum @@ -39,5 +39,5 @@ func (c *PreConfirmedDeduper[K]) MarkSent(blockNum uint64, identifier string, ke func (c *PreConfirmedDeduper[K]) Clear() { clear(c.seen) c.blockNum = 0 - c.identifier = "" + c.identifier = 0 } diff --git a/rpc/rpccore/preconfirmed_deduper_test.go b/rpc/rpccore/preconfirmed_deduper_test.go index 15f329ccbb..e8d9373125 100644 --- a/rpc/rpccore/preconfirmed_deduper_test.go +++ b/rpc/rpccore/preconfirmed_deduper_test.go @@ -11,7 +11,7 @@ import ( func TestPreConfirmedDeduper(t *testing.T) { key1 := "key1" key2 := "key2" - const id1, id2 = "round-1", "round-2" + const id1, id2 = uint64(1), uint64(2) t.Run("dedups within the same round", func(t *testing.T) { d := rpccore.NewPreConfirmedDeduper[string]() @@ -61,7 +61,7 @@ func TestPreConfirmedDeduper(t *testing.T) { func BenchmarkPreConfirmedDeduper_MarkSent(b *testing.B) { d := rpccore.NewPreConfirmedDeduper[string]() - const id = "round" + const id = uint64(1) b.ReportAllocs() b.ResetTimer() for i := range b.N { diff --git a/rpc/v10/block_test.go b/rpc/v10/block_test.go index e656a6302b..5cce08e884 100644 --- a/rpc/v10/block_test.go +++ b/rpc/v10/block_test.go @@ -654,7 +654,7 @@ func TestBlockTransactionCount(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) preConfirmedID := rpc.BlockIDPreConfirmed() @@ -666,7 +666,7 @@ func TestBlockTransactionCount(t *testing.T) { t.Run("blockID - pre_confirmed multi-block chain returns tip count", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, "") + tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, 0) baseHeader := *latestBlock.Header baseHeader.Number = latestBlock.Number - 1 diff --git a/rpc/v10/events_test.go b/rpc/v10/events_test.go index 59c1a5745a..045410d5c9 100644 --- a/rpc/v10/events_test.go +++ b/rpc/v10/events_test.go @@ -42,7 +42,7 @@ func createEventPreConfirmedFromBlock( Receipts: block.Receipts, } - preConfirmed := pending.NewPreConfirmed(preConfirmedBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(preConfirmedBlock, nil, nil, 0) // Extract events from the block and convert to emitted events var events []rpc.EmittedEvent diff --git a/rpc/v10/state_update_test.go b/rpc/v10/state_update_test.go index 876ac8d293..1781d0c49c 100644 --- a/rpc/v10/state_update_test.go +++ b/rpc/v10/state_update_test.go @@ -160,7 +160,7 @@ func TestStateUpdate(t *testing.T) { t.Run("pre_confirmed", func(t *testing.T) { update3077642.BlockHash = nil update3077642.NewRoot = nil - preConfirmed := pending.NewPreConfirmed(nil, update3077642, nil, "") + preConfirmed := pending.NewPreConfirmed(nil, update3077642, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) preConfirmedID := rpcv10.BlockIDPreConfirmed() update, rpcErr := handler.StateUpdate(&preConfirmedID, nil) @@ -175,8 +175,7 @@ func TestStateUpdate(t *testing.T) { &core.Block{Header: &core.Header{Number: 2}}, baseUpdate, nil, - "", - ) + 0,) tipUpdate := *update3077642 tipUpdate.BlockHash = nil @@ -185,8 +184,7 @@ func TestStateUpdate(t *testing.T) { &core.Block{Header: &core.Header{Number: 3}}, &tipUpdate, nil, - "", - ) + 0,) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &basePc, &tipPc), nil) preConfirmedID := rpcv10.BlockIDPreConfirmed() @@ -227,7 +225,7 @@ func TestStateUpdate(t *testing.T) { }) t.Run("empty filter returns full state diff", func(t *testing.T) { - preConfirmed := pending.NewPreConfirmed(nil, update3077642, nil, "") + preConfirmed := pending.NewPreConfirmed(nil, update3077642, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) id := rpcv10.BlockIDPreConfirmed() emptyFilter := rpcv10.AddressList{} diff --git a/rpc/v10/trace_test.go b/rpc/v10/trace_test.go index 3f5fac049a..e233616696 100644 --- a/rpc/v10/trace_test.go +++ b/rpc/v10/trace_test.go @@ -333,7 +333,7 @@ func TestTraceTransaction(t *testing.T) { hash := felt.NewUnsafeFromString[felt.Felt]("0xBBBB") // Receipt() returns error related to db mockReader.EXPECT().Receipt(hash).Return(nil, nil, uint64(0), db.ErrKeyNotFound) - preConfirmed := pending.NewPreConfirmed(&core.Block{}, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(&core.Block{}, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) trace, httpHeader, err := handler.TraceTransaction(t.Context(), hash) diff --git a/rpc/v10/transaction_test.go b/rpc/v10/transaction_test.go index af6456bbf8..c93b76fd38 100644 --- a/rpc/v10/transaction_test.go +++ b/rpc/v10/transaction_test.go @@ -600,7 +600,7 @@ func TestTransactionByHash_PreConfirmedBlock(t *testing.T) { blockNumber := uint64(11252240) update, err := gw.PreConfirmedBlockWithIdentifier( t.Context(), - strconv.FormatUint(blockNumber, 10), "", 0, + strconv.FormatUint(blockNumber, 10), 0, 0, ) require.NoError(t, err) preConfirmedFull := update.(starknet.PreConfirmedBlock) @@ -642,7 +642,7 @@ func TestTransactionByHash_MultiplePreConfirmed(t *testing.T) { hashes[i] = hash emptySlice := []*felt.Felt{} block := starknet.PreConfirmedBlock{ - BlockIdentifier: fmt.Sprintf("round-%d", blockNumber), + BlockIdentifier: starknet.BlockIdentifier(blockNumber), Status: "PRE_CONFIRMED", Timestamp: 1, Version: core.Ver0_14_0.String(), @@ -715,7 +715,7 @@ func TestTransactionByBlockIDAndIndex_PreConfirmedMultiBlockChain(t *testing.T) baseHeader.Number = latestBlock.Number - 1 baseHeader.TransactionCount = 0 baseEntry := pending.PreConfirmed{Block: &core.Block{Header: &baseHeader}} - tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, "") + tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain(). Return(mustNewChain(t, &baseEntry, &tipEntry), nil) @@ -892,7 +892,7 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil).Times(2) blockID := rpc.BlockIDPreConfirmed() diff --git a/rpc/v8/subscriptions_test.go b/rpc/v8/subscriptions_test.go index 803eff6e74..843512873c 100644 --- a/rpc/v8/subscriptions_test.go +++ b/rpc/v8/subscriptions_test.go @@ -255,12 +255,12 @@ func TestSubscribeEvents(t *testing.T) { // Sending PreConfirmed does nothing — the handler was removed // because it only handled the deprecated pending.Pending variant. pending1 := createTestPendingBlock(t, b2, 3) - preConfirmed1 := pendingpkg.NewPreConfirmed(pending1, nil, nil, "") + preConfirmed1 := pendingpkg.NewPreConfirmed(pending1, nil, nil, 0) handler.preConfirmedFeed.Send(&preConfirmed1) assertNoMessage(t, clientConn) pending2 := createTestPendingBlock(t, b2, 6) - preConfirmed2 := pendingpkg.NewPreConfirmed(pending2, nil, nil, "") + preConfirmed2 := pendingpkg.NewPreConfirmed(pending2, nil, nil, 0) handler.preConfirmedFeed.Send(&preConfirmed2) assertNoMessage(t, clientConn) diff --git a/rpc/v9/block_test.go b/rpc/v9/block_test.go index 2033f3f283..695d595a3d 100644 --- a/rpc/v9/block_test.go +++ b/rpc/v9/block_test.go @@ -273,7 +273,7 @@ func TestBlockTransactionCount(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) preConfirmedID := blockIDPreConfirmed(t) @@ -455,7 +455,7 @@ func TestBlockWithTxHashes(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil).Times(2) mockReader.EXPECT().L1Head().Return(core.L1Head{}, db.ErrKeyNotFound) @@ -726,7 +726,7 @@ func TestBlockWithTxs(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT(). PreConfirmedChain(). Return(mustNewChain(t, &preConfirmed), nil). @@ -751,7 +751,7 @@ func TestBlockWithTxs(t *testing.T) { mockSyncReader := mocks.NewMockSyncReader(mockCtrl) handler := rpc.New(mockReader, mockSyncReader, nil, nil) - tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, "") + tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, 0) baseHeader := *latestBlock.Header baseHeader.Number = latestBlock.Number - 1 @@ -951,7 +951,7 @@ func TestBlockWithReceipts(t *testing.T) { block0.Hash = nil block0.ParentHash = nil block0.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(block0, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(block0, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) mockReader.EXPECT().L1Head().Return(core.L1Head{}, nil) diff --git a/rpc/v9/events_test.go b/rpc/v9/events_test.go index bac1a2e0d1..87f0eb88b9 100644 --- a/rpc/v9/events_test.go +++ b/rpc/v9/events_test.go @@ -40,7 +40,7 @@ func createEventPreConfirmedFromBlock(block *core.Block) ( Receipts: block.Receipts, } - preConfirmed := pending.NewPreConfirmed(preConfirmedBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(preConfirmedBlock, nil, nil, 0) // Extract events from the block and convert to emitted events var events []rpc.EmittedEvent diff --git a/rpc/v9/state_update_test.go b/rpc/v9/state_update_test.go index 59b18e07fb..3896b83b29 100644 --- a/rpc/v9/state_update_test.go +++ b/rpc/v9/state_update_test.go @@ -192,7 +192,7 @@ func TestStateUpdate(t *testing.T) { t.Run("pre_confirmed", func(t *testing.T) { update21656.BlockHash = nil update21656.NewRoot = nil - preConfirmed := pending.NewPreConfirmed(nil, update21656, nil, "") + preConfirmed := pending.NewPreConfirmed(nil, update21656, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) preConfirmedID := blockIDPreConfirmed(t) update, rpcErr := handler.StateUpdate(&preConfirmedID) @@ -207,8 +207,7 @@ func TestStateUpdate(t *testing.T) { &core.Block{Header: &core.Header{Number: 2}}, baseUpdate, nil, - "", - ) + 0,) tipUpdate := *update21656 tipUpdate.BlockHash = nil @@ -217,8 +216,7 @@ func TestStateUpdate(t *testing.T) { &core.Block{Header: &core.Header{Number: 3}}, &tipUpdate, nil, - "", - ) + 0,) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &basePc, &tipPc), nil) preConfirmedID := blockIDPreConfirmed(t) diff --git a/rpc/v9/trace_test.go b/rpc/v9/trace_test.go index 3e02b05dd7..3acdefddfa 100644 --- a/rpc/v9/trace_test.go +++ b/rpc/v9/trace_test.go @@ -338,7 +338,7 @@ func TestTraceTransaction(t *testing.T) { hash := felt.NewUnsafeFromString[felt.Felt]("0xBBBB") // Receipt() returns error related to db mockReader.EXPECT().Receipt(hash).Return(nil, nil, uint64(0), db.ErrKeyNotFound) - preConfirmed := pending.NewPreConfirmed(&core.Block{}, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(&core.Block{}, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil) trace, httpHeader, err := handler.TraceTransaction(t.Context(), hash) diff --git a/rpc/v9/transaction_test.go b/rpc/v9/transaction_test.go index 57ab8a1b5d..4a0106f57d 100644 --- a/rpc/v9/transaction_test.go +++ b/rpc/v9/transaction_test.go @@ -479,7 +479,7 @@ func TestTransactionByHash_PreConfirmedBlock(t *testing.T) { mockSyncReader := mocks.NewMockSyncReader(mockCtrl) blockNumber := uint64(11252240) update, err := gw.PreConfirmedBlockWithIdentifier( - t.Context(), strconv.FormatUint(blockNumber, 10), "", 0, + t.Context(), strconv.FormatUint(blockNumber, 10), 0, 0, ) require.NoError(t, err) preConfirmedFull := update.(starknet.PreConfirmedBlock) @@ -516,7 +516,7 @@ func TestTransactionByHash_MultiplePreConfirmed(t *testing.T) { hashes[i] = hash emptySlice := []*felt.Felt{} block := starknet.PreConfirmedBlock{ - BlockIdentifier: fmt.Sprintf("round-%d", blockNumber), + BlockIdentifier: starknet.BlockIdentifier(blockNumber), Status: "PRE_CONFIRMED", Timestamp: 1, Version: core.Ver0_14_0.String(), @@ -588,7 +588,7 @@ func TestTransactionByBlockIDAndIndex_PreConfirmedMultiBlockChain(t *testing.T) baseHeader.Number = latestBlock.Number - 1 baseHeader.TransactionCount = 0 baseEntry := pending.PreConfirmed{Block: &core.Block{Header: &baseHeader}} - tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, "") + tipEntry := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain(). Return(mustNewChain(t, &baseEntry, &tipEntry), nil) @@ -759,7 +759,7 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { t.Run("blockID - pre_confirmed", func(t *testing.T) { latestBlock.Hash = nil latestBlock.GlobalStateRoot = nil - preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, "") + preConfirmed := pending.NewPreConfirmed(latestBlock, nil, nil, 0) mockSyncReader.EXPECT().PreConfirmedChain().Return(mustNewChain(t, &preConfirmed), nil).Times(2) blockID := blockIDPreConfirmed(t) @@ -1867,7 +1867,7 @@ func TestTransactionStatus(t *testing.T) { sepoliaIntClient := feeder.NewTestClient(t, network) sepoliaIntGw := adaptfeeder.New(sepoliaIntClient) blockNumber := uint64(11252240) - update, gwErr := sepoliaIntGw.PreConfirmedBlockByNumber(t.Context(), blockNumber, "", 0) + update, gwErr := sepoliaIntGw.PreConfirmedBlockByNumber(t.Context(), blockNumber, 0, 0) require.NoError(t, gwErr) full, ok := update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", update) diff --git a/sequencer/sequencer.go b/sequencer/sequencer.go index 11dcb383b9..ea2075fa78 100644 --- a/sequencer/sequencer.go +++ b/sequencer/sequencer.go @@ -159,7 +159,7 @@ func (s *Sequencer) listenPool(ctx context.Context) error { } // push the preconfirmed block to the feed - preconfirmed := pending.NewPreConfirmed(s.buildState.PreConfirmedBlock(), nil, nil, "") + preconfirmed := pending.NewPreConfirmed(s.buildState.PreConfirmedBlock(), nil, nil, 0) s.subPreConfirmed.Send(&preconfirmed) select { case <-ctx.Done(): diff --git a/starknet/pre_confirmed_update.go b/starknet/pre_confirmed_update.go index 15f6ae47c4..fd64c665e9 100644 --- a/starknet/pre_confirmed_update.go +++ b/starknet/pre_confirmed_update.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" "io" + "strconv" + "strings" "github.com/NethermindEth/juno/core/felt" ) @@ -18,6 +20,32 @@ type PreConfirmedUpdate interface { isPreConfirmedUpdate() } +type BlockIdentifier uint64 + +func (b *BlockIdentifier) UnmarshalJSON(data []byte) error { + // Handle quoted string like "0x1676efd0" + if len(data) > 0 && data[0] == '"' { + var str string + if err := json.Unmarshal(data, &str); err != nil { + return err + } + str = strings.TrimPrefix(str, "0x") + val, err := strconv.ParseUint(str, 16, 64) + if err != nil { + return err + } + *b = BlockIdentifier(val) + return nil + } + // Handle bare integer like 123 + var val uint64 + if err := json.Unmarshal(data, &val); err != nil { + return err + } + *b = BlockIdentifier(val) + return nil +} + // PreConfirmedNoChange means the server's pre_confirmed matches what the caller already has. type PreConfirmedNoChange struct{} @@ -26,7 +54,7 @@ func (PreConfirmedNoChange) isPreConfirmedUpdate() {} // PreConfirmedDeltaUpdate carries transactions/receipts/state diffs appended since the // caller's known transaction count for the same block_identifier. type PreConfirmedDeltaUpdate struct { - BlockIdentifier string `json:"block_identifier"` + BlockIdentifier BlockIdentifier `json:"block_identifier"` Transactions []Transaction `json:"transactions"` Receipts []*TransactionReceipt `json:"transaction_receipts"` TransactionStateDiffs []*StateDiff `json:"transaction_state_diffs"` @@ -35,7 +63,7 @@ type PreConfirmedDeltaUpdate struct { func (PreConfirmedDeltaUpdate) isPreConfirmedUpdate() {} func (val *PreConfirmedDeltaUpdate) validate() error { - if val.BlockIdentifier == "" { + if val.BlockIdentifier == 0 { return errors.New("block_identifier is required") } if len(val.Transactions) == 0 { @@ -49,7 +77,7 @@ func (val *PreConfirmedDeltaUpdate) validate() error { // PreConfirmedBlock carries a full pre_confirmed block for a new round. type PreConfirmedBlock struct { - BlockIdentifier string `json:"block_identifier"` + BlockIdentifier BlockIdentifier `json:"block_identifier"` Transactions []Transaction `json:"transactions"` Receipts []*TransactionReceipt `json:"transaction_receipts"` TransactionStateDiffs []*StateDiff `json:"transaction_state_diffs"` @@ -66,7 +94,7 @@ type PreConfirmedBlock struct { func (PreConfirmedBlock) isPreConfirmedUpdate() {} func (pb *PreConfirmedBlock) validate() error { - if pb.BlockIdentifier == "" { + if pb.BlockIdentifier == 0 { return errors.New("block_identifier is required") } if pb.Status != "PRE_CONFIRMED" { @@ -145,42 +173,57 @@ type PreConfirmedUpdateEnvelope struct { // DecodePreConfirmedUpdate decodes a "get_preconfirmed_block" response and // discriminates it into a [PreConfirmedUpdateEnvelope]. func DecodePreConfirmedUpdate(r io.Reader) (PreConfirmedUpdateEnvelope, error) { - // preConfirmedWire is the flat shape the decoder fills. Discrimination is structural: - // - "changed": false → NoChange - // - "changed": true + "timestamp" → Full block (new round) - // - "changed": true, no "timestamp" → Delta - type preConfirmedWire struct { + data, err := io.ReadAll(r) + if err != nil { + return PreConfirmedUpdateEnvelope{}, err + } + + // The discriminator is decoded on its own first: a NoChange response is + // identified purely by "changed": false, and any other field must be + // ignored even if malformed, so the full payload is only decoded once + // changed is known to be true. + var discriminator struct { Changed *bool `json:"changed"` BlockNumber *uint64 `json:"block_number"` - PreConfirmedBlock } - - var raw preConfirmedWire - if err := json.NewDecoder(r).Decode(&raw); err != nil { + if err := json.Unmarshal(data, &discriminator); err != nil { return PreConfirmedUpdateEnvelope{}, err } - if raw.Changed == nil { + if discriminator.Changed == nil { return PreConfirmedUpdateEnvelope{}, errors.New( "missing required \"changed\" field", ) } var env PreConfirmedUpdateEnvelope - if raw.BlockNumber != nil { - env.BlockNumber = *raw.BlockNumber + if discriminator.BlockNumber != nil { + env.BlockNumber = *discriminator.BlockNumber } - switch { - case !*raw.Changed: + if !*discriminator.Changed { env.Update = PreConfirmedNoChange{} - case raw.Timestamp != 0: - env.Update = raw.PreConfirmedBlock + return env, nil + } + + // Discrimination between Full (new round) and Delta is structural: + // - "timestamp" present → Full block (new round) + // - "timestamp" absent → Delta + var body struct { + PreConfirmedBlock + } + if err := json.Unmarshal(data, &body); err != nil { + return PreConfirmedUpdateEnvelope{}, err + } + + switch { + case body.Timestamp != 0: + env.Update = body.PreConfirmedBlock default: env.Update = PreConfirmedDeltaUpdate{ - BlockIdentifier: raw.BlockIdentifier, - Transactions: raw.Transactions, - Receipts: raw.Receipts, - TransactionStateDiffs: raw.TransactionStateDiffs, + BlockIdentifier: body.BlockIdentifier, + Transactions: body.Transactions, + Receipts: body.Receipts, + TransactionStateDiffs: body.TransactionStateDiffs, } } return env, nil diff --git a/starknet/pre_confirmed_update_test.go b/starknet/pre_confirmed_update_test.go index e8d1d0ec71..98e68ccb8d 100644 --- a/starknet/pre_confirmed_update_test.go +++ b/starknet/pre_confirmed_update_test.go @@ -35,7 +35,7 @@ func TestDecodePreConfirmedUpdate(t *testing.T) { full, ok := env.Update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", env.Update) - assert.Equal(t, "0x1cbe25d9", full.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1cbe25d9), full.BlockIdentifier) assert.Equal(t, "PRE_CONFIRMED", full.Status) assert.Equal(t, "0.14.2", full.Version) assert.NotZero(t, full.Timestamp) @@ -56,7 +56,7 @@ func TestDecodePreConfirmedUpdate(t *testing.T) { delta, ok := env.Update.(starknet.PreConfirmedDeltaUpdate) require.True(t, ok, "expected PreConfirmedDeltaUpdate, got %T", env.Update) - assert.Equal(t, "0x1cbe25d9", delta.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1cbe25d9), delta.BlockIdentifier) assert.Len(t, delta.Transactions, 1) assert.Len(t, delta.Receipts, 1) assert.Len(t, delta.TransactionStateDiffs, 1) @@ -88,7 +88,7 @@ func TestDecodePreConfirmedUpdate(t *testing.T) { full, ok := env.Update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", env.Update) - assert.Equal(t, "0x1857317c", full.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1857317c), full.BlockIdentifier) assert.Equal(t, "PRE_CONFIRMED", full.Status) assert.Equal(t, "0.14.2", full.Version) assert.NotZero(t, full.Timestamp) @@ -107,7 +107,7 @@ func TestDecodePreConfirmedUpdate(t *testing.T) { delta, ok := env.Update.(starknet.PreConfirmedDeltaUpdate) require.True(t, ok, "expected PreConfirmedDeltaUpdate, got %T", env.Update) - assert.Equal(t, "0x1857317c", delta.BlockIdentifier) + assert.Equal(t, starknet.BlockIdentifier(0x1857317c), delta.BlockIdentifier) }) t.Run("NoChange decodes when nothing was appended", func(t *testing.T) { @@ -158,7 +158,7 @@ func TestDecodePreConfirmedUpdate(t *testing.T) { }) t.Run("invalid Delta payload returns error", func(t *testing.T) { - raw := []byte(`{"changed": true, "block_identifier": 7}`) + raw := []byte(`{"changed": true, "block_identifier": {}}`) _, err := starknet.DecodePreConfirmedUpdate(bytes.NewReader(raw)) require.Error(t, err) }) @@ -173,7 +173,7 @@ func nonEmptyTx() starknet.Transaction { // tests can flip a single field to exercise one failure path at a time. func validBlock() starknet.PreConfirmedBlock { return starknet.PreConfirmedBlock{ - BlockIdentifier: "abc123", + BlockIdentifier: 123, Timestamp: 1234567890, Transactions: []starknet.Transaction{nonEmptyTx()}, Receipts: []*starknet.TransactionReceipt{{}}, @@ -190,7 +190,7 @@ func validBlock() starknet.PreConfirmedBlock { // validDelta returns a PreConfirmedDeltaUpdate that passes validate(). func validDelta() starknet.PreConfirmedDeltaUpdate { return starknet.PreConfirmedDeltaUpdate{ - BlockIdentifier: "abc123", + BlockIdentifier: 123, Transactions: []starknet.Transaction{nonEmptyTx()}, Receipts: []*starknet.TransactionReceipt{{}}, TransactionStateDiffs: []*starknet.StateDiff{{}}, @@ -253,7 +253,7 @@ func TestPreConfirmedBlock_validate(t *testing.T) { }, { name: "missing block_identifier", - mutate: func(b *starknet.PreConfirmedBlock) { b.BlockIdentifier = "" }, + mutate: func(b *starknet.PreConfirmedBlock) { b.BlockIdentifier = 0 }, wantErr: true, }, { @@ -348,7 +348,7 @@ func TestPreConfirmedDeltaUpdate_validate(t *testing.T) { }, { name: "missing block_identifier", - mutate: func(d *starknet.PreConfirmedDeltaUpdate) { d.BlockIdentifier = "" }, + mutate: func(d *starknet.PreConfirmedDeltaUpdate) { d.BlockIdentifier = 0 }, wantErr: true, }, { diff --git a/starknetdata/feeder/feeder.go b/starknetdata/feeder/feeder.go index fd0ed39cf6..437cffff8e 100644 --- a/starknetdata/feeder/feeder.go +++ b/starknetdata/feeder/feeder.go @@ -165,7 +165,7 @@ func (f *Feeder) StateUpdateWithBlock( func (f *Feeder) PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) { return f.client.PreConfirmedBlockWithIdentifier( @@ -181,7 +181,7 @@ func (f *Feeder) PreConfirmedBlockByNumber( // The returned block number is the height the response describes. func (f *Feeder) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) { return f.client.PreConfirmedBlockLatest(ctx, blockIdentifier, knownTransactionCount) diff --git a/starknetdata/feeder/feeder_test.go b/starknetdata/feeder/feeder_test.go index 944ebb63b8..97f7b9c7dc 100644 --- a/starknetdata/feeder/feeder_test.go +++ b/starknetdata/feeder/feeder_test.go @@ -300,7 +300,7 @@ func TestAdapterErrorPaths(t *testing.T) { }) t.Run("PreConfirmedBlockByNumber error", func(t *testing.T) { - preConfirmed, err := adapter.PreConfirmedBlockByNumber(ctx, missing, "", 0) + preConfirmed, err := adapter.PreConfirmedBlockByNumber(ctx, missing, 0, 0) assert.Zero(t, preConfirmed) assert.Error(t, err) }) @@ -326,7 +326,7 @@ func TestPreConfirmedBlock(t *testing.T) { ctx := t.Context() blockNumber := uint64(11252240) - update, err := adapter.PreConfirmedBlockByNumber(ctx, blockNumber, "", 0) + update, err := adapter.PreConfirmedBlockByNumber(ctx, blockNumber, 0, 0) require.NoError(t, err) full, ok := update.(starknet.PreConfirmedBlock) require.True(t, ok, "expected PreConfirmedBlock, got %T", update) diff --git a/starknetdata/starknetdata.go b/starknetdata/starknetdata.go index 8004c1854c..a417169375 100644 --- a/starknetdata/starknetdata.go +++ b/starknetdata/starknetdata.go @@ -23,12 +23,12 @@ type StarknetData interface { PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) } diff --git a/sync/data_source.go b/sync/data_source.go index f437cc6547..ded5a867b1 100644 --- a/sync/data_source.go +++ b/sync/data_source.go @@ -25,12 +25,12 @@ type DataSource interface { PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) } @@ -132,7 +132,7 @@ func (f *feederGatewayDataSource) fetchUnknownClasses( func (f *feederGatewayDataSource) PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) { return f.starknetData.PreConfirmedBlockByNumber( @@ -145,7 +145,7 @@ func (f *feederGatewayDataSource) PreConfirmedBlockByNumber( func (f *feederGatewayDataSource) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) { return f.starknetData.PreConfirmedBlockLatest(ctx, blockIdentifier, knownTransactionCount) diff --git a/sync/helpers.go b/sync/helpers.go index 209482e283..b48f1c1ef9 100644 --- a/sync/helpers.go +++ b/sync/helpers.go @@ -114,7 +114,7 @@ func MakeEmptyPreConfirmedForParent( }, NewClasses: make(map[felt.Felt]core.ClassDefinition, 0), TransactionStateDiffs: make([]*core.StateDiff, 0), - BlockIdentifier: feeder.PreConfirmedBlankIdentifier, + BlockIdentifier: uint64(feeder.PreConfirmedBlankIdentifier), } return preConfirmed, nil diff --git a/sync/preconfirmed/chain_storage.go b/sync/preconfirmed/chain_storage.go index 94ba540a15..d620efd6fc 100644 --- a/sync/preconfirmed/chain_storage.go +++ b/sync/preconfirmed/chain_storage.go @@ -583,7 +583,7 @@ func validBottomForHead(bottom uint64, head *core.Header) bool { // same-identifier block replaces. func shouldPreserveSlot(existing, incoming *pending.PreConfirmed) bool { if incoming.BlockIdentifier != existing.BlockIdentifier && - incoming.BlockIdentifier != feeder.PreConfirmedBlankIdentifier { + incoming.BlockIdentifier != uint64(feeder.PreConfirmedBlankIdentifier) { return false } if incoming.Block.TransactionCount > existing.Block.TransactionCount { diff --git a/sync/preconfirmed/chain_storage_test.go b/sync/preconfirmed/chain_storage_test.go index b27eda1719..bdc5d815b6 100644 --- a/sync/preconfirmed/chain_storage_test.go +++ b/sync/preconfirmed/chain_storage_test.go @@ -2,7 +2,6 @@ package preconfirmed_test import ( "errors" - "fmt" "testing" "time" @@ -22,10 +21,14 @@ import ( func headAt(n uint64) *core.Header { return &core.Header{Number: n} } // roundID is the per-slot identifier convention used across the storage -// tests: slot N's block carries identifier "round-N", so each slot in a -// chain is structurally distinguishable from every other (and a slot-mixup -// bug would surface as an identifier mismatch in assertChain). -func roundID(slot uint64) string { return fmt.Sprintf("round-%d", slot) } +// tests: slot N's block carries identifier N, so each slot in a chain is +// structurally distinguishable from every other (and a slot-mixup bug +// would surface as an identifier mismatch in assertChain). +func roundID(slot uint64) starknet.BlockIdentifier { return starknet.BlockIdentifier(slot) } + +// altRoundID returns an identifier distinct from roundID(slot), used to +// simulate a new round replacing the previous one at the same slot. +func altRoundID(slot uint64) starknet.BlockIdentifier { return starknet.BlockIdentifier(slot + 1_000_000) } // chainBlockNumbers collects block numbers in oldest-first order. Used where // the test cares about ordering / contiguity rather than per-slot identity @@ -46,7 +49,7 @@ func chainBlockNumbers(c *preconfirmed.ChainReader) []uint64 { func applyBlock( t *testing.T, s *preconfirmed.ChainStorage, - identifier string, + identifier starknet.BlockIdentifier, txCount int, number uint64, head *core.Header, @@ -232,7 +235,7 @@ func testApplyUpdateReplaceTipNewRound(t *testing.T) { before := s.SnapshotForHead(head) // Different identifier at slot 2 → new round replaces. - bNew := applyBlock(t, s, "round-2-alt", 0, 2, head) + bNew := applyBlock(t, s, altRoundID(2), 0, 2, head) after := s.SnapshotForHead(head) require.NotSame(t, before.Head(), after.Head()) assertChain(t, &after, entry(1, &b1), entry(2, &bNew)) @@ -259,7 +262,7 @@ func testApplyUpdateReorgNonTipTruncates(t *testing.T) { applyBlock(t, s, roundID(3), 0, 3, head) // New round at non-tip slot 2 → slot 3 is truncated. - bReorg := applyBlock(t, s, "round-2-alt", 5, 2, head) + bReorg := applyBlock(t, s, altRoundID(2), 5, 2, head) view := s.SnapshotForHead(head) assertChain(t, &view, entry(1, &b1), entry(2, &bReorg)) } @@ -272,7 +275,7 @@ func testApplyUpdateReorgBottomTruncates(t *testing.T) { } // Reorg at slot 1 (bottom) with a new round — everything above truncated. - bReorg := applyBlock(t, s, "round-1-alt", 2, 1, head) + bReorg := applyBlock(t, s, altRoundID(1), 2, 1, head) view := s.SnapshotForHead(head) assertChain(t, &view, entry(1, &bReorg)) } @@ -285,13 +288,13 @@ func testApplyUpdateReorgReExtend(t *testing.T) { applyBlock(t, s, roundID(3), 0, 3, head) // will be truncated // Reorg at slot 2. - b2Alt := applyBlock(t, s, "round-2-alt", 1, 2, head) + b2Alt := applyBlock(t, s, altRoundID(2), 1, 2, head) view := s.SnapshotForHead(head) assertChain(t, &view, entry(1, &b1), entry(2, &b2Alt)) // Re-extend slots 3 and 4 with new rounds. - b3Alt := applyBlock(t, s, "round-3-alt", 0, 3, head) - b4Alt := applyBlock(t, s, "round-4-alt", 0, 4, head) + b3Alt := applyBlock(t, s, altRoundID(3), 0, 3, head) + b4Alt := applyBlock(t, s, altRoundID(4), 0, 4, head) view2 := s.SnapshotForHead(head) assertChain(t, &view2, entry(1, &b1), @@ -311,7 +314,7 @@ func testApplyUpdateReorgSequential(t *testing.T) { applyBlock(t, s, roundID(5), 0, 5, head) // First reorg at slot 4. - b4Alt := applyBlock(t, s, "round-4-alt", 0, 4, head) + b4Alt := applyBlock(t, s, altRoundID(4), 0, 4, head) view := s.SnapshotForHead(head) assertChain(t, &view, entry(1, &b1), @@ -321,7 +324,7 @@ func testApplyUpdateReorgSequential(t *testing.T) { ) // Re-extend slot 5 with a new round. - b5Alt := applyBlock(t, s, "round-5-alt", 0, 5, head) + b5Alt := applyBlock(t, s, altRoundID(5), 0, 5, head) view2 := s.SnapshotForHead(head) assertChain(t, &view2, entry(1, &b1), @@ -332,7 +335,7 @@ func testApplyUpdateReorgSequential(t *testing.T) { ) // Second reorg at slot 3 — truncates everything above. - b3Alt := applyBlock(t, s, "round-3-alt", 0, 3, head) + b3Alt := applyBlock(t, s, altRoundID(3), 0, 3, head) view3 := s.SnapshotForHead(head) assertChain(t, &view3, entry(1, &b1), @@ -352,7 +355,7 @@ func testApplyUpdateReorgPreSnapshotIntact(t *testing.T) { pre := s.SnapshotForHead(head) // Reorg at slot 2 — slots 3 and 4 truncated in the live chain. - b2Alt := applyBlock(t, s, "round-2-alt", 0, 2, head) + b2Alt := applyBlock(t, s, altRoundID(2), 0, 2, head) view := s.SnapshotForHead(head) assertChain(t, &view, entry(1, &original[0]), entry(2, &b2Alt)) @@ -364,7 +367,7 @@ func testApplyUpdateDeltaAtTip(t *testing.T) { head := headAt(0) s := preconfirmed.NewChainStorage() // Delta and seed MUST share an identifier for the merge to be valid. - const round = "round-1" + const round = starknet.BlockIdentifier(1) seed := applyBlock(t, s, round, 2, 1, head) delta := makeTestDelta(round, 3) @@ -379,7 +382,7 @@ func testApplyUpdateDeltaAtTip(t *testing.T) { func testApplyUpdateDeltaAtNonTipRejected(t *testing.T) { head := headAt(0) s := preconfirmed.NewChainStorage() - const slot1Round = "round-1" + const slot1Round = starknet.BlockIdentifier(1) applyBlock(t, s, slot1Round, 1, 1, head) applyBlock(t, s, roundID(2), 0, 2, head) applyBlock(t, s, roundID(3), 0, 3, head) @@ -396,7 +399,7 @@ func testApplyUpdateDeltaAtNonTipRejected(t *testing.T) { func testApplyUpdateDeltaWrongBaseTxCount(t *testing.T) { head := headAt(0) s := preconfirmed.NewChainStorage() - const round = "round-1" + const round = starknet.BlockIdentifier(1) seed := applyBlock(t, s, round, 2, 1, head) before := s.SnapshotForHead(head) @@ -412,10 +415,10 @@ func testApplyUpdateDeltaWrongBaseTxCount(t *testing.T) { func testApplyUpdateDeltaIdentifierMismatch(t *testing.T) { head := headAt(0) s := preconfirmed.NewChainStorage() - seed := applyBlock(t, s, "round-1", 1, 1, head) + seed := applyBlock(t, s, roundID(1), 1, 1, head) before := s.SnapshotForHead(head) - delta := makeTestDelta("round-1-different", 1) + delta := makeTestDelta(altRoundID(1), 1) _, err := s.ApplyUpdate(delta, 1, 1, head) require.Error(t, err) after := s.SnapshotForHead(head) @@ -735,7 +738,7 @@ type storageWrite struct { func applyBlockWithStorageWrites( t *testing.T, s *preconfirmed.ChainStorage, - identifier string, + identifier starknet.BlockIdentifier, contract *felt.Felt, writes []storageWrite, number uint64, diff --git a/sync/preconfirmed/poller.go b/sync/preconfirmed/poller.go index b96d319f33..22f8387694 100644 --- a/sync/preconfirmed/poller.go +++ b/sync/preconfirmed/poller.go @@ -22,13 +22,13 @@ import ( type DataSource interface { PreConfirmedBlockLatest( ctx context.Context, - identifier string, + identifier starknet.BlockIdentifier, txCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - identifier string, + identifier starknet.BlockIdentifier, txCount uint64, ) (starknet.PreConfirmedUpdate, error) } @@ -107,7 +107,7 @@ func (p *Poller) tick(ctx context.Context) error { chain := p.storage.SnapshotForHead(head) var ( mostRecent *pending.PreConfirmed - identifier string + identifier starknet.BlockIdentifier txCount uint64 ) fromBlock := headPlusOne(head) @@ -115,7 +115,7 @@ func (p *Poller) tick(ctx context.Context) error { if chain.Length() > 0 { if mostRecent = chain.Head(); mostRecent != nil { fromBlock = mostRecent.Block.Number - identifier = mostRecent.BlockIdentifier + identifier = starknet.BlockIdentifier(mostRecent.BlockIdentifier) txCount = uint64(len(mostRecent.Block.Transactions)) } } @@ -163,7 +163,7 @@ func (p *Poller) backfill( ctx context.Context, head *core.Header, fromBlockNum uint64, - identifier string, + identifier starknet.BlockIdentifier, txCount uint64, endExclusive uint64, ) error { @@ -177,7 +177,7 @@ func (p *Poller) backfill( } for n := fromBlockNum + 1; n < endExclusive; n++ { - update, err := p.dataSource.PreConfirmedBlockByNumber(ctx, n, "", 0) + update, err := p.dataSource.PreConfirmedBlockByNumber(ctx, n, 0, 0) if err != nil { return fmt.Errorf("polling pre-confirmed for number %d: %w", n, err) } diff --git a/sync/preconfirmed/poller_test.go b/sync/preconfirmed/poller_test.go index a2787f3f5b..54b64f3064 100644 --- a/sync/preconfirmed/poller_test.go +++ b/sync/preconfirmed/poller_test.go @@ -31,7 +31,7 @@ const tickInterval = 100 * time.Millisecond // makeTestPreConfirmedBlock returns a starknet.PreConfirmedBlock carrying // `txCount` synthesised invoke transactions with matching receipts and per-tx // state diffs. -func makeTestPreConfirmedBlock(identifier string, txCount int) starknet.PreConfirmedBlock { +func makeTestPreConfirmedBlock(identifier starknet.BlockIdentifier, txCount int) starknet.PreConfirmedBlock { txs := make([]starknet.Transaction, txCount) receipts := make([]*starknet.TransactionReceipt, txCount) stateDiffs := make([]*starknet.StateDiff, txCount) @@ -76,7 +76,7 @@ func makeTestPreConfirmedBlock(identifier string, txCount int) starknet.PreConfi // makeTestDelta returns a PreConfirmedDeltaUpdate that appends `addedCount` // transactions/receipts/state diffs under the given block identifier. -func makeTestDelta(identifier string, addedCount int) starknet.PreConfirmedDeltaUpdate { +func makeTestDelta(identifier starknet.BlockIdentifier, addedCount int) starknet.PreConfirmedDeltaUpdate { txs := make([]starknet.Transaction, addedCount) receipts := make([]*starknet.TransactionReceipt, addedCount) stateDiffs := make([]*starknet.StateDiff, addedCount) @@ -101,6 +101,17 @@ func makeTestDelta(identifier string, addedCount int) starknet.PreConfirmedDelta } } +// r0..r4 and rZ are opaque round identifiers used across poller tests to +// distinguish rounds; only their distinctness from one another matters. +const ( + r0 = starknet.BlockIdentifier(100) + r1 = starknet.BlockIdentifier(101) + r2 = starknet.BlockIdentifier(102) + r3 = starknet.BlockIdentifier(103) + r4 = starknet.BlockIdentifier(104) + rZ = starknet.BlockIdentifier(999) +) + type chainFixture struct { bc *blockchain.Blockchain db db.KeyValueStore @@ -179,7 +190,7 @@ func wirePoller( // assertChain to pin down the full storage state after a tick. type expectedEntry struct { number uint64 - identifier string + identifier uint64 txCount int } @@ -196,7 +207,7 @@ func entry( for _, d := range deltas { txCount += len(d.Transactions) } - return expectedEntry{number, block.BlockIdentifier, txCount} + return expectedEntry{number, uint64(block.BlockIdentifier), txCount} } // assertChain pins down a snapshot's full contents in oldest-first order. @@ -221,11 +232,11 @@ func TestPollerColdBootstrapNoGap(t *testing.T) { t.Parallel() fx := newChainFixture(t) - block1 := makeTestPreConfirmedBlock("r0", 1) + block1 := makeTestPreConfirmedBlock(r0, 1) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), starknet.BlockIdentifier(0), uint64(0)). Return(block1, uint64(1), nil) synctest.Test(t, func(t *testing.T) { @@ -246,9 +257,9 @@ func TestPollerColdBootstrapWithGap(t *testing.T) { t.Parallel() fx := newChainFixture(t) - block1 := makeTestPreConfirmedBlock("r1", 0) - block2 := makeTestPreConfirmedBlock("r2", 0) - block3 := makeTestPreConfirmedBlock("r3", 0) + block1 := makeTestPreConfirmedBlock(r1, 0) + block2 := makeTestPreConfirmedBlock(r2, 0) + block3 := makeTestPreConfirmedBlock(r3, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) @@ -257,10 +268,10 @@ func TestPollerColdBootstrapWithGap(t *testing.T) { PreConfirmedBlockLatest(gomock.Any(), gomock.Any(), gomock.Any()). Return(block3, uint64(3), nil), ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(1), "", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(1), starknet.BlockIdentifier(0), uint64(0)). Return(block1, nil), ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(2), "", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(2), starknet.BlockIdentifier(0), uint64(0)). Return(block2, nil), ) @@ -287,11 +298,11 @@ func TestPollerSameHeightNoBackfill(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed := makeTestPreConfirmedBlock("r0", 0) + seed := makeTestPreConfirmedBlock(r0, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r0", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r0, uint64(0)). Return(starknet.PreConfirmedNoChange{}, uint64(1), nil) synctest.Test(t, func(t *testing.T) { @@ -320,13 +331,13 @@ func TestPollerSameHeightDeltaAppliesToSlot(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed := makeTestPreConfirmedBlock("r0", 0) - delta := makeTestDelta("r0", 2) + seed := makeTestPreConfirmedBlock(r0, 0) + delta := makeTestDelta(r0, 2) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - // Delta hint matches mostRecent: identifier="r0", txCount=0. - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r0", uint64(0)). + // Delta hint matches mostRecent: identifier=r0, txCount=0. + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r0, uint64(0)). Return(delta, uint64(1), nil) synctest.Test(t, func(t *testing.T) { @@ -355,9 +366,9 @@ func TestPollerForwardJumpFinalisesMostRecent(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed := makeTestPreConfirmedBlock("r0", 0) - finaliseDelta := makeTestDelta("r0", 3) // 3 final txs appended at block 1 - block2 := makeTestPreConfirmedBlock("r1", 0) + seed := makeTestPreConfirmedBlock(r0, 0) + finaliseDelta := makeTestDelta(r0, 3) // 3 final txs appended at block 1 + block2 := makeTestPreConfirmedBlock(r1, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) @@ -368,7 +379,7 @@ func TestPollerForwardJumpFinalisesMostRecent(t *testing.T) { // Finalise poll: server replies with a Delta keyed off the stored // identifier+txCount; carries any txs appended since. ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(1), "r0", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(1), r0, uint64(0)). Return(finaliseDelta, nil), ) @@ -397,11 +408,11 @@ func TestPollerLargeJumpWalksGap(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed := makeTestPreConfirmedBlock("r0", 0) - finaliseReply := makeTestPreConfirmedBlock("r0", 0) // same content → slot preserved - block2 := makeTestPreConfirmedBlock("r2", 0) - block3 := makeTestPreConfirmedBlock("r3", 0) - block4 := makeTestPreConfirmedBlock("r4", 0) + seed := makeTestPreConfirmedBlock(r0, 0) + finaliseReply := makeTestPreConfirmedBlock(r0, 0) // same content → slot preserved + block2 := makeTestPreConfirmedBlock(r2, 0) + block3 := makeTestPreConfirmedBlock(r3, 0) + block4 := makeTestPreConfirmedBlock(r4, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) @@ -411,14 +422,14 @@ func TestPollerLargeJumpWalksGap(t *testing.T) { Return(block4, uint64(4), nil), // Finalise mostRecent (1) with delta hints. ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(1), "r0", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(1), r0, uint64(0)). Return(finaliseReply, nil), // Walk intermediate blocks 2, 3 with blank hints. ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(2), "", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(2), starknet.BlockIdentifier(0), uint64(0)). Return(block2, nil), ds.EXPECT(). - PreConfirmedBlockByNumber(gomock.Any(), uint64(3), "", uint64(0)). + PreConfirmedBlockByNumber(gomock.Any(), uint64(3), starknet.BlockIdentifier(0), uint64(0)). Return(block3, nil), ) @@ -497,7 +508,7 @@ func TestPollerBackfillErrorSkipsApply(t *testing.T) { t.Parallel() fx := newChainFixture(t) - latestReply := makeTestPreConfirmedBlock("r3", 0) + latestReply := makeTestPreConfirmedBlock(r3, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) @@ -530,9 +541,9 @@ func TestPollerMultiTickExtendsChain(t *testing.T) { t.Parallel() fx := newChainFixture(t) - block1 := makeTestPreConfirmedBlock("r1", 0) - block2 := makeTestPreConfirmedBlock("r2", 0) - block3 := makeTestPreConfirmedBlock("r3", 0) + block1 := makeTestPreConfirmedBlock(r1, 0) + block2 := makeTestPreConfirmedBlock(r2, 0) + block3 := makeTestPreConfirmedBlock(r3, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) @@ -541,17 +552,17 @@ func TestPollerMultiTickExtendsChain(t *testing.T) { // shouldPreserveSlot keeps the entry instead of replacing it. gomock.InOrder( // Tick 1: cold bootstrap. - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), starknet.BlockIdentifier(0), uint64(0)). Return(block1, uint64(1), nil), // Tick 2: sequencer advanced; latest + finalise of block 1. - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r1", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r1, uint64(0)). Return(block2, uint64(2), nil), - ds.EXPECT().PreConfirmedBlockByNumber(gomock.Any(), uint64(1), "r1", uint64(0)). + ds.EXPECT().PreConfirmedBlockByNumber(gomock.Any(), uint64(1), r1, uint64(0)). Return(block1, nil), // Tick 3: advanced again; latest + finalise of block 2. - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r2", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r2, uint64(0)). Return(block3, uint64(3), nil), - ds.EXPECT().PreConfirmedBlockByNumber(gomock.Any(), uint64(2), "r2", uint64(0)). + ds.EXPECT().PreConfirmedBlockByNumber(gomock.Any(), uint64(2), r2, uint64(0)). Return(block2, nil), ) @@ -594,14 +605,14 @@ func TestPollerHeadAdvancesDropsCommittedEntries(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed1 := makeTestPreConfirmedBlock("r1", 0) // will be dropped after head advances past it - seed2 := makeTestPreConfirmedBlock("r2", 0) + seed1 := makeTestPreConfirmedBlock(r1, 0) // will be dropped after head advances past it + seed2 := makeTestPreConfirmedBlock(r2, 0) var latestBlockNumber atomic.Uint64 ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), gomock.Any(), gomock.Any()). - DoAndReturn(func(context.Context, string, uint64) (starknet.PreConfirmedUpdate, uint64, error) { + DoAndReturn(func(context.Context, starknet.BlockIdentifier, uint64) (starknet.PreConfirmedUpdate, uint64, error) { return starknet.PreConfirmedNoChange{}, latestBlockNumber.Load(), nil }) @@ -640,17 +651,17 @@ func TestPollerReorgLowerHeightDifferentIdentifier(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed1 := makeTestPreConfirmedBlock("r1", 0) - seed2 := makeTestPreConfirmedBlock("r2", 0) - seed3 := makeTestPreConfirmedBlock("r3", 0) + seed1 := makeTestPreConfirmedBlock(r1, 0) + seed2 := makeTestPreConfirmedBlock(r2, 0) + seed3 := makeTestPreConfirmedBlock(r3, 0) // New round arrives at block 2 with a different identifier — anything // above (block 3) must be dropped. - replacement := makeTestPreConfirmedBlock("rZ", 0) + replacement := makeTestPreConfirmedBlock(rZ, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - // Hint matches the most recent (block 3, "r3", 0 txs) the poller would carry. - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r3", uint64(0)). + // Hint matches the most recent (block 3, r3, 0 txs) the poller would carry. + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r3, uint64(0)). Return(replacement, uint64(2), nil) synctest.Test(t, func(t *testing.T) { @@ -683,15 +694,15 @@ func TestPollerReorgSameHeightDifferentIdentifier(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed1 := makeTestPreConfirmedBlock("r1", 0) - seed2 := makeTestPreConfirmedBlock("r2", 0) - seed3 := makeTestPreConfirmedBlock("r3", 0) + seed1 := makeTestPreConfirmedBlock(r1, 0) + seed2 := makeTestPreConfirmedBlock(r2, 0) + seed3 := makeTestPreConfirmedBlock(r3, 0) // New round at the same slot — different identifier replaces the most recent. - replacement := makeTestPreConfirmedBlock("rZ", 0) + replacement := makeTestPreConfirmedBlock(rZ, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r3", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r3, uint64(0)). Return(replacement, uint64(3), nil) synctest.Test(t, func(t *testing.T) { @@ -726,11 +737,11 @@ func TestPollerBroadcastsOnApply(t *testing.T) { t.Parallel() fx := newChainFixture(t) - block1 := makeTestPreConfirmedBlock("r0", 1) + block1 := makeTestPreConfirmedBlock(r0, 1) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), starknet.BlockIdentifier(0), uint64(0)). Return(block1, uint64(1), nil) synctest.Test(t, func(t *testing.T) { @@ -745,7 +756,7 @@ func TestPollerBroadcastsOnApply(t *testing.T) { case pc := <-h.sub.Recv(): require.NotNil(t, pc) require.Equal(t, uint64(1), pc.Block.Number) - require.Equal(t, "r0", pc.BlockIdentifier) + require.Equal(t, uint64(r0), pc.BlockIdentifier) default: t.Fatal("expected a pre_confirmed broadcast on successful apply") } @@ -757,11 +768,11 @@ func TestPollerSilentOnNoChange(t *testing.T) { t.Parallel() fx := newChainFixture(t) - seed := makeTestPreConfirmedBlock("r0", 0) + seed := makeTestPreConfirmedBlock(r0, 0) ctrl := gomock.NewController(t) ds := mocks.NewMockStarknetData(ctrl) - ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), "r0", uint64(0)). + ds.EXPECT().PreConfirmedBlockLatest(gomock.Any(), r0, uint64(0)). Return(starknet.PreConfirmedNoChange{}, uint64(1), nil) synctest.Test(t, func(t *testing.T) { diff --git a/sync/reorg_test.go b/sync/reorg_test.go index 6a5ecd147b..9abfd14c0f 100644 --- a/sync/reorg_test.go +++ b/sync/reorg_test.go @@ -65,7 +65,7 @@ func (t *testBlockDataSource) BlockHeaderLatest(ctx context.Context) (*core.Head func (t *testBlockDataSource) PreConfirmedBlockByNumber( ctx context.Context, blockNumber uint64, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, error) { return nil, errors.New("not implemented") @@ -73,7 +73,7 @@ func (t *testBlockDataSource) PreConfirmedBlockByNumber( func (t *testBlockDataSource) PreConfirmedBlockLatest( ctx context.Context, - blockIdentifier string, + blockIdentifier starknet.BlockIdentifier, knownTransactionCount uint64, ) (starknet.PreConfirmedUpdate, uint64, error) { return nil, 0, errors.New("not implemented")