diff --git a/beacon-chain/state/state-native/setters_misc.go b/beacon-chain/state/state-native/setters_misc.go index bf855bcd6..e5c4b4e65 100644 --- a/beacon-chain/state/state-native/setters_misc.go +++ b/beacon-chain/state/state-native/setters_misc.go @@ -6,6 +6,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil" fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/container/slice" "github.com/prysmaticlabs/prysm/v5/crypto/hash" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" @@ -198,9 +199,14 @@ func (b *BeaconState) addDirtyIndices(index types.FieldIndex, indices []uint64) return } totalIndicesLen := len(b.dirtyIndices[index]) + len(indices) + // Reduce duplicates to verify that these are indeed unique. + if totalIndicesLen > indicesLimit { + b.dirtyIndices[index] = slice.SetUint64(b.dirtyIndices[index]) + totalIndicesLen = len(b.dirtyIndices[index]) + len(indices) + } if totalIndicesLen > indicesLimit { b.rebuildTrie[index] = true - b.dirtyIndices[index] = []uint64{} + b.dirtyIndices[index] = make([]uint64, 0, indicesLimit) } else { b.dirtyIndices[index] = append(b.dirtyIndices[index], indices...) } diff --git a/beacon-chain/state/state-native/state_test.go b/beacon-chain/state/state-native/state_test.go index a7070d886..faed7b7f6 100644 --- a/beacon-chain/state/state-native/state_test.go +++ b/beacon-chain/state/state-native/state_test.go @@ -416,6 +416,26 @@ func TestCopyAllTries(t *testing.T) { assert.NotEqual(t, rt, newRt) } +func TestDuplicateDirtyIndices(t *testing.T) { + newState := &BeaconState{ + rebuildTrie: make(map[types.FieldIndex]bool), + dirtyIndices: make(map[types.FieldIndex][]uint64), + } + for i := uint64(0); i < indicesLimit-5; i++ { + newState.dirtyIndices[types.Balances] = append(newState.dirtyIndices[types.Balances], i) + } + // Append duplicates + newState.dirtyIndices[types.Balances] = append(newState.dirtyIndices[types.Balances], []uint64{0, 1, 2, 3, 4}...) + + // We would remove the duplicates and stay under the threshold + newState.addDirtyIndices(types.Balances, []uint64{9997, 9998}) + assert.Equal(t, false, newState.rebuildTrie[types.Balances]) + + // We would trigger above the threshold. + newState.addDirtyIndices(types.Balances, []uint64{10000, 10001, 10002, 10003}) + assert.Equal(t, true, newState.rebuildTrie[types.Balances]) +} + func generateState(t *testing.T) state.BeaconState { count := uint64(100) vals := make([]*ethpb.Validator, 0, count) diff --git a/container/slice/slice.go b/container/slice/slice.go index 2cd81f96d..c39c371d3 100644 --- a/container/slice/slice.go +++ b/container/slice/slice.go @@ -94,7 +94,7 @@ func UnionUint64(s ...[]uint64) []uint64 { // values from the provided list of indices. func SetUint64(a []uint64) []uint64 { // Remove duplicates indices. - intMap := map[uint64]bool{} + intMap := make(map[uint64]bool, len(a)) cleanedIndices := make([]uint64, 0, len(a)) for _, idx := range a { if intMap[idx] {