mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
Fix state diff repetitive anchor slot bug (#16037)
**What type of PR is this?** Bug fix **What does this PR do? Why is it needed?** This PR fixes a bug in the state diff `getBaseAndDiffChain()` method. In the process of finding the diff chain indices, there could be a scenario where multiple levels return the same diff slot number not equal to the base (full snapshot) slot number. This resulted in multiple diff items being added to the diff chain for the same slot, but on different levels, which resulted in errors reading the diff. Fix: we keep a `lastSeenAnchorSlot` equal to the `BaseAnchorSlot` and update it every time we see a new anchor slot. We ignore if the current found anchor slot is equal to the `lastSeenAnchorSlot`. Scenario example: exponents: [20, 14, 10, 7, 5] offset: 0 slots saved: slot 2^11, and slot (2^11 + 2^5) slot to read: slot (2^11 + 2^5) resulting list of anchor slots (diff chain indices): [0, 0, 2^11, 2^11, 2^11 + 2^5]
This commit is contained in:
@@ -221,13 +221,15 @@ func (s *Store) getBaseAndDiffChain(offset uint64, slot primitives.Slot) (state.
|
||||
}
|
||||
|
||||
var diffChainItems []diffItem
|
||||
lastSeenAnchorSlot := baseAnchorSlot
|
||||
for i, exp := range exponents[1 : lvl+1] {
|
||||
span := math.PowerOf2(uint64(exp))
|
||||
diffSlot := rel / span * span
|
||||
if diffSlot == baseAnchorSlot {
|
||||
if diffSlot == lastSeenAnchorSlot {
|
||||
continue
|
||||
}
|
||||
diffChainItems = append(diffChainItems, diffItem{level: i + 1, slot: diffSlot + offset})
|
||||
lastSeenAnchorSlot = diffSlot
|
||||
}
|
||||
|
||||
baseSnapshot, err := s.getFullSnapshot(baseAnchorSlot)
|
||||
|
||||
@@ -278,6 +278,46 @@ func TestStateDiff_SaveAndReadDiff(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateDiff_SaveAndReadDiff_WithRepetitiveAnchorSlots(t *testing.T) {
|
||||
globalFlags := flags.GlobalFlags{
|
||||
StateDiffExponents: []int{20, 14, 10, 7, 5},
|
||||
}
|
||||
flags.Init(&globalFlags)
|
||||
|
||||
for v := range version.All() {
|
||||
t.Run(version.String(v), func(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
||||
err := setOffsetInDB(db, 0)
|
||||
|
||||
st, _ := createState(t, 0, v)
|
||||
require.NoError(t, err)
|
||||
err = db.saveStateByDiff(context.Background(), st)
|
||||
require.NoError(t, err)
|
||||
|
||||
slot := primitives.Slot(math.PowerOf2(11))
|
||||
st, _ = createState(t, slot, v)
|
||||
err = db.saveStateByDiff(context.Background(), st)
|
||||
require.NoError(t, err)
|
||||
|
||||
slot = primitives.Slot(math.PowerOf2(11) + math.PowerOf2(5))
|
||||
st, _ = createState(t, slot, v)
|
||||
err = db.saveStateByDiff(context.Background(), st)
|
||||
require.NoError(t, err)
|
||||
|
||||
readSt, err := db.stateByDiff(context.Background(), slot)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, readSt)
|
||||
|
||||
stSSZ, err := st.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
readStSSZ, err := readSt.MarshalSSZ()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, stSSZ, readStSSZ)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateDiff_SaveAndReadDiff_MultipleLevels(t *testing.T) {
|
||||
setDefaultExponents()
|
||||
|
||||
|
||||
3
changelog/bastin_state-diff-anchor-slot-bug.md
Normal file
3
changelog/bastin_state-diff-anchor-slot-bug.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Fixed
|
||||
|
||||
- Fix state diff repetitive anchor slot bug.
|
||||
Reference in New Issue
Block a user