Skip to content

Commit b845222

Browse files
Integrate state-diff into HasState() (#16045)
**What type of PR is this?** Feature **What does this PR do? Why is it needed?** This PR adds integrates state-diff into `HasState()`. One thing to note: we are assuming that, for a given block root, that has either a state summary or a block in db, and also falls in the state diff tree, then there must exist a state. This function could return true, even when there is no actual state saved due to any error. But this is fine, because we have that assumption throughout the whole state diff feature.
1 parent 5bbdebe commit b845222

File tree

4 files changed

+79
-0
lines changed

4 files changed

+79
-0
lines changed

beacon-chain/db/kv/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ go_test(
142142
"@com_github_golang_snappy//:go_default_library",
143143
"@com_github_pkg_errors//:go_default_library",
144144
"@com_github_sirupsen_logrus//:go_default_library",
145+
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
145146
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
146147
"@io_etcd_go_bbolt//:go_default_library",
147148
"@org_golang_google_protobuf//proto:go_default_library",

beacon-chain/db/kv/state.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,16 @@ func (s *Store) storeValidatorEntriesSeparately(ctx context.Context, tx *bolt.Tx
427427
func (s *Store) HasState(ctx context.Context, blockRoot [32]byte) bool {
428428
_, span := trace.StartSpan(ctx, "BeaconDB.HasState")
429429
defer span.End()
430+
431+
if features.Get().EnableStateDiff {
432+
hasState, err := s.hasStateUsingStateDiff(ctx, blockRoot)
433+
if err != nil {
434+
log.WithError(err).Error(fmt.Sprintf("error checking state existence using state-diff"))
435+
return false
436+
}
437+
return hasState
438+
}
439+
430440
hasState := false
431441
err := s.db.View(func(tx *bolt.Tx) error {
432442
bkt := tx.Bucket(stateBucket)
@@ -1053,3 +1063,13 @@ func (s *Store) getStateUsingStateDiff(ctx context.Context, blockRoot [32]byte)
10531063

10541064
return st, nil
10551065
}
1066+
1067+
func (s *Store) hasStateUsingStateDiff(ctx context.Context, blockRoot [32]byte) (bool, error) {
1068+
slot, err := s.SlotByBlockRoot(ctx, blockRoot)
1069+
if err != nil {
1070+
return false, err
1071+
}
1072+
1073+
stateLvl := computeLevel(s.getOffset(), slot)
1074+
return stateLvl != -1, nil
1075+
}

beacon-chain/db/kv/state_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"github.com/OffchainLabs/prysm/v7/testing/assert"
2727
"github.com/OffchainLabs/prysm/v7/testing/require"
2828
"github.com/OffchainLabs/prysm/v7/testing/util"
29+
logTest "github.com/sirupsen/logrus/hooks/test"
2930
bolt "go.etcd.io/bbolt"
3031
)
3132

@@ -1573,3 +1574,57 @@ func TestStore_CanSaveRetrieveStateUsingStateDiff(t *testing.T) {
15731574
})
15741575
})
15751576
}
1577+
1578+
func TestStore_HasStateUsingStateDiff(t *testing.T) {
1579+
t.Run("No state summary or block", func(t *testing.T) {
1580+
hook := logTest.NewGlobal()
1581+
db := setupDB(t)
1582+
featCfg := &features.Flags{}
1583+
featCfg.EnableStateDiff = true
1584+
reset := features.InitWithReset(featCfg)
1585+
defer reset()
1586+
setDefaultStateDiffExponents()
1587+
1588+
err := setOffsetInDB(db, 0)
1589+
require.NoError(t, err)
1590+
1591+
hasSt := db.HasState(t.Context(), [32]byte{'A'})
1592+
require.Equal(t, false, hasSt)
1593+
require.LogsContain(t, hook, "neither state summary nor block found")
1594+
})
1595+
1596+
t.Run("slot in tree or not", func(t *testing.T) {
1597+
db := setupDB(t)
1598+
featCfg := &features.Flags{}
1599+
featCfg.EnableStateDiff = true
1600+
reset := features.InitWithReset(featCfg)
1601+
defer reset()
1602+
setDefaultStateDiffExponents()
1603+
1604+
err := setOffsetInDB(db, 0)
1605+
require.NoError(t, err)
1606+
1607+
testCases := []struct {
1608+
slot primitives.Slot
1609+
expected bool
1610+
}{
1611+
{slot: 1, expected: false}, // slot 1 not in tree
1612+
{slot: 32, expected: true}, // slot 32 in tree
1613+
{slot: 0, expected: true}, // slot 0 in tree
1614+
{slot: primitives.Slot(math.PowerOf2(21)), expected: true}, // slot in tree
1615+
{slot: primitives.Slot(math.PowerOf2(21) - 1), expected: false}, // slot not in tree
1616+
{slot: primitives.Slot(math.PowerOf2(22)), expected: true}, // slot in tree
1617+
}
1618+
1619+
for _, tc := range testCases {
1620+
r := bytesutil.ToBytes32([]byte{'A'})
1621+
ss := &ethpb.StateSummary{Slot: tc.slot, Root: r[:]}
1622+
err = db.SaveStateSummary(t.Context(), ss)
1623+
require.NoError(t, err)
1624+
1625+
hasSt := db.HasState(t.Context(), r)
1626+
require.Equal(t, tc.expected, hasSt)
1627+
}
1628+
1629+
})
1630+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
### Added
2+
3+
- Integrate state-diff into `HasState()`.

0 commit comments

Comments
 (0)