From 9a652f4c14455648a262c210b64c776020ff7973 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Mon, 22 Jun 2026 08:07:52 +0000 Subject: [PATCH 1/5] test(state): add unit tests for state accessors Adds dedicated unit tests for core/state/accessors.go. Closes #3688 --- core/state/accessors_test.go | 255 +++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 core/state/accessors_test.go diff --git a/core/state/accessors_test.go b/core/state/accessors_test.go new file mode 100644 index 0000000000..518465b420 --- /dev/null +++ b/core/state/accessors_test.go @@ -0,0 +1,255 @@ +package state + +import ( + "testing" + + "github.com/NethermindEth/juno/core" + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/db" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestContractAccessors(t *testing.T) { + stateDB := newTestStateDB() + addr := felt.NewUnsafeFromString[felt.Felt]("0x123") + + t.Run("absent before write", func(t *testing.T) { + exists, err := HasContract(stateDB.disk, addr) + require.NoError(t, err) + assert.False(t, exists) + + _, err = GetContract(stateDB.disk, addr) + assert.ErrorIs(t, err, db.ErrKeyNotFound) + }) + + t.Run("write then read round-trip", func(t *testing.T) { + require.NoError(t, WriteContract( + stateDB.disk, addr, + felt.UnsafeFromString[felt.Felt]("0x1"), // nonce + felt.UnsafeFromString[felt.Felt]("0xabc"), // classHash + 42, // deployHeight + )) + + exists, err := HasContract(stateDB.disk, addr) + require.NoError(t, err) + assert.True(t, exists) + + contract, err := GetContract(stateDB.disk, addr) + require.NoError(t, err) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x1"), contract.Nonce) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xabc"), contract.ClassHash) + assert.Equal(t, uint64(42), contract.DeployedHeight) + }) + + t.Run("overwrite reflects latest values", func(t *testing.T) { + require.NoError(t, WriteContract( + stateDB.disk, addr, + felt.UnsafeFromString[felt.Felt]("0x2"), + felt.UnsafeFromString[felt.Felt]("0xdef"), + 99, + )) + + contract, err := GetContract(stateDB.disk, addr) + require.NoError(t, err) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x2"), contract.Nonce) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xdef"), contract.ClassHash) + assert.Equal(t, uint64(99), contract.DeployedHeight) + }) + + t.Run("delete removes the contract", func(t *testing.T) { + require.NoError(t, DeleteContract(stateDB.disk, addr)) + + exists, err := HasContract(stateDB.disk, addr) + require.NoError(t, err) + assert.False(t, exists) + + _, err = GetContract(stateDB.disk, addr) + assert.ErrorIs(t, err, db.ErrKeyNotFound) + }) +} + +func TestClassAccessors(t *testing.T) { + stateDB := newTestStateDB() + classHash := felt.NewUnsafeFromString[felt.Felt]("0xabc") + class := &core.DeclaredClassDefinition{ + At: 12, + Class: &core.SierraClass{ + SemanticVersion: "0.1.0", + Program: []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x1")}, + }, + } + + t.Run("absent before write", func(t *testing.T) { + exists, err := HasClass(stateDB.disk, classHash) + require.NoError(t, err) + assert.False(t, exists) + + _, err = GetClass(stateDB.disk, classHash) + assert.ErrorIs(t, err, db.ErrKeyNotFound) + }) + + t.Run("write then read round-trips the encoded class", func(t *testing.T) { + require.NoError(t, WriteClass(stateDB.disk, classHash, class)) + + exists, err := HasClass(stateDB.disk, classHash) + require.NoError(t, err) + assert.True(t, exists) + + got, err := GetClass(stateDB.disk, classHash) + require.NoError(t, err) + assert.Equal(t, class.At, got.At) + sierra, ok := got.Class.(*core.SierraClass) + require.True(t, ok) + assert.Equal(t, "0.1.0", sierra.SemanticVersion) + assert.Equal(t, []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x1")}, sierra.Program) + }) + + t.Run("delete removes the class", func(t *testing.T) { + require.NoError(t, DeleteClass(stateDB.disk, classHash)) + + exists, err := HasClass(stateDB.disk, classHash) + require.NoError(t, err) + assert.False(t, exists) + + _, err = GetClass(stateDB.disk, classHash) + assert.ErrorIs(t, err, db.ErrKeyNotFound) + }) +} + +// Reads values back through the StateReader history readers, which use a different key path +// than the accessors, so the round-trip tests behavior rather than the accessor's own keys. +func TestHistoryAccessors(t *testing.T) { + addr := felt.NewUnsafeFromString[felt.Felt]("0x123") + storageKey := felt.NewUnsafeFromString[felt.Felt]("0x456") + + type historyKind struct { + name string + write func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error + del func(w db.KeyValueWriter, blockNum uint64) error + readAt func(r *StateReader, blockNum uint64) (felt.Felt, error) + valueOne *felt.Felt + valueTwo *felt.Felt + } + + kinds := []historyKind{ + { + name: "nonce", + write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { + return WriteNonceHistory(w, addr, blockNum, value) + }, + del: func(w db.KeyValueWriter, blockNum uint64) error { + return DeleteNonceHistory(w, addr, blockNum) + }, + readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + return r.ContractNonceAt(addr, blockNum) + }, + valueOne: felt.NewUnsafeFromString[felt.Felt]("0x7"), + valueTwo: felt.NewUnsafeFromString[felt.Felt]("0x2a"), + }, + { + name: "class hash", + write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { + return WriteClassHashHistory(w, addr, blockNum, value) + }, + del: func(w db.KeyValueWriter, blockNum uint64) error { + return DeleteClassHashHistory(w, addr, blockNum) + }, + readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + return r.ContractClassHashAt(addr, blockNum) + }, + valueOne: felt.NewUnsafeFromString[felt.Felt]("0xaaa"), + valueTwo: felt.NewUnsafeFromString[felt.Felt]("0xbbb"), + }, + { + name: "storage", + write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { + return WriteStorageHistory(w, addr, storageKey, blockNum, value) + }, + del: func(w db.KeyValueWriter, blockNum uint64) error { + return DeleteStorageHistory(w, addr, storageKey, blockNum) + }, + readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + return r.ContractStorageAt(addr, storageKey, blockNum) + }, + valueOne: felt.NewUnsafeFromString[felt.Felt]("0xdef"), + valueTwo: felt.NewUnsafeFromString[felt.Felt]("0xfed"), + }, + } + + const blockOne, blockTwo = uint64(7), uint64(15) + + for _, k := range kinds { + t.Run(k.name, func(t *testing.T) { + stateDB := newTestStateDB() + reader, err := NewStateReader(&felt.Zero, stateDB) + require.NoError(t, err) + + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + + t.Run("reads the written value at its block", func(t *testing.T) { + got, err := k.readAt(reader, blockOne) + require.NoError(t, err) + assert.Equal(t, *k.valueOne, got) + }) + + t.Run("steps back to the last entry for a later block", func(t *testing.T) { + got, err := k.readAt(reader, blockOne+3) + require.NoError(t, err) + assert.Equal(t, *k.valueOne, got) + }) + + t.Run("reads zero before the first entry", func(t *testing.T) { + got, err := k.readAt(reader, blockOne-1) + require.NoError(t, err) + assert.Equal(t, felt.Zero, got) + }) + + t.Run("honours block boundaries across two entries", func(t *testing.T) { + require.NoError(t, k.write(stateDB.disk, blockTwo, k.valueTwo)) + + between, err := k.readAt(reader, blockTwo-1) + require.NoError(t, err) + assert.Equal(t, *k.valueOne, between) + + after, err := k.readAt(reader, blockTwo) + require.NoError(t, err) + assert.Equal(t, *k.valueTwo, after) + }) + + t.Run("delete drops the entry", func(t *testing.T) { + require.NoError(t, k.del(stateDB.disk, blockOne)) + require.NoError(t, k.del(stateDB.disk, blockTwo)) + + got, err := k.readAt(reader, blockTwo+1) + require.NoError(t, err) + assert.Equal(t, felt.Zero, got) + }) + }) + } +} + +func TestGetStateObject(t *testing.T) { + stateDB := newTestStateDB() + addr := felt.NewUnsafeFromString[felt.Felt]("0x123") + + t.Run("propagates not-found for a missing contract", func(t *testing.T) { + _, err := GetStateObject(stateDB.disk, nil, addr) + assert.ErrorIs(t, err, db.ErrKeyNotFound) + }) + + t.Run("wraps the stored contract on success", func(t *testing.T) { + require.NoError(t, WriteContract(stateDB.disk, addr, + felt.UnsafeFromString[felt.Felt]("0x1"), + felt.UnsafeFromString[felt.Felt]("0xabc"), + 42, + )) + + obj, err := GetStateObject(stateDB.disk, nil, addr) + require.NoError(t, err) + assert.Equal(t, *addr, obj.addr) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x1"), obj.contract.Nonce) + assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xabc"), obj.contract.ClassHash) + assert.Equal(t, uint64(42), obj.contract.DeployedHeight) + }) +} From b2230fa1ff49a0973ab10db6ba3841d6d51de660 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Mon, 22 Jun 2026 09:50:10 +0000 Subject: [PATCH 2/5] test(state): make accessor subtests order-independent Give each subtest its own StateDB (and StateReader for history) so they no longer share mutable state or depend on execution order. Rename the contract-writing helper to storeContract to avoid shadowing the package-level writeContract function. --- core/state/accessors_test.go | 89 +++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/core/state/accessors_test.go b/core/state/accessors_test.go index 518465b420..b1c89abeff 100644 --- a/core/state/accessors_test.go +++ b/core/state/accessors_test.go @@ -11,10 +11,22 @@ import ( ) func TestContractAccessors(t *testing.T) { - stateDB := newTestStateDB() addr := felt.NewUnsafeFromString[felt.Felt]("0x123") + // storeContract stores a contract with the given values and fails the test on error. + storeContract := func(t *testing.T, stateDB *StateDB, nonce, classHash string, height uint64) { + t.Helper() + require.NoError(t, WriteContract( + stateDB.disk, addr, + felt.UnsafeFromString[felt.Felt](nonce), + felt.UnsafeFromString[felt.Felt](classHash), + height, + )) + } + t.Run("absent before write", func(t *testing.T) { + stateDB := newTestStateDB() + exists, err := HasContract(stateDB.disk, addr) require.NoError(t, err) assert.False(t, exists) @@ -24,12 +36,8 @@ func TestContractAccessors(t *testing.T) { }) t.Run("write then read round-trip", func(t *testing.T) { - require.NoError(t, WriteContract( - stateDB.disk, addr, - felt.UnsafeFromString[felt.Felt]("0x1"), // nonce - felt.UnsafeFromString[felt.Felt]("0xabc"), // classHash - 42, // deployHeight - )) + stateDB := newTestStateDB() + storeContract(t, stateDB, "0x1", "0xabc", 42) exists, err := HasContract(stateDB.disk, addr) require.NoError(t, err) @@ -43,12 +51,9 @@ func TestContractAccessors(t *testing.T) { }) t.Run("overwrite reflects latest values", func(t *testing.T) { - require.NoError(t, WriteContract( - stateDB.disk, addr, - felt.UnsafeFromString[felt.Felt]("0x2"), - felt.UnsafeFromString[felt.Felt]("0xdef"), - 99, - )) + stateDB := newTestStateDB() + storeContract(t, stateDB, "0x1", "0xabc", 42) + storeContract(t, stateDB, "0x2", "0xdef", 99) contract, err := GetContract(stateDB.disk, addr) require.NoError(t, err) @@ -58,6 +63,9 @@ func TestContractAccessors(t *testing.T) { }) t.Run("delete removes the contract", func(t *testing.T) { + stateDB := newTestStateDB() + storeContract(t, stateDB, "0x1", "0xabc", 42) + require.NoError(t, DeleteContract(stateDB.disk, addr)) exists, err := HasContract(stateDB.disk, addr) @@ -70,17 +78,20 @@ func TestContractAccessors(t *testing.T) { } func TestClassAccessors(t *testing.T) { - stateDB := newTestStateDB() classHash := felt.NewUnsafeFromString[felt.Felt]("0xabc") - class := &core.DeclaredClassDefinition{ - At: 12, - Class: &core.SierraClass{ - SemanticVersion: "0.1.0", - Program: []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x1")}, - }, + newClass := func() *core.DeclaredClassDefinition { + return &core.DeclaredClassDefinition{ + At: 12, + Class: &core.SierraClass{ + SemanticVersion: "0.1.0", + Program: []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x1")}, + }, + } } t.Run("absent before write", func(t *testing.T) { + stateDB := newTestStateDB() + exists, err := HasClass(stateDB.disk, classHash) require.NoError(t, err) assert.False(t, exists) @@ -90,6 +101,8 @@ func TestClassAccessors(t *testing.T) { }) t.Run("write then read round-trips the encoded class", func(t *testing.T) { + stateDB := newTestStateDB() + class := newClass() require.NoError(t, WriteClass(stateDB.disk, classHash, class)) exists, err := HasClass(stateDB.disk, classHash) @@ -106,6 +119,9 @@ func TestClassAccessors(t *testing.T) { }) t.Run("delete removes the class", func(t *testing.T) { + stateDB := newTestStateDB() + require.NoError(t, WriteClass(stateDB.disk, classHash, newClass())) + require.NoError(t, DeleteClass(stateDB.disk, classHash)) exists, err := HasClass(stateDB.disk, classHash) @@ -181,31 +197,46 @@ func TestHistoryAccessors(t *testing.T) { for _, k := range kinds { t.Run(k.name, func(t *testing.T) { - stateDB := newTestStateDB() - reader, err := NewStateReader(&felt.Zero, stateDB) - require.NoError(t, err) - - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + // newReader returns a fresh state and a reader over it, so each subtest + // starts from an empty history and is independent of execution order. + newReader := func(t *testing.T) (*StateDB, *StateReader) { + t.Helper() + stateDB := newTestStateDB() + reader, err := NewStateReader(&felt.Zero, stateDB) + require.NoError(t, err) + return stateDB, reader + } t.Run("reads the written value at its block", func(t *testing.T) { + stateDB, reader := newReader(t) + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + got, err := k.readAt(reader, blockOne) require.NoError(t, err) assert.Equal(t, *k.valueOne, got) }) t.Run("steps back to the last entry for a later block", func(t *testing.T) { + stateDB, reader := newReader(t) + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + got, err := k.readAt(reader, blockOne+3) require.NoError(t, err) assert.Equal(t, *k.valueOne, got) }) t.Run("reads zero before the first entry", func(t *testing.T) { + stateDB, reader := newReader(t) + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + got, err := k.readAt(reader, blockOne-1) require.NoError(t, err) assert.Equal(t, felt.Zero, got) }) t.Run("honours block boundaries across two entries", func(t *testing.T) { + stateDB, reader := newReader(t) + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) require.NoError(t, k.write(stateDB.disk, blockTwo, k.valueTwo)) between, err := k.readAt(reader, blockTwo-1) @@ -218,6 +249,10 @@ func TestHistoryAccessors(t *testing.T) { }) t.Run("delete drops the entry", func(t *testing.T) { + stateDB, reader := newReader(t) + require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + require.NoError(t, k.write(stateDB.disk, blockTwo, k.valueTwo)) + require.NoError(t, k.del(stateDB.disk, blockOne)) require.NoError(t, k.del(stateDB.disk, blockTwo)) @@ -230,15 +265,17 @@ func TestHistoryAccessors(t *testing.T) { } func TestGetStateObject(t *testing.T) { - stateDB := newTestStateDB() addr := felt.NewUnsafeFromString[felt.Felt]("0x123") t.Run("propagates not-found for a missing contract", func(t *testing.T) { + stateDB := newTestStateDB() + _, err := GetStateObject(stateDB.disk, nil, addr) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) t.Run("wraps the stored contract on success", func(t *testing.T) { + stateDB := newTestStateDB() require.NoError(t, WriteContract(stateDB.disk, addr, felt.UnsafeFromString[felt.Felt]("0x1"), felt.UnsafeFromString[felt.Felt]("0xabc"), From 365cedffcc9326e3621fdcc8041e611f0025256a Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Sat, 27 Jun 2026 05:40:52 +0000 Subject: [PATCH 3/5] test(state): exercise accessors through the public API Move accessors_test.go to package state_test so it compiles against the exported accessors only, instead of reaching into unexported internals (stateDB.disk, newTestStateDB). Contract/class tests now write through a plain memory store, and history tests build a StateDB/StateReader via the exported constructors. Drop the "wraps the stored contract on success" case from TestGetStateObject: it only asserted, via unexported fields, that the constructor copied its inputs (a tautological test). The not-found case, which is the actual behavior of GetStateObject, is kept. --- core/state/accessors_test.go | 147 ++++++++++++++++------------------- 1 file changed, 68 insertions(+), 79 deletions(-) diff --git a/core/state/accessors_test.go b/core/state/accessors_test.go index b1c89abeff..fc30f8562f 100644 --- a/core/state/accessors_test.go +++ b/core/state/accessors_test.go @@ -1,11 +1,15 @@ -package state +package state_test import ( "testing" "github.com/NethermindEth/juno/core" "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/core/state" + "github.com/NethermindEth/juno/core/trie2/triedb" "github.com/NethermindEth/juno/db" + "github.com/NethermindEth/juno/db/memory" + _ "github.com/NethermindEth/juno/encoder/registry" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -14,10 +18,10 @@ func TestContractAccessors(t *testing.T) { addr := felt.NewUnsafeFromString[felt.Felt]("0x123") // storeContract stores a contract with the given values and fails the test on error. - storeContract := func(t *testing.T, stateDB *StateDB, nonce, classHash string, height uint64) { + storeContract := func(t *testing.T, disk db.KeyValueWriter, nonce, classHash string, height uint64) { t.Helper() - require.NoError(t, WriteContract( - stateDB.disk, addr, + require.NoError(t, state.WriteContract( + disk, addr, felt.UnsafeFromString[felt.Felt](nonce), felt.UnsafeFromString[felt.Felt](classHash), height, @@ -25,25 +29,25 @@ func TestContractAccessors(t *testing.T) { } t.Run("absent before write", func(t *testing.T) { - stateDB := newTestStateDB() + disk := memory.New() - exists, err := HasContract(stateDB.disk, addr) + exists, err := state.HasContract(disk, addr) require.NoError(t, err) assert.False(t, exists) - _, err = GetContract(stateDB.disk, addr) + _, err = state.GetContract(disk, addr) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) t.Run("write then read round-trip", func(t *testing.T) { - stateDB := newTestStateDB() - storeContract(t, stateDB, "0x1", "0xabc", 42) + disk := memory.New() + storeContract(t, disk, "0x1", "0xabc", 42) - exists, err := HasContract(stateDB.disk, addr) + exists, err := state.HasContract(disk, addr) require.NoError(t, err) assert.True(t, exists) - contract, err := GetContract(stateDB.disk, addr) + contract, err := state.GetContract(disk, addr) require.NoError(t, err) assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x1"), contract.Nonce) assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xabc"), contract.ClassHash) @@ -51,11 +55,11 @@ func TestContractAccessors(t *testing.T) { }) t.Run("overwrite reflects latest values", func(t *testing.T) { - stateDB := newTestStateDB() - storeContract(t, stateDB, "0x1", "0xabc", 42) - storeContract(t, stateDB, "0x2", "0xdef", 99) + disk := memory.New() + storeContract(t, disk, "0x1", "0xabc", 42) + storeContract(t, disk, "0x2", "0xdef", 99) - contract, err := GetContract(stateDB.disk, addr) + contract, err := state.GetContract(disk, addr) require.NoError(t, err) assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x2"), contract.Nonce) assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xdef"), contract.ClassHash) @@ -63,16 +67,16 @@ func TestContractAccessors(t *testing.T) { }) t.Run("delete removes the contract", func(t *testing.T) { - stateDB := newTestStateDB() - storeContract(t, stateDB, "0x1", "0xabc", 42) + disk := memory.New() + storeContract(t, disk, "0x1", "0xabc", 42) - require.NoError(t, DeleteContract(stateDB.disk, addr)) + require.NoError(t, state.DeleteContract(disk, addr)) - exists, err := HasContract(stateDB.disk, addr) + exists, err := state.HasContract(disk, addr) require.NoError(t, err) assert.False(t, exists) - _, err = GetContract(stateDB.disk, addr) + _, err = state.GetContract(disk, addr) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) } @@ -90,26 +94,26 @@ func TestClassAccessors(t *testing.T) { } t.Run("absent before write", func(t *testing.T) { - stateDB := newTestStateDB() + disk := memory.New() - exists, err := HasClass(stateDB.disk, classHash) + exists, err := state.HasClass(disk, classHash) require.NoError(t, err) assert.False(t, exists) - _, err = GetClass(stateDB.disk, classHash) + _, err = state.GetClass(disk, classHash) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) t.Run("write then read round-trips the encoded class", func(t *testing.T) { - stateDB := newTestStateDB() + disk := memory.New() class := newClass() - require.NoError(t, WriteClass(stateDB.disk, classHash, class)) + require.NoError(t, state.WriteClass(disk, classHash, class)) - exists, err := HasClass(stateDB.disk, classHash) + exists, err := state.HasClass(disk, classHash) require.NoError(t, err) assert.True(t, exists) - got, err := GetClass(stateDB.disk, classHash) + got, err := state.GetClass(disk, classHash) require.NoError(t, err) assert.Equal(t, class.At, got.At) sierra, ok := got.Class.(*core.SierraClass) @@ -119,16 +123,16 @@ func TestClassAccessors(t *testing.T) { }) t.Run("delete removes the class", func(t *testing.T) { - stateDB := newTestStateDB() - require.NoError(t, WriteClass(stateDB.disk, classHash, newClass())) + disk := memory.New() + require.NoError(t, state.WriteClass(disk, classHash, newClass())) - require.NoError(t, DeleteClass(stateDB.disk, classHash)) + require.NoError(t, state.DeleteClass(disk, classHash)) - exists, err := HasClass(stateDB.disk, classHash) + exists, err := state.HasClass(disk, classHash) require.NoError(t, err) assert.False(t, exists) - _, err = GetClass(stateDB.disk, classHash) + _, err = state.GetClass(disk, classHash) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) } @@ -143,7 +147,7 @@ func TestHistoryAccessors(t *testing.T) { name string write func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error del func(w db.KeyValueWriter, blockNum uint64) error - readAt func(r *StateReader, blockNum uint64) (felt.Felt, error) + readAt func(r *state.StateReader, blockNum uint64) (felt.Felt, error) valueOne *felt.Felt valueTwo *felt.Felt } @@ -152,12 +156,12 @@ func TestHistoryAccessors(t *testing.T) { { name: "nonce", write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { - return WriteNonceHistory(w, addr, blockNum, value) + return state.WriteNonceHistory(w, addr, blockNum, value) }, del: func(w db.KeyValueWriter, blockNum uint64) error { - return DeleteNonceHistory(w, addr, blockNum) + return state.DeleteNonceHistory(w, addr, blockNum) }, - readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + readAt: func(r *state.StateReader, blockNum uint64) (felt.Felt, error) { return r.ContractNonceAt(addr, blockNum) }, valueOne: felt.NewUnsafeFromString[felt.Felt]("0x7"), @@ -166,12 +170,12 @@ func TestHistoryAccessors(t *testing.T) { { name: "class hash", write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { - return WriteClassHashHistory(w, addr, blockNum, value) + return state.WriteClassHashHistory(w, addr, blockNum, value) }, del: func(w db.KeyValueWriter, blockNum uint64) error { - return DeleteClassHashHistory(w, addr, blockNum) + return state.DeleteClassHashHistory(w, addr, blockNum) }, - readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + readAt: func(r *state.StateReader, blockNum uint64) (felt.Felt, error) { return r.ContractClassHashAt(addr, blockNum) }, valueOne: felt.NewUnsafeFromString[felt.Felt]("0xaaa"), @@ -180,12 +184,12 @@ func TestHistoryAccessors(t *testing.T) { { name: "storage", write: func(w db.KeyValueWriter, blockNum uint64, value *felt.Felt) error { - return WriteStorageHistory(w, addr, storageKey, blockNum, value) + return state.WriteStorageHistory(w, addr, storageKey, blockNum, value) }, del: func(w db.KeyValueWriter, blockNum uint64) error { - return DeleteStorageHistory(w, addr, storageKey, blockNum) + return state.DeleteStorageHistory(w, addr, storageKey, blockNum) }, - readAt: func(r *StateReader, blockNum uint64) (felt.Felt, error) { + readAt: func(r *state.StateReader, blockNum uint64) (felt.Felt, error) { return r.ContractStorageAt(addr, storageKey, blockNum) }, valueOne: felt.NewUnsafeFromString[felt.Felt]("0xdef"), @@ -197,19 +201,20 @@ func TestHistoryAccessors(t *testing.T) { for _, k := range kinds { t.Run(k.name, func(t *testing.T) { - // newReader returns a fresh state and a reader over it, so each subtest + // newReader returns a fresh disk store and a reader over it, so each subtest // starts from an empty history and is independent of execution order. - newReader := func(t *testing.T) (*StateDB, *StateReader) { + newReader := func(t *testing.T) (db.KeyValueStore, *state.StateReader) { t.Helper() - stateDB := newTestStateDB() - reader, err := NewStateReader(&felt.Zero, stateDB) + disk := memory.New() + stateDB := state.NewStateDB(disk, triedb.New(disk, nil)) + reader, err := state.NewStateReader(&felt.Zero, stateDB) require.NoError(t, err) - return stateDB, reader + return disk, reader } t.Run("reads the written value at its block", func(t *testing.T) { - stateDB, reader := newReader(t) - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + disk, reader := newReader(t) + require.NoError(t, k.write(disk, blockOne, k.valueOne)) got, err := k.readAt(reader, blockOne) require.NoError(t, err) @@ -217,8 +222,8 @@ func TestHistoryAccessors(t *testing.T) { }) t.Run("steps back to the last entry for a later block", func(t *testing.T) { - stateDB, reader := newReader(t) - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + disk, reader := newReader(t) + require.NoError(t, k.write(disk, blockOne, k.valueOne)) got, err := k.readAt(reader, blockOne+3) require.NoError(t, err) @@ -226,8 +231,8 @@ func TestHistoryAccessors(t *testing.T) { }) t.Run("reads zero before the first entry", func(t *testing.T) { - stateDB, reader := newReader(t) - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) + disk, reader := newReader(t) + require.NoError(t, k.write(disk, blockOne, k.valueOne)) got, err := k.readAt(reader, blockOne-1) require.NoError(t, err) @@ -235,9 +240,9 @@ func TestHistoryAccessors(t *testing.T) { }) t.Run("honours block boundaries across two entries", func(t *testing.T) { - stateDB, reader := newReader(t) - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) - require.NoError(t, k.write(stateDB.disk, blockTwo, k.valueTwo)) + disk, reader := newReader(t) + require.NoError(t, k.write(disk, blockOne, k.valueOne)) + require.NoError(t, k.write(disk, blockTwo, k.valueTwo)) between, err := k.readAt(reader, blockTwo-1) require.NoError(t, err) @@ -249,12 +254,12 @@ func TestHistoryAccessors(t *testing.T) { }) t.Run("delete drops the entry", func(t *testing.T) { - stateDB, reader := newReader(t) - require.NoError(t, k.write(stateDB.disk, blockOne, k.valueOne)) - require.NoError(t, k.write(stateDB.disk, blockTwo, k.valueTwo)) + disk, reader := newReader(t) + require.NoError(t, k.write(disk, blockOne, k.valueOne)) + require.NoError(t, k.write(disk, blockTwo, k.valueTwo)) - require.NoError(t, k.del(stateDB.disk, blockOne)) - require.NoError(t, k.del(stateDB.disk, blockTwo)) + require.NoError(t, k.del(disk, blockOne)) + require.NoError(t, k.del(disk, blockTwo)) got, err := k.readAt(reader, blockTwo+1) require.NoError(t, err) @@ -268,25 +273,9 @@ func TestGetStateObject(t *testing.T) { addr := felt.NewUnsafeFromString[felt.Felt]("0x123") t.Run("propagates not-found for a missing contract", func(t *testing.T) { - stateDB := newTestStateDB() + disk := memory.New() - _, err := GetStateObject(stateDB.disk, nil, addr) + _, err := state.GetStateObject(disk, nil, addr) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) - - t.Run("wraps the stored contract on success", func(t *testing.T) { - stateDB := newTestStateDB() - require.NoError(t, WriteContract(stateDB.disk, addr, - felt.UnsafeFromString[felt.Felt]("0x1"), - felt.UnsafeFromString[felt.Felt]("0xabc"), - 42, - )) - - obj, err := GetStateObject(stateDB.disk, nil, addr) - require.NoError(t, err) - assert.Equal(t, *addr, obj.addr) - assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0x1"), obj.contract.Nonce) - assert.Equal(t, felt.UnsafeFromString[felt.Felt]("0xabc"), obj.contract.ClassHash) - assert.Equal(t, uint64(42), obj.contract.DeployedHeight) - }) } From dca0afe261f228b0af0224f79de8bf93940424d8 Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Mon, 29 Jun 2026 07:06:26 +0000 Subject: [PATCH 4/5] test(state): wrap long func signature to satisfy lll linter --- core/state/accessors_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/state/accessors_test.go b/core/state/accessors_test.go index fc30f8562f..42bdeae42a 100644 --- a/core/state/accessors_test.go +++ b/core/state/accessors_test.go @@ -18,7 +18,9 @@ func TestContractAccessors(t *testing.T) { addr := felt.NewUnsafeFromString[felt.Felt]("0x123") // storeContract stores a contract with the given values and fails the test on error. - storeContract := func(t *testing.T, disk db.KeyValueWriter, nonce, classHash string, height uint64) { + storeContract := func( + t *testing.T, disk db.KeyValueWriter, nonce, classHash string, height uint64, + ) { t.Helper() require.NoError(t, state.WriteContract( disk, addr, From 270cd942d2f4dc2b5ba1d505ee58ae626546c67e Mon Sep 17 00:00:00 2001 From: Ehsan-saradar Date: Tue, 30 Jun 2026 07:50:14 +0000 Subject: [PATCH 5/5] test(state): cover class overwrite and GetStateObject happy path --- core/state/accessors_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/core/state/accessors_test.go b/core/state/accessors_test.go index 42bdeae42a..ee0f82eeae 100644 --- a/core/state/accessors_test.go +++ b/core/state/accessors_test.go @@ -124,6 +124,28 @@ func TestClassAccessors(t *testing.T) { assert.Equal(t, []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x1")}, sierra.Program) }) + t.Run("overwrite reflects latest values", func(t *testing.T) { + disk := memory.New() + require.NoError(t, state.WriteClass(disk, classHash, newClass())) + + updated := &core.DeclaredClassDefinition{ + At: 99, + Class: &core.SierraClass{ + SemanticVersion: "0.2.0", + Program: []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x2")}, + }, + } + require.NoError(t, state.WriteClass(disk, classHash, updated)) + + got, err := state.GetClass(disk, classHash) + require.NoError(t, err) + assert.Equal(t, updated.At, got.At) + sierra, ok := got.Class.(*core.SierraClass) + require.True(t, ok) + assert.Equal(t, "0.2.0", sierra.SemanticVersion) + assert.Equal(t, []*felt.Felt{felt.NewUnsafeFromString[felt.Felt]("0x2")}, sierra.Program) + }) + t.Run("delete removes the class", func(t *testing.T) { disk := memory.New() require.NoError(t, state.WriteClass(disk, classHash, newClass())) @@ -280,4 +302,18 @@ func TestGetStateObject(t *testing.T) { _, err := state.GetStateObject(disk, nil, addr) assert.ErrorIs(t, err, db.ErrKeyNotFound) }) + + t.Run("returns a state object for an existing contract", func(t *testing.T) { + disk := memory.New() + require.NoError(t, state.WriteContract( + disk, addr, + felt.UnsafeFromString[felt.Felt]("0x1"), + felt.UnsafeFromString[felt.Felt]("0xabc"), + 42, + )) + + obj, err := state.GetStateObject(disk, nil, addr) + require.NoError(t, err) + assert.NotNil(t, obj) + }) }