Make the multi-value slice permanent (#15414)

* Remove Old State Paths

* Changelog

* Gazelle

* Lint

* Fix State Tests

* fix tests, update native state code

* move ErrOutOfBounds error from consensus types to mvslice

* fix TestStreamEvents_OperationsEvents

* add missing gc to fuzz tests

* more test fixes

* build fix

---------

Co-authored-by: nisdas <nishdas93@gmail.com>
This commit is contained in:
Radosław Kapka
2025-07-08 19:45:20 +02:00
committed by GitHub
parent 961ea05454
commit 7025e50a6c
38 changed files with 490 additions and 1707 deletions

View File

@@ -2,7 +2,6 @@ package blockchain
import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
@@ -17,9 +16,6 @@ var stateDefragmentationTime = promauto.NewSummary(prometheus.SummaryOpts{
// a higher number of fragmented indexes are reallocated to a new separate slice for
// that field.
func (s *Service) defragmentState(st state.BeaconState) {
if !features.Get().EnableExperimentalState {
return
}
startTime := time.Now()
st.Defragment()
elapsedTime := time.Since(startTime)

View File

@@ -8,16 +8,6 @@ import (
"github.com/OffchainLabs/prysm/v6/testing/util"
)
func TestReportEpochMetrics_BadHeadState(t *testing.T) {
s, err := util.NewBeaconState()
require.NoError(t, err)
h, err := util.NewBeaconState()
require.NoError(t, err)
require.NoError(t, h.SetValidators(nil))
err = reportEpochMetrics(t.Context(), s, h)
require.ErrorContains(t, "failed to initialize precompute: state has nil validator slice", err)
}
func TestReportEpochMetrics_BadAttestation(t *testing.T) {
s, err := util.NewBeaconState()
require.NoError(t, err)

View File

@@ -31,7 +31,7 @@ func Test_BaseReward(t *testing.T) {
valIdx: 2,
st: genState(1),
want: 0,
errString: "validator index 2 does not exist",
errString: "index 2 out of bounds",
},
{
name: "active balance is 32eth",
@@ -89,7 +89,7 @@ func Test_BaseRewardWithTotalBalance(t *testing.T) {
valIdx: 2,
activeBalance: 1,
want: 0,
errString: "validator index 2 does not exist",
errString: "index 2 out of bounds",
},
{
name: "active balance is 1",

View File

@@ -119,6 +119,7 @@ func TestFuzzEth1DataHasEnoughSupport_10000(t *testing.T) {
require.NoError(t, err)
_, err = Eth1DataHasEnoughSupport(s, eth1data)
_ = err
fuzz.FreeMemory(i)
}
}
@@ -319,6 +320,7 @@ func TestFuzzverifyDeposit_10000(t *testing.T) {
require.NoError(t, err)
err = VerifyDeposit(s, deposit)
_ = err
fuzz.FreeMemory(i)
}
}
@@ -382,5 +384,6 @@ func TestFuzzVerifyExit_10000(t *testing.T) {
_ = err
err = VerifyExitAndSignature(val, s, ve)
_ = err
fuzz.FreeMemory(i)
}
}

View File

@@ -100,7 +100,7 @@ func TestIsCurrentEpochSyncCommittee_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
ok, err := helpers.IsCurrentPeriodSyncCommittee(state, 12390192)
require.ErrorContains(t, "validator index 12390192 does not exist", err)
require.ErrorContains(t, "index 12390192 out of bounds", err)
require.Equal(t, false, ok)
}
@@ -187,7 +187,7 @@ func TestIsNextEpochSyncCommittee_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
ok, err := helpers.IsNextPeriodSyncCommittee(state, 120391029)
require.ErrorContains(t, "validator index 120391029 does not exist", err)
require.ErrorContains(t, "index 120391029 out of bounds", err)
require.Equal(t, false, ok)
}
@@ -287,7 +287,7 @@ func TestCurrentEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
index, err := helpers.CurrentPeriodSyncSubcommitteeIndices(state, 129301923)
require.ErrorContains(t, "validator index 129301923 does not exist", err)
require.ErrorContains(t, "index 129301923 out of bounds", err)
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
}
@@ -374,7 +374,7 @@ func TestNextEpochSyncSubcommitteeIndices_DoesNotExist(t *testing.T) {
require.NoError(t, state.SetNextSyncCommittee(syncCommittee))
index, err := helpers.NextPeriodSyncSubcommitteeIndices(state, 21093019)
require.ErrorContains(t, "validator index 21093019 does not exist", err)
require.ErrorContains(t, "index 21093019 out of bounds", err)
require.DeepEqual(t, []primitives.CommitteeIndex(nil), index)
}

View File

@@ -561,17 +561,6 @@ func TestActiveValidatorIndices(t *testing.T) {
},
want: []primitives.ValidatorIndex{0, 2, 3},
},*/
{
name: "impossible_zero_validators", // Regression test for issue #13051
args: args{
state: &ethpb.BeaconState{
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
Validators: make([]*ethpb.Validator, 0),
},
epoch: 10,
},
wantedErr: "state has nil validator slice",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@@ -46,11 +46,11 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//container/multi-value-slice:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",

View File

@@ -22,8 +22,8 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/rpc/eth/shared"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
mvslice "github.com/OffchainLabs/prysm/v6/container/multi-value-slice"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/httputil"
@@ -501,7 +501,7 @@ func (s *Server) SubmitVoluntaryExit(w http.ResponseWriter, r *http.Request) {
}
val, err := headState.ValidatorAtIndexReadOnly(exit.Exit.ValidatorIndex)
if err != nil {
if errors.Is(err, consensus_types.ErrOutOfBounds) {
if errors.Is(err, mvslice.ErrOutOfBounds) {
httputil.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
return
}

View File

@@ -529,6 +529,7 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
st := tc.getState()
v := &eth.Validator{ExitEpoch: math.MaxUint64, EffectiveBalance: params.BeaconConfig().MinActivationBalance, WithdrawalCredentials: make([]byte, 32)}
require.NoError(t, st.SetValidators([]*eth.Validator{v}))
require.NoError(t, st.SetBalances([]uint64{0}))
currentSlot := primitives.Slot(0)
// to avoid slot processing
require.NoError(t, st.SetSlot(currentSlot+1))

View File

@@ -33,10 +33,10 @@ go_library(
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/primitives:go_default_library",
"//consensus-types/validator:go_default_library",
"//container/multi-value-slice:go_default_library",
"//crypto/bls/common:go_default_library",
"//encoding/bytesutil:go_default_library",
"//monitoring/tracing/trace:go_default_library",

View File

@@ -26,9 +26,9 @@ import (
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
validator2 "github.com/OffchainLabs/prysm/v6/consensus-types/validator"
mvslice "github.com/OffchainLabs/prysm/v6/container/multi-value-slice"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v6/network/httputil"
@@ -570,7 +570,7 @@ func (s *Server) SubmitBeaconCommitteeSubscription(w http.ResponseWriter, r *htt
subscriptions[i] = consensusItem
val, err := st.ValidatorAtIndexReadOnly(consensusItem.ValidatorIndex)
if err != nil {
if errors.Is(err, consensus_types.ErrOutOfBounds) {
if errors.Is(err, mvslice.ErrOutOfBounds) {
httputil.HandleError(w, "Could not get validator: "+err.Error(), http.StatusBadRequest)
return
}

View File

@@ -31,7 +31,6 @@ go_test(
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",

View File

@@ -7,7 +7,6 @@ import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
mvslice "github.com/OffchainLabs/prysm/v6/container/multi-value-slice"
@@ -21,32 +20,19 @@ func TestFieldTrie_NewTrie(t *testing.T) {
t.Run("native state", func(t *testing.T) {
runNewTrie(t)
})
t.Run("native state with multivalue slice", func(t *testing.T) {
cfg := &features.Flags{}
cfg.EnableExperimentalState = true
reset := features.InitWithReset(cfg)
runNewTrie(t)
reset()
})
}
func runNewTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 40)
roots := newState.BlockRoots()
var elements interface{}
blockRoots := make([][32]byte, len(roots))
for i, r := range roots {
blockRoots[i] = [32]byte(r)
}
elements = customtypes.BlockRoots(blockRoots)
if features.Get().EnableExperimentalState {
mvRoots := buildTestCompositeSlice[[32]byte](blockRoots)
elements = mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvRoots,
}
mvRoots := buildTestCompositeSlice[[32]byte](blockRoots)
elements := mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvRoots,
}
trie, err := NewFieldTrie(types.BlockRoots, types.BasicArray, elements, uint64(params.BeaconConfig().SlotsPerHistoricalRoot))
@@ -69,27 +55,15 @@ func TestFieldTrie_RecomputeTrie(t *testing.T) {
t.Run("native state", func(t *testing.T) {
runRecomputeTrie(t)
})
t.Run("native state with multivalue slice", func(t *testing.T) {
cfg := &features.Flags{}
cfg.EnableExperimentalState = true
reset := features.InitWithReset(cfg)
runRecomputeTrie(t)
reset()
})
}
func runRecomputeTrie(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
var elements interface{}
elements = newState.Validators()
if features.Get().EnableExperimentalState {
mvRoots := buildTestCompositeSlice[*ethpb.Validator](newState.Validators())
elements = mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvRoots,
}
mvRoots := buildTestCompositeSlice[*ethpb.Validator](newState.Validators())
elements := mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvRoots,
}
trie, err := NewFieldTrie(types.Validators, types.CompositeArray, elements, params.BeaconConfig().ValidatorRegistryLimit)
@@ -125,26 +99,14 @@ func TestFieldTrie_RecomputeTrie_CompressedArray(t *testing.T) {
t.Run("native state", func(t *testing.T) {
runRecomputeTrie_CompressedArray(t)
})
t.Run("native state with multivalue slice", func(t *testing.T) {
cfg := &features.Flags{}
cfg.EnableExperimentalState = true
reset := features.InitWithReset(cfg)
runRecomputeTrie_CompressedArray(t)
reset()
})
}
func runRecomputeTrie_CompressedArray(t *testing.T) {
newState, _ := util.DeterministicGenesisState(t, 32)
var elements interface{}
elements = newState.Balances()
if features.Get().EnableExperimentalState {
mvBals := buildTestCompositeSlice(newState.Balances())
elements = mvslice.MultiValueSliceComposite[uint64]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvBals,
}
mvBals := buildTestCompositeSlice(newState.Balances())
elements := mvslice.MultiValueSliceComposite[uint64]{
Identifiable: mockIdentifier{},
MultiValueSlice: mvBals,
}
trie, err := NewFieldTrie(types.Balances, types.CompressedArray, elements, stateutil.ValidatorLimitForBalancesChunks())

View File

@@ -59,10 +59,8 @@ go_library(
"//beacon-chain/state/state-native/custom-types:go_default_library",
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types:go_default_library",
"//consensus-types/blocks:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//consensus-types/primitives:go_default_library",
@@ -135,7 +133,6 @@ go_test(
"//beacon-chain/state/state-native/types:go_default_library",
"//beacon-chain/state/stateutil:go_default_library",
"//beacon-chain/state/testing:go_default_library",
"//config/features:go_default_library",
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/blocks:go_default_library",

View File

@@ -13,9 +13,7 @@ Add the new getter and setter to `/beacon-chain/state/interfaces.go`.
- Update `spec_parameters.go`.
- Update `state_trie.go`:
- Add a `[version]Fields` variable that contains all fields of the new state version.
- Add a `[version]SharedFieldRefCount` constant that represents the number of fields whose references are shared between states.
- Add an `experimentalState[Version]SharedFieldCountRef` constant that represents the number of **non multi-value slice** fields whose references are shared
between states.
- Add a `[version]SharedFieldRefCount` constant that represents the number of fields whose references are shared between states. Multi-value slice references are not shared in this way so don't include them.
- Add the following functions: `InitializeFromProto[Version]()`, `InitializeFromProtoUnsafe[Version]()`.
- Update the following functions: `Copy()`, `initializeMerkleLayers()`, `RecordStateMetrics()` (applies only to multi-value slice fields), `rootSelector()`,
`finalizerCleanup()` (applies only to multi-value slice fields).

View File

@@ -8,7 +8,6 @@ import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
@@ -24,19 +23,14 @@ type BeaconState struct {
slot primitives.Slot
fork *ethpb.Fork
latestBlockHeader *ethpb.BeaconBlockHeader
blockRoots customtypes.BlockRoots
blockRootsMultiValue *MultiValueBlockRoots
stateRoots customtypes.StateRoots
stateRootsMultiValue *MultiValueStateRoots
historicalRoots customtypes.HistoricalRoots
eth1Data *ethpb.Eth1Data
eth1DataVotes []*ethpb.Eth1Data
eth1DepositIndex uint64
validators []*ethpb.Validator
validatorsMultiValue *MultiValueValidators
balances []uint64
balancesMultiValue *MultiValueBalances
randaoMixes customtypes.RandaoMixes
randaoMixesMultiValue *MultiValueRandaoMixes
slashings []uint64
previousEpochAttestations []*ethpb.PendingAttestation
@@ -47,7 +41,6 @@ type BeaconState struct {
previousJustifiedCheckpoint *ethpb.Checkpoint
currentJustifiedCheckpoint *ethpb.Checkpoint
finalizedCheckpoint *ethpb.Checkpoint
inactivityScores []uint64
inactivityScoresMultiValue *MultiValueInactivityScores
currentSyncCommittee *ethpb.SyncCommittee
nextSyncCommittee *ethpb.SyncCommittee
@@ -130,28 +123,12 @@ type beaconStateMarshalable struct {
}
func (b *BeaconState) MarshalJSON() ([]byte, error) {
var bRoots customtypes.BlockRoots
var sRoots customtypes.StateRoots
var mixes customtypes.RandaoMixes
var balances []uint64
var inactivityScores []uint64
var vals []*ethpb.Validator
if features.Get().EnableExperimentalState {
bRoots = b.blockRootsMultiValue.Value(b)
sRoots = b.stateRootsMultiValue.Value(b)
mixes = b.randaoMixesMultiValue.Value(b)
balances = b.balancesMultiValue.Value(b)
inactivityScores = b.inactivityScoresMultiValue.Value(b)
vals = b.validatorsMultiValue.Value(b)
} else {
bRoots = b.blockRoots
sRoots = b.stateRoots
mixes = b.randaoMixes
balances = b.balances
inactivityScores = b.inactivityScores
vals = b.validators
}
bRoots := b.blockRootsMultiValue.Value(b)
sRoots := b.stateRootsMultiValue.Value(b)
mixes := b.randaoMixesMultiValue.Value(b)
balances := b.balancesMultiValue.Value(b)
inactivityScores := b.inactivityScoresMultiValue.Value(b)
vals := b.validatorsMultiValue.Value(b)
marshalable := &beaconStateMarshalable{
Version: b.version,

View File

@@ -2,10 +2,7 @@ package state_native
import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/config/features"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/pkg/errors"
)
// LatestBlockHeader stored within the beacon state.
@@ -58,13 +55,10 @@ func (b *BeaconState) BlockRoots() [][]byte {
}
func (b *BeaconState) blockRootsVal() customtypes.BlockRoots {
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue == nil {
return nil
}
return b.blockRootsMultiValue.Value(b)
if b.blockRootsMultiValue == nil {
return nil
}
return b.blockRoots
return b.blockRootsMultiValue.Value(b)
}
// BlockRootAtIndex retrieves a specific block root based on an
@@ -73,33 +67,12 @@ func (b *BeaconState) BlockRootAtIndex(idx uint64) ([]byte, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue == nil {
return []byte{}, nil
}
r, err := b.blockRootsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
if b.blockRoots == nil {
if b.blockRootsMultiValue == nil {
return []byte{}, nil
}
r, err := b.blockRootAtIndex(idx)
r, err := b.blockRootsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
// blockRootAtIndex retrieves a specific block root based on an
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) blockRootAtIndex(idx uint64) ([32]byte, error) {
if uint64(len(b.blockRoots)) <= idx {
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "block root index %d does not exist", idx)
}
return b.blockRoots[idx], nil
}

View File

@@ -4,7 +4,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/runtime/version"
)
@@ -82,11 +81,7 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er
return 0, 0, 0, ErrNilParticipation
}
if features.Get().EnableExperimentalState {
return stateutil.UnrealizedCheckpointBalances(cp, pp, stateutil.NewValMultiValueSliceReader(b.validatorsMultiValue, b), currentEpoch)
} else {
return stateutil.UnrealizedCheckpointBalances(cp, pp, stateutil.NewValSliceReader(b.validators), currentEpoch)
}
return stateutil.UnrealizedCheckpointBalances(cp, pp, stateutil.NewValMultiValueSliceReader(b.validatorsMultiValue, b), currentEpoch)
}
// currentEpochParticipationVal corresponding to participation bits on the beacon chain.

View File

@@ -2,9 +2,6 @@ package state_native
import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/config/features"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/pkg/errors"
)
// RandaoMixes of block proposers on the beacon chain.
@@ -20,13 +17,10 @@ func (b *BeaconState) RandaoMixes() [][]byte {
}
func (b *BeaconState) randaoMixesVal() customtypes.RandaoMixes {
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return nil
}
return b.randaoMixesMultiValue.Value(b)
if b.randaoMixesMultiValue == nil {
return nil
}
return b.randaoMixes
return b.randaoMixesMultiValue.Value(b)
}
// RandaoMixAtIndex retrieves a specific block root based on an
@@ -35,36 +29,14 @@ func (b *BeaconState) RandaoMixAtIndex(idx uint64) ([]byte, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return nil, nil
}
r, err := b.randaoMixesMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
if b.randaoMixes == nil {
if b.randaoMixesMultiValue == nil {
return nil, nil
}
m, err := b.randaoMixAtIndex(idx)
r, err := b.randaoMixesMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return m[:], nil
}
// randaoMixAtIndex retrieves a specific block root based on an
// input index value.
// This assumes that a lock is already held on BeaconState.
func (b *BeaconState) randaoMixAtIndex(idx uint64) ([32]byte, error) {
if uint64(len(b.randaoMixes)) <= idx {
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "randao mix index %d does not exist", idx)
}
return b.randaoMixes[idx], nil
return r[:], nil
}
// RandaoMixesLength returns the length of the randao mixes slice.
@@ -72,14 +44,8 @@ func (b *BeaconState) RandaoMixesLength() int {
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue == nil {
return 0
}
return b.randaoMixesMultiValue.Len(b)
}
if b.randaoMixes == nil {
if b.randaoMixesMultiValue == nil {
return 0
}
return len(b.randaoMixes)
return b.randaoMixesMultiValue.Len(b)
}

View File

@@ -2,8 +2,6 @@ package state_native
import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/config/features"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/pkg/errors"
@@ -24,20 +22,14 @@ func (b *BeaconState) ToProtoUnsafe() interface{} {
var bals []uint64
var inactivityScores []uint64
if features.Get().EnableExperimentalState {
if b.balancesMultiValue != nil {
bals = b.balancesMultiValue.Value(b)
}
if b.inactivityScoresMultiValue != nil {
inactivityScores = b.inactivityScoresMultiValue.Value(b)
}
if b.validatorsMultiValue != nil {
vals = b.validatorsMultiValue.Value(b)
}
} else {
bals = b.balances
inactivityScores = b.inactivityScores
vals = b.validators
if b.balancesMultiValue != nil {
bals = b.balancesMultiValue.Value(b)
}
if b.inactivityScoresMultiValue != nil {
inactivityScores = b.inactivityScoresMultiValue.Value(b)
}
if b.validatorsMultiValue != nil {
vals = b.validatorsMultiValue.Value(b)
}
switch b.version {
@@ -536,13 +528,10 @@ func (b *BeaconState) StateRoots() [][]byte {
}
func (b *BeaconState) stateRootsVal() customtypes.StateRoots {
if features.Get().EnableExperimentalState {
if b.stateRootsMultiValue == nil {
return nil
}
return b.stateRootsMultiValue.Value(b)
if b.stateRootsMultiValue == nil {
return nil
}
return b.stateRoots
return b.stateRootsMultiValue.Value(b)
}
// StateRootAtIndex retrieves a specific state root based on an
@@ -551,39 +540,16 @@ func (b *BeaconState) StateRootAtIndex(idx uint64) ([]byte, error) {
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.stateRootsMultiValue == nil {
return nil, nil
}
r, err := b.stateRootsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
if b.stateRoots == nil {
if b.stateRootsMultiValue == nil {
return nil, nil
}
r, err := b.stateRootAtIndex(idx)
r, err := b.stateRootsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
return r[:], nil
}
// stateRootAtIndex retrieves a specific state root based on an
// input index value.
// This assumes that a lock is already held on BeaconState.
//
// WARNING: This function does not work with the multi-value slice feature.
func (b *BeaconState) stateRootAtIndex(idx uint64) ([32]byte, error) {
if uint64(len(b.stateRoots)) <= idx {
return [32]byte{}, errors.Wrapf(consensus_types.ErrOutOfBounds, "state root index %d does not exist", idx)
}
return b.stateRoots[idx], nil
}
// ProtobufBeaconStatePhase0 transforms an input into beacon state in the form of protobuf.
// Error is returned if the input is not type protobuf beacon state.
func ProtobufBeaconStatePhase0(s interface{}) (*ethpb.BeaconState, error) {

View File

@@ -2,16 +2,12 @@ package state_native
import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/runtime/version"
"github.com/pkg/errors"
)
// Validators participating in consensus on the beacon chain.
@@ -32,17 +28,10 @@ func (b *BeaconState) ValidatorsReadOnly() []state.ReadOnlyValidator {
func (b *BeaconState) validatorsVal() []*ethpb.Validator {
var v []*ethpb.Validator
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue == nil {
return nil
}
v = b.validatorsMultiValue.Value(b)
} else {
if b.validators == nil {
return nil
}
v = b.validators
if b.validatorsMultiValue == nil {
return nil
}
v = b.validatorsMultiValue.Value(b)
res := make([]*ethpb.Validator, len(v))
for i := 0; i < len(res); i++ {
@@ -56,18 +45,10 @@ func (b *BeaconState) validatorsVal() []*ethpb.Validator {
}
func (b *BeaconState) validatorsReadOnlyVal() []state.ReadOnlyValidator {
var v []*ethpb.Validator
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue == nil {
return nil
}
v = b.validatorsMultiValue.Value(b)
} else {
if b.validators == nil {
return nil
}
v = b.validators
if b.validatorsMultiValue == nil {
return nil
}
v := b.validatorsMultiValue.Value(b)
res := make([]state.ReadOnlyValidator, len(v))
var err error
@@ -84,34 +65,11 @@ func (b *BeaconState) validatorsReadOnlyVal() []state.ReadOnlyValidator {
return res
}
// references of validators participating in consensus on the beacon chain.
// This assumes that a lock is already held on BeaconState. This does not
// copy fully and instead just copies the reference.
func (b *BeaconState) validatorsReferences() []*ethpb.Validator {
if b.validators == nil {
return nil
}
res := make([]*ethpb.Validator, len(b.validators), len(b.validators)+int(params.BeaconConfig().MaxDeposits))
for i := 0; i < len(res); i++ {
validator := b.validators[i]
if validator == nil {
continue
}
// copy validator reference instead.
res[i] = validator
}
return res
}
func (b *BeaconState) validatorsLen() int {
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue == nil {
return 0
}
return b.validatorsMultiValue.Len(b)
if b.validatorsMultiValue == nil {
return 0
}
return len(b.validators)
return b.validatorsMultiValue.Len(b)
}
// ValidatorAtIndex is the validator at the provided index.
@@ -123,25 +81,14 @@ func (b *BeaconState) ValidatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Va
}
func (b *BeaconState) validatorAtIndex(idx primitives.ValidatorIndex) (*ethpb.Validator, error) {
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue == nil {
return &ethpb.Validator{}, nil
}
v, err := b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return nil, err
}
return ethpb.CopyValidator(v), nil
}
if b.validators == nil {
if b.validatorsMultiValue == nil {
return &ethpb.Validator{}, nil
}
if uint64(len(b.validators)) <= uint64(idx) {
return nil, errors.Wrapf(consensus_types.ErrOutOfBounds, "validator index %d does not exist", idx)
v, err := b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return nil, err
}
val := b.validators[idx]
return ethpb.CopyValidator(val), nil
return ethpb.CopyValidator(v), nil
}
// ValidatorAtIndexReadOnly is the validator at the provided index. This method
@@ -154,25 +101,14 @@ func (b *BeaconState) ValidatorAtIndexReadOnly(idx primitives.ValidatorIndex) (s
}
func (b *BeaconState) validatorAtIndexReadOnly(idx primitives.ValidatorIndex) (state.ReadOnlyValidator, error) {
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue == nil {
return nil, state.ErrNilValidatorsInState
}
v, err := b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return nil, err
}
return NewValidator(v)
}
if b.validators == nil {
if b.validatorsMultiValue == nil {
return nil, state.ErrNilValidatorsInState
}
if uint64(len(b.validators)) <= uint64(idx) {
return nil, errors.Wrapf(consensus_types.ErrOutOfBounds, "validator index %d does not exist", idx)
v, err := b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return nil, err
}
val := b.validators[idx]
return NewValidator(val)
return NewValidator(v)
}
// ValidatorIndexByPubkey returns a given validator by its 48-byte public key.
@@ -183,12 +119,7 @@ func (b *BeaconState) ValidatorIndexByPubkey(key [fieldparams.BLSPubkeyLength]by
b.lock.RLock()
defer b.lock.RUnlock()
var numOfVals int
if features.Get().EnableExperimentalState {
numOfVals = b.validatorsMultiValue.Len(b)
} else {
numOfVals = len(b.validators)
}
numOfVals := b.validatorsMultiValue.Len(b)
idx, ok := b.valMapHandler.Get(key)
if ok && primitives.ValidatorIndex(numOfVals) <= idx {
@@ -203,18 +134,9 @@ func (b *BeaconState) PubkeyAtIndex(idx primitives.ValidatorIndex) [fieldparams.
b.lock.RLock()
defer b.lock.RUnlock()
var v *ethpb.Validator
if features.Get().EnableExperimentalState {
var err error
v, err = b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return [fieldparams.BLSPubkeyLength]byte{}
}
} else {
if uint64(idx) >= uint64(len(b.validators)) {
return [fieldparams.BLSPubkeyLength]byte{}
}
v = b.validators[idx]
v, err := b.validatorsMultiValue.At(b, uint64(idx))
if err != nil {
return [fieldparams.BLSPubkeyLength]byte{}
}
if v == nil {
@@ -231,20 +153,10 @@ func (b *BeaconState) AggregateKeyFromIndices(idxs []uint64) (bls.PublicKey, err
pubKeys := make([][]byte, len(idxs))
for i, idx := range idxs {
var v *ethpb.Validator
if features.Get().EnableExperimentalState {
var err error
v, err = b.validatorsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
} else {
if idx >= uint64(len(b.validators)) {
return nil, consensus_types.ErrOutOfBounds
}
v = b.validators[idx]
v, err := b.validatorsMultiValue.At(b, idx)
if err != nil {
return nil, err
}
if v == nil {
return nil, ErrNilWrappedValidator
}
@@ -261,15 +173,11 @@ func (b *BeaconState) PublicKeys() ([][fieldparams.BLSPubkeyLength]byte, error)
l := b.validatorsLen()
res := make([][fieldparams.BLSPubkeyLength]byte, l)
for i := 0; i < l; i++ {
if features.Get().EnableExperimentalState {
val, err := b.validatorsMultiValue.At(b, uint64(i))
if err != nil {
return nil, err
}
copy(res[i][:], val.PublicKey)
} else {
copy(res[i][:], b.validators[i].PublicKey)
val, err := b.validatorsMultiValue.At(b, uint64(i))
if err != nil {
return nil, err
}
copy(res[i][:], val.PublicKey)
}
return res, nil
}
@@ -289,30 +197,6 @@ func (b *BeaconState) ReadFromEveryValidator(f func(idx int, val state.ReadOnlyV
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
return b.readFromEveryValidatorMVSlice(f)
}
if b.validators == nil {
return state.ErrNilValidatorsInState
}
validators := b.validators
for i, v := range validators {
v, err := NewValidator(v)
if err != nil {
return err
}
if err = f(i, v); err != nil {
return err
}
}
return nil
}
// WARNING: This function works only for the multi-value slice feature.
func (b *BeaconState) readFromEveryValidatorMVSlice(f func(idx int, val state.ReadOnlyValidator) error) error {
if b.validatorsMultiValue == nil {
return state.ErrNilValidatorsInState
}
@@ -342,18 +226,10 @@ func (b *BeaconState) Balances() []uint64 {
}
func (b *BeaconState) balancesVal() []uint64 {
if features.Get().EnableExperimentalState {
if b.balancesMultiValue == nil {
return nil
}
return b.balancesMultiValue.Value(b)
}
if b.balances == nil {
if b.balancesMultiValue == nil {
return nil
}
res := make([]uint64, len(b.balances))
copy(res, b.balances)
return res
return b.balancesMultiValue.Value(b)
}
// BalanceAtIndex of validator with the provided index.
@@ -365,19 +241,10 @@ func (b *BeaconState) BalanceAtIndex(idx primitives.ValidatorIndex) (uint64, err
}
func (b *BeaconState) balanceAtIndex(idx primitives.ValidatorIndex) (uint64, error) {
if features.Get().EnableExperimentalState {
if b.balancesMultiValue == nil {
return 0, nil
}
return b.balancesMultiValue.At(b, uint64(idx))
}
if b.balances == nil {
if b.balancesMultiValue == nil {
return 0, nil
}
if uint64(len(b.balances)) <= uint64(idx) {
return 0, errors.Wrapf(consensus_types.ErrOutOfBounds, "balance index %d does not exist", idx)
}
return b.balances[idx], nil
return b.balancesMultiValue.At(b, uint64(idx))
}
// BalancesLength returns the length of the balances slice.
@@ -385,13 +252,10 @@ func (b *BeaconState) BalancesLength() int {
b.lock.RLock()
defer b.lock.RUnlock()
if features.Get().EnableExperimentalState {
if b.balancesMultiValue == nil {
return 0
}
return b.balancesMultiValue.Len(b)
if b.balancesMultiValue == nil {
return 0
}
return len(b.balances)
return b.balancesMultiValue.Len(b)
}
// Slashings of validators on the beacon chain.
@@ -431,18 +295,10 @@ func (b *BeaconState) InactivityScores() ([]uint64, error) {
}
func (b *BeaconState) inactivityScoresVal() []uint64 {
if features.Get().EnableExperimentalState {
if b.inactivityScoresMultiValue == nil {
return nil
}
return b.inactivityScoresMultiValue.Value(b)
}
if b.inactivityScores == nil {
if b.inactivityScoresMultiValue == nil {
return nil
}
res := make([]uint64, len(b.inactivityScores))
copy(res, b.inactivityScores)
return res
return b.inactivityScoresMultiValue.Value(b)
}
// PendingBalanceToWithdraw returns the sum of all pending withdrawals for the given validator.

View File

@@ -3,18 +3,12 @@ package state_native
import (
"testing"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
)
func FuzzMultiValueBalances(f *testing.F) {
resetFn := features.InitWithReset(&features.Flags{
EnableExperimentalState: true,
})
defer resetFn()
bals := make([]uint64, 65536)
firstState, err := InitializeFromProtoPhase0(&ethpb.BeaconState{Balances: bals})
require.NoError(f, err)

View File

@@ -8,7 +8,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/assert"
@@ -17,663 +16,358 @@ import (
)
func TestStateReferenceSharing_Finalizer_Phase0(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
// This test showcases the logic on the Slashings field with the GC finalizer.
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{RandaoMixes: [][]byte{[]byte("foo")}})
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{Slashings: []uint64{10, 30, 40}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
assert.Equal(t, uint(2), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
assert.Equal(t, uint(2), b.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateSlashingsAtIndex(0, 100))
if b.sharedFieldReferences[types.Slashings].Refs() != 1 || a.sharedFieldReferences[types.Slashings].Refs() != 1 {
t.Error("Expected 1 shared reference to Slashings for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Altair(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
// This test showcases the logic on the Slashings field with the GC finalizer.
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{RandaoMixes: [][]byte{[]byte("foo")}})
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{Slashings: []uint64{10, 30, 40}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
assert.Equal(t, uint(2), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
assert.Equal(t, uint(2), b.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateSlashingsAtIndex(0, 100))
if b.sharedFieldReferences[types.Slashings].Refs() != 1 || a.sharedFieldReferences[types.Slashings].Refs() != 1 {
t.Error("Expected 1 shared reference to Slashings for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Bellatrix(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
// This test showcases the logic on the Slashings field with the GC finalizer.
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{RandaoMixes: [][]byte{[]byte("foo")}})
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{Slashings: []uint64{10, 30, 40}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
assert.Equal(t, uint(2), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
assert.Equal(t, uint(2), b.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateSlashingsAtIndex(0, 100))
if b.sharedFieldReferences[types.Slashings].Refs() != 1 || a.sharedFieldReferences[types.Slashings].Refs() != 1 {
t.Error("Expected 1 shared reference to Slashings for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Capella(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
// This test showcases the logic on the Slashings field with the GC finalizer.
s, err := InitializeFromProtoUnsafeCapella(&ethpb.BeaconStateCapella{RandaoMixes: [][]byte{[]byte("foo")}})
s, err := InitializeFromProtoUnsafeCapella(&ethpb.BeaconStateCapella{Slashings: []uint64{10, 30, 40}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
assert.Equal(t, uint(2), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
assert.Equal(t, uint(2), b.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateSlashingsAtIndex(0, 100))
if b.sharedFieldReferences[types.Slashings].Refs() != 1 || a.sharedFieldReferences[types.Slashings].Refs() != 1 {
t.Error("Expected 1 shared reference to Slashings for both a and b")
}
}
func TestStateReferenceSharing_Finalizer_Deneb(t *testing.T) {
// This test showcases the logic on the RandaoMixes field with the GC finalizer.
// This test showcases the logic on the Slashings field with the GC finalizer.
s, err := InitializeFromProtoUnsafeDeneb(&ethpb.BeaconStateDeneb{RandaoMixes: [][]byte{[]byte("foo")}})
s, err := InitializeFromProtoUnsafeDeneb(&ethpb.BeaconStateDeneb{Slashings: []uint64{10, 30, 40}})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected a single reference for RANDAO mixes")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected a single reference for RANDAO mixes")
func() {
// Create object in a different scope for GC
b := a.Copy()
assert.Equal(t, uint(2), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 references to RANDAO mixes")
assert.Equal(t, uint(2), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 references to RANDAO mixes")
_ = b
}()
runtime.GC() // Should run finalizer on object b
assert.Equal(t, uint(1), a.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 1 shared reference to RANDAO mixes!")
assert.Equal(t, uint(1), a.sharedFieldReferences[types.Slashings].Refs(), "Expected 1 shared reference to RANDAO mixes!")
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assert.Equal(t, uint(2), b.sharedFieldReferences[types.RandaoMixes].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateRandaoMixesAtIndex(0, bytesutil.ToBytes32([]byte("bar"))))
if b.sharedFieldReferences[types.RandaoMixes].Refs() != 1 || a.sharedFieldReferences[types.RandaoMixes].Refs() != 1 {
t.Error("Expected 1 shared reference to RANDAO mix for both a and b")
assert.Equal(t, uint(2), b.sharedFieldReferences[types.Slashings].Refs(), "Expected 2 shared references to RANDAO mixes")
require.NoError(t, b.UpdateSlashingsAtIndex(0, 100))
if b.sharedFieldReferences[types.Slashings].Refs() != 1 || a.sharedFieldReferences[types.Slashings].Refs() != 1 {
t.Error("Expected 1 shared reference to Slashings for both a and b")
}
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Phase0(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
func TestStateReferenceCopy_NoUnexpectedSlashingsMutation_Phase0(t *testing.T) {
val1, val2 := uint64(10), uint64(20)
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
Slashings: []uint64{val1},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.BlockRoots, 2)
assertRefCount(t, a, types.StateRoots, 2)
assertRefCount(t, b, types.BlockRoots, 2)
assertRefCount(t, b, types.StateRoots, 2)
assertRefCount(t, a, types.Slashings, 2)
assertRefCount(t, b, types.Slashings, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
slashingsA := a.Slashings()
slashingsB := b.Slashings()
assertValFound(t, slashingsA, val1)
assertValFound(t, slashingsB, val1)
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
require.NoError(t, a.UpdateSlashingsAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
assertValFound(t, a.Slashings(), val2)
assertValNotFound(t, a.Slashings(), val1)
assertValFound(t, b.Slashings(), val1)
assertValNotFound(t, b.Slashings(), val2)
assertValFound(t, slashingsB, val1)
assertValNotFound(t, slashingsB, val2)
assert.DeepEqual(t, val2, a.Slashings()[0], "Expected mutation not found")
assert.DeepEqual(t, val1, slashingsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, b, types.BlockRoots, 1)
assertRefCount(t, b, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
assertRefCount(t, b, types.Slashings, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Altair(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
func TestStateReferenceCopy_NoUnexpectedSlashingMutation_Altair(t *testing.T) {
val1, val2 := uint64(10), uint64(20)
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
Slashings: []uint64{val1},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.BlockRoots, 2)
assertRefCount(t, a, types.StateRoots, 2)
assertRefCount(t, b, types.BlockRoots, 2)
assertRefCount(t, b, types.StateRoots, 2)
assertRefCount(t, a, types.Slashings, 2)
assertRefCount(t, b, types.Slashings, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
slashingsA := a.Slashings()
slashingsB := b.Slashings()
assertValFound(t, slashingsA, val1)
assertValFound(t, slashingsB, val1)
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
require.NoError(t, a.UpdateSlashingsAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
assertValFound(t, a.Slashings(), val2)
assertValNotFound(t, a.Slashings(), val1)
assertValFound(t, b.Slashings(), val1)
assertValNotFound(t, b.Slashings(), val2)
assertValFound(t, slashingsB, val1)
assertValNotFound(t, slashingsB, val2)
assert.DeepEqual(t, val2, a.Slashings()[0], "Expected mutation not found")
assert.DeepEqual(t, val1, slashingsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, b, types.BlockRoots, 1)
assertRefCount(t, b, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
assertRefCount(t, b, types.Slashings, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Bellatrix(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
func TestStateReferenceCopy_NoUnexpectedSlashingMutation_Bellatrix(t *testing.T) {
val1, val2 := uint64(10), uint64(20)
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
Slashings: []uint64{val1},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.BlockRoots, 2)
assertRefCount(t, a, types.StateRoots, 2)
assertRefCount(t, b, types.BlockRoots, 2)
assertRefCount(t, b, types.StateRoots, 2)
assertRefCount(t, a, types.Slashings, 2)
assertRefCount(t, b, types.Slashings, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
slashingsA := a.Slashings()
slashingsB := b.Slashings()
assertValFound(t, slashingsA, val1)
assertValFound(t, slashingsB, val1)
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
require.NoError(t, a.UpdateSlashingsAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
assertValFound(t, a.Slashings(), val2)
assertValNotFound(t, a.Slashings(), val1)
assertValFound(t, b.Slashings(), val1)
assertValNotFound(t, b.Slashings(), val2)
assertValFound(t, slashingsB, val1)
assertValNotFound(t, slashingsB, val2)
assert.DeepEqual(t, val2, a.Slashings()[0], "Expected mutation not found")
assert.DeepEqual(t, val1, slashingsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, b, types.BlockRoots, 1)
assertRefCount(t, b, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
assertRefCount(t, b, types.Slashings, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Capella(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
func TestStateReferenceCopy_NoUnexpectedSlashingMutation_Capella(t *testing.T) {
val1, val2 := uint64(10), uint64(20)
s, err := InitializeFromProtoUnsafeCapella(&ethpb.BeaconStateCapella{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
Slashings: []uint64{val1},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.BlockRoots, 2)
assertRefCount(t, a, types.StateRoots, 2)
assertRefCount(t, b, types.BlockRoots, 2)
assertRefCount(t, b, types.StateRoots, 2)
assertRefCount(t, a, types.Slashings, 2)
assertRefCount(t, b, types.Slashings, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
slashingsA := a.Slashings()
slashingsB := b.Slashings()
assertValFound(t, slashingsA, val1)
assertValFound(t, slashingsB, val1)
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
require.NoError(t, a.UpdateSlashingsAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
assertValFound(t, a.Slashings(), val2)
assertValNotFound(t, a.Slashings(), val1)
assertValFound(t, b.Slashings(), val1)
assertValNotFound(t, b.Slashings(), val2)
assertValFound(t, slashingsB, val1)
assertValNotFound(t, slashingsB, val2)
assert.DeepEqual(t, val2, a.Slashings()[0], "Expected mutation not found")
assert.DeepEqual(t, val1, slashingsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, b, types.BlockRoots, 1)
assertRefCount(t, b, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
assertRefCount(t, b, types.Slashings, 1)
}
func TestStateReferenceCopy_NoUnexpectedRootsMutation_Deneb(t *testing.T) {
root1, root2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
func TestStateReferenceCopy_NoUnexpectedSlashingMutation_Deneb(t *testing.T) {
val1, val2 := uint64(10), uint64(20)
s, err := InitializeFromProtoUnsafeDeneb(&ethpb.BeaconStateDeneb{
BlockRoots: [][]byte{
root1[:],
},
StateRoots: [][]byte{
root1[:],
},
Slashings: []uint64{val1},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, a, types.Slashings, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.BlockRoots, 2)
assertRefCount(t, a, types.StateRoots, 2)
assertRefCount(t, b, types.BlockRoots, 2)
assertRefCount(t, b, types.StateRoots, 2)
assertRefCount(t, a, types.Slashings, 2)
assertRefCount(t, b, types.Slashings, 2)
// Assert shared state.
blockRootsA := a.BlockRoots()
stateRootsA := a.StateRoots()
blockRootsB := b.BlockRoots()
stateRootsB := b.StateRoots()
assertValFound(t, blockRootsA, root1[:])
assertValFound(t, blockRootsB, root1[:])
assertValFound(t, stateRootsA, root1[:])
assertValFound(t, stateRootsB, root1[:])
slashingsA := a.Slashings()
slashingsB := b.Slashings()
assertValFound(t, slashingsA, val1)
assertValFound(t, slashingsB, val1)
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateBlockRootAtIndex(0, root2))
require.NoError(t, a.UpdateStateRootAtIndex(0, root2))
require.NoError(t, a.UpdateSlashingsAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValNotFound(t, a.BlockRoots(), root1[:])
assertValNotFound(t, a.StateRoots(), root1[:])
assertValFound(t, a.BlockRoots(), root2[:])
assertValFound(t, a.StateRoots(), root2[:])
assertValFound(t, b.BlockRoots(), root1[:])
assertValFound(t, b.StateRoots(), root1[:])
assert.DeepEqual(t, root2[:], a.BlockRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root2[:], a.StateRoots()[0], "Expected mutation not found")
assert.DeepEqual(t, root1[:], blockRootsB[0], "Unexpected mutation found")
assert.DeepEqual(t, root1[:], stateRootsB[0], "Unexpected mutation found")
assertValFound(t, a.Slashings(), val2)
assertValNotFound(t, a.Slashings(), val1)
assertValFound(t, b.Slashings(), val1)
assertValNotFound(t, b.Slashings(), val2)
assertValFound(t, slashingsB, val1)
assertValNotFound(t, slashingsB, val2)
assert.DeepEqual(t, val2, a.Slashings()[0], "Expected mutation not found")
assert.DeepEqual(t, val1, slashingsB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.BlockRoots, 1)
assertRefCount(t, a, types.StateRoots, 1)
assertRefCount(t, b, types.BlockRoots, 1)
assertRefCount(t, b, types.StateRoots, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Phase0(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafePhase0(&ethpb.BeaconState{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.RandaoMixes, 2)
assertRefCount(t, b, types.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.RandaoMixes, 1)
assertRefCount(t, b, types.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Altair(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.RandaoMixes, 2)
assertRefCount(t, b, types.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.RandaoMixes, 1)
assertRefCount(t, b, types.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Bellatrix(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeBellatrix(&ethpb.BeaconStateBellatrix{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.RandaoMixes, 2)
assertRefCount(t, b, types.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.RandaoMixes, 1)
assertRefCount(t, b, types.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Capella(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeCapella(&ethpb.BeaconStateCapella{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.RandaoMixes, 2)
assertRefCount(t, b, types.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.RandaoMixes, 1)
assertRefCount(t, b, types.RandaoMixes, 1)
}
func TestStateReferenceCopy_NoUnexpectedRandaoMutation_Deneb(t *testing.T) {
val1, val2 := bytesutil.ToBytes32([]byte("foo")), bytesutil.ToBytes32([]byte("bar"))
s, err := InitializeFromProtoUnsafeDeneb(&ethpb.BeaconStateDeneb{
RandaoMixes: [][]byte{
val1[:],
},
})
require.NoError(t, err)
a, ok := s.(*BeaconState)
require.Equal(t, true, ok)
require.NoError(t, err)
assertRefCount(t, a, types.RandaoMixes, 1)
// Copy, increases reference count.
copied := a.Copy()
b, ok := copied.(*BeaconState)
require.Equal(t, true, ok)
assertRefCount(t, a, types.RandaoMixes, 2)
assertRefCount(t, b, types.RandaoMixes, 2)
// Assert shared state.
mixesA := a.RandaoMixes()
mixesB := b.RandaoMixes()
assertValFound(t, mixesA, val1[:])
assertValFound(t, mixesB, val1[:])
// Mutator should only affect calling state: a.
require.NoError(t, a.UpdateRandaoMixesAtIndex(0, val2))
// Assert no shared state mutation occurred only on state a (copy on write).
assertValFound(t, a.RandaoMixes(), val2[:])
assertValNotFound(t, a.RandaoMixes(), val1[:])
assertValFound(t, b.RandaoMixes(), val1[:])
assertValNotFound(t, b.RandaoMixes(), val2[:])
assertValFound(t, mixesB, val1[:])
assertValNotFound(t, mixesB, val2[:])
assert.DeepEqual(t, val2[:], a.RandaoMixes()[0], "Expected mutation not found")
assert.DeepEqual(t, val1[:], mixesB[0], "Unexpected mutation found")
// Copy on write happened, reference counters are reset.
assertRefCount(t, a, types.RandaoMixes, 1)
assertRefCount(t, b, types.RandaoMixes, 1)
assertRefCount(t, a, types.Slashings, 1)
assertRefCount(t, b, types.Slashings, 1)
}
func TestStateReferenceCopy_NoUnexpectedAttestationsMutation(t *testing.T) {
@@ -1017,10 +711,6 @@ func TestValidatorReferences_RemainsConsistent_Bellatrix(t *testing.T) {
}
func TestValidatorReferences_ApplyValidator_BalancesRead(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
EnableExperimentalState: true,
})
defer resetCfg()
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
Validators: []*ethpb.Validator{
{PublicKey: []byte{'A'}},
@@ -1061,7 +751,7 @@ func assertRefCount(t *testing.T, b *BeaconState, idx types.FieldIndex, want uin
}
// assertValFound checks whether item with a given value exists in list.
func assertValFound(t *testing.T, vals [][]byte, val []byte) {
func assertValFound(t *testing.T, vals []uint64, val uint64) {
for i := range vals {
if reflect.DeepEqual(vals[i], val) {
return
@@ -1072,7 +762,7 @@ func assertValFound(t *testing.T, vals [][]byte, val []byte) {
}
// assertValNotFound checks whether item with a given value doesn't exist in list.
func assertValNotFound(t *testing.T, vals [][]byte, val []byte) {
func assertValNotFound(t *testing.T, vals []uint64, val uint64) {
for i := range vals {
if reflect.DeepEqual(vals[i], val) {
t.Log(string(debug.Stack()))

View File

@@ -2,10 +2,6 @@ package state_native
import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/pkg/errors"
)
@@ -26,21 +22,10 @@ func (b *BeaconState) SetBlockRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue != nil {
b.blockRootsMultiValue.Detach(b)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(val)
} else {
b.sharedFieldReferences[types.BlockRoots].MinusRef()
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
rootsArr := make([][32]byte, fieldparams.BlockRootsLength)
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
b.blockRoots = rootsArr
if b.blockRootsMultiValue != nil {
b.blockRootsMultiValue.Detach(b)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(val)
b.markFieldAsDirty(types.BlockRoots)
b.rebuildTrie[types.BlockRoots] = true
@@ -53,25 +38,8 @@ func (b *BeaconState) UpdateBlockRootAtIndex(idx uint64, blockRoot [32]byte) err
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if err := b.blockRootsMultiValue.UpdateAt(b, idx, blockRoot); err != nil {
return errors.Wrap(err, "could not update block roots")
}
} else {
if uint64(len(b.blockRoots)) <= idx {
return errors.Wrapf(consensus_types.ErrOutOfBounds, "block root index %d does not exist", idx)
}
r := b.blockRoots
if ref := b.sharedFieldReferences[types.BlockRoots]; ref.Refs() > 1 {
// Copy elements in underlying array by reference.
r = make([][32]byte, len(b.blockRoots))
copy(r, b.blockRoots)
ref.MinusRef()
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
}
r[idx] = blockRoot
b.blockRoots = r
if err := b.blockRootsMultiValue.UpdateAt(b, idx, blockRoot); err != nil {
return errors.Wrap(err, "could not update block roots")
}
b.markFieldAsDirty(types.BlockRoots)

View File

@@ -2,10 +2,6 @@ package state_native
import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/pkg/errors"
)
@@ -15,21 +11,10 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if b.randaoMixesMultiValue != nil {
b.randaoMixesMultiValue.Detach(b)
}
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(val)
} else {
b.sharedFieldReferences[types.RandaoMixes].MinusRef()
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
rootsArr := make([][32]byte, fieldparams.RandaoMixesLength)
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
b.randaoMixes = rootsArr
if b.randaoMixesMultiValue != nil {
b.randaoMixesMultiValue.Detach(b)
}
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(val)
b.markFieldAsDirty(types.RandaoMixes)
b.rebuildTrie[types.RandaoMixes] = true
@@ -39,29 +24,8 @@ func (b *BeaconState) SetRandaoMixes(val [][]byte) error {
// UpdateRandaoMixesAtIndex for the beacon state. Updates the randao mixes
// at a specific index to a new value.
func (b *BeaconState) UpdateRandaoMixesAtIndex(idx uint64, val [32]byte) error {
if features.Get().EnableExperimentalState {
if err := b.randaoMixesMultiValue.UpdateAt(b, idx, val); err != nil {
return errors.Wrap(err, "could not update randao mixes")
}
} else {
if uint64(len(b.randaoMixes)) <= idx {
return errors.Wrapf(consensus_types.ErrOutOfBounds, "randao mix index %d does not exist", idx)
}
b.lock.Lock()
m := b.randaoMixes
if ref := b.sharedFieldReferences[types.RandaoMixes]; ref.Refs() > 1 {
// Copy elements in underlying array by reference.
m = make([][32]byte, len(b.randaoMixes))
copy(m, b.randaoMixes)
ref.MinusRef()
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
}
m[idx] = val
b.randaoMixes = m
b.lock.Unlock()
if err := b.randaoMixesMultiValue.UpdateAt(b, idx, val); err != nil {
return errors.Wrap(err, "could not update randao mixes")
}
b.lock.Lock()

View File

@@ -2,10 +2,6 @@ package state_native
import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/pkg/errors"
)
@@ -15,21 +11,10 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if b.stateRootsMultiValue != nil {
b.stateRootsMultiValue.Detach(b)
}
b.stateRootsMultiValue = NewMultiValueStateRoots(val)
} else {
b.sharedFieldReferences[types.StateRoots].MinusRef()
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
rootsArr := make([][32]byte, fieldparams.StateRootsLength)
for i := 0; i < len(rootsArr); i++ {
copy(rootsArr[i][:], val[i])
}
b.stateRoots = rootsArr
if b.stateRootsMultiValue != nil {
b.stateRootsMultiValue.Detach(b)
}
b.stateRootsMultiValue = NewMultiValueStateRoots(val)
b.markFieldAsDirty(types.StateRoots)
b.rebuildTrie[types.StateRoots] = true
@@ -39,29 +24,8 @@ func (b *BeaconState) SetStateRoots(val [][]byte) error {
// UpdateStateRootAtIndex for the beacon state. Updates the state root
// at a specific index to a new value.
func (b *BeaconState) UpdateStateRootAtIndex(idx uint64, stateRoot [32]byte) error {
if features.Get().EnableExperimentalState {
if err := b.stateRootsMultiValue.UpdateAt(b, idx, stateRoot); err != nil {
return errors.Wrap(err, "could not update state roots")
}
} else {
if uint64(len(b.stateRoots)) <= idx {
return errors.Wrapf(consensus_types.ErrOutOfBounds, "state root index %d does not exist", idx)
}
b.lock.Lock()
r := b.stateRoots
if ref := b.sharedFieldReferences[types.StateRoots]; ref.Refs() > 1 {
// Copy elements in underlying array by reference.
r = make([][32]byte, len(b.stateRoots))
copy(r, b.stateRoots)
ref.MinusRef()
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
}
r[idx] = stateRoot
b.stateRoots = r
b.lock.Unlock()
if err := b.stateRootsMultiValue.UpdateAt(b, idx, stateRoot); err != nil {
return errors.Wrap(err, "could not update state roots")
}
b.lock.Lock()

View File

@@ -4,9 +4,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
consensus_types "github.com/OffchainLabs/prysm/v6/consensus-types"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
@@ -20,16 +17,10 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if b.validatorsMultiValue != nil {
b.validatorsMultiValue.Detach(b)
}
b.validatorsMultiValue = NewMultiValueValidators(val)
} else {
b.validators = val
b.sharedFieldReferences[types.Validators].MinusRef()
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
if b.validatorsMultiValue != nil {
b.validatorsMultiValue.Detach(b)
}
b.validatorsMultiValue = NewMultiValueValidators(val)
b.markFieldAsDirty(types.Validators)
b.rebuildTrie[types.Validators] = true
@@ -41,58 +32,26 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
// validator registry.
func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val state.ReadOnlyValidator) (*ethpb.Validator, error)) error {
var changedVals []uint64
if features.Get().EnableExperimentalState {
l := b.validatorsMultiValue.Len(b)
for i := 0; i < l; i++ {
v, err := b.validatorsMultiValue.At(b, uint64(i))
if err != nil {
return err
}
ro, err := NewValidator(v)
if err != nil {
return err
}
newVal, err := f(i, ro)
if err != nil {
return err
}
if newVal != nil {
changedVals = append(changedVals, uint64(i))
if err = b.validatorsMultiValue.UpdateAt(b, uint64(i), newVal); err != nil {
return errors.Wrapf(err, "could not update validator at index %d", i)
}
l := b.validatorsMultiValue.Len(b)
for i := 0; i < l; i++ {
v, err := b.validatorsMultiValue.At(b, uint64(i))
if err != nil {
return err
}
ro, err := NewValidator(v)
if err != nil {
return err
}
newVal, err := f(i, ro)
if err != nil {
return err
}
if newVal != nil {
changedVals = append(changedVals, uint64(i))
if err = b.validatorsMultiValue.UpdateAt(b, uint64(i), newVal); err != nil {
return errors.Wrapf(err, "could not update validator at index %d", i)
}
}
} else {
b.lock.Lock()
v := b.validators
if ref := b.sharedFieldReferences[types.Validators]; ref.Refs() > 1 {
v = b.validatorsReferences()
ref.MinusRef()
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
}
b.lock.Unlock()
for i, val := range v {
ro, err := NewValidator(val)
if err != nil {
return err
}
newVal, err := f(i, ro)
if err != nil {
return err
}
if newVal != nil {
changedVals = append(changedVals, uint64(i))
v[i] = newVal
}
}
b.lock.Lock()
b.validators = v
b.lock.Unlock()
}
b.lock.Lock()
@@ -108,27 +67,8 @@ func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val state.ReadOnlyVa
// UpdateValidatorAtIndex for the beacon state. Updates the validator
// at a specific index to a new value.
func (b *BeaconState) UpdateValidatorAtIndex(idx primitives.ValidatorIndex, val *ethpb.Validator) error {
if features.Get().EnableExperimentalState {
if err := b.validatorsMultiValue.UpdateAt(b, uint64(idx), val); err != nil {
return errors.Wrap(err, "could not update validator")
}
} else {
if uint64(len(b.validators)) <= uint64(idx) {
return errors.Wrapf(consensus_types.ErrOutOfBounds, "validator index %d does not exist", idx)
}
b.lock.Lock()
v := b.validators
if ref := b.sharedFieldReferences[types.Validators]; ref.Refs() > 1 {
v = b.validatorsReferences()
ref.MinusRef()
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
}
v[idx] = val
b.validators = v
b.lock.Unlock()
if err := b.validatorsMultiValue.UpdateAt(b, uint64(idx), val); err != nil {
return errors.Wrap(err, "could not update validator")
}
b.lock.Lock()
@@ -145,16 +85,10 @@ func (b *BeaconState) SetBalances(val []uint64) error {
b.lock.Lock()
defer b.lock.Unlock()
if features.Get().EnableExperimentalState {
if b.balancesMultiValue != nil {
b.balancesMultiValue.Detach(b)
}
b.balancesMultiValue = NewMultiValueBalances(val)
} else {
b.sharedFieldReferences[types.Balances].MinusRef()
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.balances = val
if b.balancesMultiValue != nil {
b.balancesMultiValue.Detach(b)
}
b.balancesMultiValue = NewMultiValueBalances(val)
b.markFieldAsDirty(types.Balances)
b.rebuildTrie[types.Balances] = true
@@ -164,27 +98,8 @@ func (b *BeaconState) SetBalances(val []uint64) error {
// UpdateBalancesAtIndex for the beacon state. This method updates the balance
// at a specific index to a new value.
func (b *BeaconState) UpdateBalancesAtIndex(idx primitives.ValidatorIndex, val uint64) error {
if features.Get().EnableExperimentalState {
if err := b.balancesMultiValue.UpdateAt(b, uint64(idx), val); err != nil {
return errors.Wrap(err, "could not update balances")
}
} else {
if uint64(len(b.balances)) <= uint64(idx) {
return errors.Wrapf(consensus_types.ErrOutOfBounds, "balance index %d does not exist", idx)
}
b.lock.Lock()
bals := b.balances
if b.sharedFieldReferences[types.Balances].Refs() > 1 {
bals = b.balancesVal()
b.sharedFieldReferences[types.Balances].MinusRef()
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
}
bals[idx] = val
b.balances = bals
b.lock.Unlock()
if err := b.balancesMultiValue.UpdateAt(b, uint64(idx), val); err != nil {
return errors.Wrap(err, "could not update balances")
}
b.lock.Lock()
@@ -236,25 +151,8 @@ func (b *BeaconState) UpdateSlashingsAtIndex(idx, val uint64) error {
// AppendValidator for the beacon state. Appends the new value
// to the end of list.
func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
var valIdx primitives.ValidatorIndex
if features.Get().EnableExperimentalState {
b.validatorsMultiValue.Append(b, val)
valIdx = primitives.ValidatorIndex(b.validatorsMultiValue.Len(b) - 1)
} else {
b.lock.Lock()
vals := b.validators
if b.sharedFieldReferences[types.Validators].Refs() > 1 {
vals = b.validatorsReferences()
b.sharedFieldReferences[types.Validators].MinusRef()
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
}
b.validators = append(vals, val)
valIdx = primitives.ValidatorIndex(len(b.validators) - 1)
b.lock.Unlock()
}
b.validatorsMultiValue.Append(b, val)
valIdx := primitives.ValidatorIndex(b.validatorsMultiValue.Len(b) - 1)
b.lock.Lock()
defer b.lock.Unlock()
@@ -268,26 +166,8 @@ func (b *BeaconState) AppendValidator(val *ethpb.Validator) error {
// AppendBalance for the beacon state. Appends the new value
// to the end of list.
func (b *BeaconState) AppendBalance(bal uint64) error {
var balIdx uint64
if features.Get().EnableExperimentalState {
b.balancesMultiValue.Append(b, bal)
balIdx = uint64(b.balancesMultiValue.Len(b) - 1)
} else {
b.lock.Lock()
bals := b.balances
if b.sharedFieldReferences[types.Balances].Refs() > 1 {
bals = make([]uint64, 0, len(b.balances)+int(params.BeaconConfig().MaxDeposits))
bals = append(bals, b.balances...)
b.sharedFieldReferences[types.Balances].MinusRef()
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
}
b.balances = append(bals, bal)
balIdx = uint64(len(b.balances) - 1)
b.lock.Unlock()
}
b.balancesMultiValue.Append(b, bal)
balIdx := uint64(b.balancesMultiValue.Len(b) - 1)
b.lock.Lock()
defer b.lock.Unlock()
@@ -303,22 +183,7 @@ func (b *BeaconState) AppendInactivityScore(s uint64) error {
return errNotSupported("AppendInactivityScore", b.version)
}
if features.Get().EnableExperimentalState {
b.inactivityScoresMultiValue.Append(b, s)
} else {
b.lock.Lock()
scores := b.inactivityScores
if b.sharedFieldReferences[types.InactivityScores].Refs() > 1 {
scores = make([]uint64, 0, len(b.inactivityScores)+int(params.BeaconConfig().MaxDeposits))
scores = append(scores, b.inactivityScores...)
b.sharedFieldReferences[types.InactivityScores].MinusRef()
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
b.inactivityScores = append(scores, s)
b.lock.Unlock()
}
b.inactivityScoresMultiValue.Append(b, s)
b.lock.Lock()
defer b.lock.Unlock()
@@ -337,16 +202,10 @@ func (b *BeaconState) SetInactivityScores(val []uint64) error {
return errNotSupported("SetInactivityScores", b.version)
}
if features.Get().EnableExperimentalState {
if b.inactivityScoresMultiValue != nil {
b.inactivityScoresMultiValue.Detach(b)
}
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(val)
} else {
b.sharedFieldReferences[types.InactivityScores].MinusRef()
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
b.inactivityScores = val
if b.inactivityScoresMultiValue != nil {
b.inactivityScoresMultiValue.Detach(b)
}
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(val)
b.markFieldAsDirty(types.InactivityScores)
return nil

View File

@@ -11,7 +11,6 @@ import (
customtypes "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/custom-types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native/types"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/stateutil"
"github.com/OffchainLabs/prysm/v6/config/features"
fieldparams "github.com/OffchainLabs/prysm/v6/config/fieldparams"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
@@ -116,20 +115,13 @@ var (
)
const (
phase0SharedFieldRefCount = 10
altairSharedFieldRefCount = 11
bellatrixSharedFieldRefCount = 12
capellaSharedFieldRefCount = 13
denebSharedFieldRefCount = 13
electraSharedFieldRefCount = 16
fuluSharedFieldRefCount = 17
experimentalStatePhase0SharedFieldRefCount = 5
experimentalStateAltairSharedFieldRefCount = 5
experimentalStateBellatrixSharedFieldRefCount = 6
experimentalStateCapellaSharedFieldRefCount = 7
experimentalStateDenebSharedFieldRefCount = 7
experimentalStateElectraSharedFieldRefCount = 10
experimentalStateFuluSharedFieldRefCount = 11
phase0SharedFieldRefCount = 5
altairSharedFieldRefCount = 5
bellatrixSharedFieldRefCount = 6
capellaSharedFieldRefCount = 7
denebSharedFieldRefCount = 7
electraSharedFieldRefCount = 10
fuluSharedFieldRefCount = 11
)
// InitializeFromProtoPhase0 the beacon state from a protobuf representation.
@@ -208,37 +200,12 @@ func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState,
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStatePhase0SharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, phase0SharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, phase0SharedFieldRefCount)
for _, f := range phase0Fields {
b.dirtyFields[f] = true
@@ -257,13 +224,6 @@ func InitializeFromProtoUnsafePhase0(st *ethpb.BeaconState) (state.BeaconState,
b.sharedFieldReferences[types.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PreviousEpochAttestations] = stateutil.NewRef(1)
b.sharedFieldReferences[types.CurrentEpochAttestations] = stateutil.NewRef(1)
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -314,39 +274,13 @@ func InitializeFromProtoUnsafeAltair(st *ethpb.BeaconStateAltair) (state.BeaconS
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateAltairSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, altairSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, altairSharedFieldRefCount)
for _, f := range altairFields {
b.dirtyFields[f] = true
@@ -365,14 +299,6 @@ func InitializeFromProtoUnsafeAltair(st *ethpb.BeaconStateAltair) (state.BeaconS
b.sharedFieldReferences[types.Slashings] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1) // New in Altair.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -424,39 +350,13 @@ func InitializeFromProtoUnsafeBellatrix(st *ethpb.BeaconStateBellatrix) (state.B
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateBellatrixSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, bellatrixSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, bellatrixSharedFieldRefCount)
for _, f := range bellatrixFields {
b.dirtyFields[f] = true
@@ -476,14 +376,6 @@ func InitializeFromProtoUnsafeBellatrix(st *ethpb.BeaconStateBellatrix) (state.B
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.LatestExecutionPayloadHeader] = stateutil.NewRef(1) // New in Bellatrix.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -538,39 +430,13 @@ func InitializeFromProtoUnsafeCapella(st *ethpb.BeaconStateCapella) (state.Beaco
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateCapellaSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, capellaSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, capellaSharedFieldRefCount)
for _, f := range capellaFields {
b.dirtyFields[f] = true
@@ -591,14 +457,6 @@ func InitializeFromProtoUnsafeCapella(st *ethpb.BeaconStateCapella) (state.Beaco
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.LatestExecutionPayloadHeaderCapella] = stateutil.NewRef(1) // New in Capella.
b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1) // New in Capella.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -651,39 +509,13 @@ func InitializeFromProtoUnsafeDeneb(st *ethpb.BeaconStateDeneb) (state.BeaconSta
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateDenebSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount)
for _, f := range denebFields {
b.dirtyFields[f] = true
@@ -704,14 +536,6 @@ func InitializeFromProtoUnsafeDeneb(st *ethpb.BeaconStateDeneb) (state.BeaconSta
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
b.sharedFieldReferences[types.LatestExecutionPayloadHeaderDeneb] = stateutil.NewRef(1) // New in Deneb.
b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1)
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -773,39 +597,13 @@ func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.Beaco
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateElectraSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
for _, f := range electraFields {
b.dirtyFields[f] = true
@@ -829,14 +627,6 @@ func InitializeFromProtoUnsafeElectra(st *ethpb.BeaconStateElectra) (state.Beaco
b.sharedFieldReferences[types.PendingDeposits] = stateutil.NewRef(1) // New in Electra.
b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1) // New in Electra.
b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1) // New in Electra.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -903,39 +693,13 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateFulu) (state.BeaconState
valMapHandler: stateutil.NewValMapHandler(st.Validators),
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateFuluSharedFieldRefCount)
} else {
bRoots := make([][32]byte, fieldparams.BlockRootsLength)
for i, r := range st.BlockRoots {
bRoots[i] = bytesutil.ToBytes32(r)
}
b.blockRoots = bRoots
sRoots := make([][32]byte, fieldparams.StateRootsLength)
for i, r := range st.StateRoots {
sRoots[i] = bytesutil.ToBytes32(r)
}
b.stateRoots = sRoots
mixes := make([][32]byte, fieldparams.RandaoMixesLength)
for i, m := range st.RandaoMixes {
mixes[i] = bytesutil.ToBytes32(m)
}
b.randaoMixes = mixes
b.balances = st.Balances
b.validators = st.Validators
b.inactivityScores = st.InactivityScores
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, fuluSharedFieldRefCount)
}
b.blockRootsMultiValue = NewMultiValueBlockRoots(st.BlockRoots)
b.stateRootsMultiValue = NewMultiValueStateRoots(st.StateRoots)
b.randaoMixesMultiValue = NewMultiValueRandaoMixes(st.RandaoMixes)
b.balancesMultiValue = NewMultiValueBalances(st.Balances)
b.validatorsMultiValue = NewMultiValueValidators(st.Validators)
b.inactivityScoresMultiValue = NewMultiValueInactivityScores(st.InactivityScores)
b.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, fuluSharedFieldRefCount)
for _, f := range fuluFields {
b.dirtyFields[f] = true
@@ -960,14 +724,6 @@ func InitializeFromProtoUnsafeFulu(st *ethpb.BeaconStateFulu) (state.BeaconState
b.sharedFieldReferences[types.PendingPartialWithdrawals] = stateutil.NewRef(1)
b.sharedFieldReferences[types.PendingConsolidations] = stateutil.NewRef(1)
b.sharedFieldReferences[types.ProposerLookahead] = stateutil.NewRef(1) // New in Fulu.
if !features.Get().EnableExperimentalState {
b.sharedFieldReferences[types.BlockRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.StateRoots] = stateutil.NewRef(1)
b.sharedFieldReferences[types.RandaoMixes] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
b.sharedFieldReferences[types.Validators] = stateutil.NewRef(1)
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}
state.Count.Inc()
// Finalizer runs when dst is being destroyed in garbage collection.
@@ -1015,11 +771,8 @@ func (b *BeaconState) Copy() state.BeaconState {
earliestConsolidationEpoch: b.earliestConsolidationEpoch,
// Large arrays, infrequently changed, constant size.
blockRoots: b.blockRoots,
blockRootsMultiValue: b.blockRootsMultiValue,
stateRoots: b.stateRoots,
stateRootsMultiValue: b.stateRootsMultiValue,
randaoMixes: b.randaoMixes,
randaoMixesMultiValue: b.randaoMixesMultiValue,
previousEpochAttestations: b.previousEpochAttestations,
currentEpochAttestations: b.currentEpochAttestations,
@@ -1028,15 +781,12 @@ func (b *BeaconState) Copy() state.BeaconState {
proposerLookahead: b.proposerLookahead,
// Large arrays, increases over time.
balances: b.balances,
balancesMultiValue: b.balancesMultiValue,
historicalRoots: b.historicalRoots,
historicalSummaries: b.historicalSummaries,
validators: b.validators,
validatorsMultiValue: b.validatorsMultiValue,
previousEpochParticipation: b.previousEpochParticipation,
currentEpochParticipation: b.currentEpochParticipation,
inactivityScores: b.inactivityScores,
inactivityScoresMultiValue: b.inactivityScoresMultiValue,
pendingDeposits: b.pendingDeposits,
pendingPartialWithdrawals: b.pendingPartialWithdrawals,
@@ -1068,51 +818,30 @@ func (b *BeaconState) Copy() state.BeaconState {
valMapHandler: b.valMapHandler,
}
if features.Get().EnableExperimentalState {
b.blockRootsMultiValue.Copy(b, dst)
b.stateRootsMultiValue.Copy(b, dst)
b.randaoMixesMultiValue.Copy(b, dst)
b.balancesMultiValue.Copy(b, dst)
if b.version > version.Phase0 {
b.inactivityScoresMultiValue.Copy(b, dst)
}
b.validatorsMultiValue.Copy(b, dst)
b.blockRootsMultiValue.Copy(b, dst)
b.stateRootsMultiValue.Copy(b, dst)
b.randaoMixesMultiValue.Copy(b, dst)
b.balancesMultiValue.Copy(b, dst)
if b.version > version.Phase0 {
b.inactivityScoresMultiValue.Copy(b, dst)
}
b.validatorsMultiValue.Copy(b, dst)
if features.Get().EnableExperimentalState {
switch b.version {
case version.Phase0:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStatePhase0SharedFieldRefCount)
case version.Altair:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateAltairSharedFieldRefCount)
case version.Bellatrix:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateBellatrixSharedFieldRefCount)
case version.Capella:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateCapellaSharedFieldRefCount)
case version.Deneb:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateDenebSharedFieldRefCount)
case version.Electra:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateElectraSharedFieldRefCount)
case version.Fulu:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, experimentalStateFuluSharedFieldRefCount)
}
} else {
switch b.version {
case version.Phase0:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, phase0SharedFieldRefCount)
case version.Altair:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, altairSharedFieldRefCount)
case version.Bellatrix:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, bellatrixSharedFieldRefCount)
case version.Capella:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, capellaSharedFieldRefCount)
case version.Deneb:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount)
case version.Electra:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
case version.Fulu:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, fuluSharedFieldRefCount)
}
switch b.version {
case version.Phase0:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, phase0SharedFieldRefCount)
case version.Altair:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, altairSharedFieldRefCount)
case version.Bellatrix:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, bellatrixSharedFieldRefCount)
case version.Capella:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, capellaSharedFieldRefCount)
case version.Deneb:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, denebSharedFieldRefCount)
case version.Electra:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, electraSharedFieldRefCount)
case version.Fulu:
dst.sharedFieldReferences = make(map[types.FieldIndex]*stateutil.Reference, fuluSharedFieldRefCount)
}
for field, ref := range b.sharedFieldReferences {
@@ -1256,10 +985,6 @@ func (b *BeaconState) FieldReferencesCount() map[string]uint64 {
func (b *BeaconState) RecordStateMetrics() {
b.lock.RLock()
defer b.lock.RUnlock()
// Only run this for nodes running with the experimental state.
if !features.Get().EnableExperimentalState {
return
}
// Validators
if b.validatorsMultiValue != nil {
@@ -1413,11 +1138,7 @@ func (b *BeaconState) rootSelector(ctx context.Context, field types.FieldIndex)
case types.FinalizedCheckpoint:
return ssz.CheckpointRoot(b.finalizedCheckpoint)
case types.InactivityScores:
if features.Get().EnableExperimentalState {
return stateutil.Uint64ListRootWithRegistryLimit(b.inactivityScoresMultiValue.Value(b))
} else {
return stateutil.Uint64ListRootWithRegistryLimit(b.inactivityScores)
}
return stateutil.Uint64ListRootWithRegistryLimit(b.inactivityScoresMultiValue.Value(b))
case types.CurrentSyncCommittee:
return stateutil.SyncCommitteeRoot(b.currentSyncCommittee)
case types.NextSyncCommittee:
@@ -1561,25 +1282,23 @@ func finalizerCleanup(b *BeaconState) {
delete(b.stateFieldLeaves, i)
}
if features.Get().EnableExperimentalState {
if b.blockRootsMultiValue != nil {
b.blockRootsMultiValue.Detach(b)
}
if b.stateRootsMultiValue != nil {
b.stateRootsMultiValue.Detach(b)
}
if b.randaoMixesMultiValue != nil {
b.randaoMixesMultiValue.Detach(b)
}
if b.balancesMultiValue != nil {
b.balancesMultiValue.Detach(b)
}
if b.inactivityScoresMultiValue != nil {
b.inactivityScoresMultiValue.Detach(b)
}
if b.validatorsMultiValue != nil {
b.validatorsMultiValue.Detach(b)
}
if b.blockRootsMultiValue != nil {
b.blockRootsMultiValue.Detach(b)
}
if b.stateRootsMultiValue != nil {
b.stateRootsMultiValue.Detach(b)
}
if b.randaoMixesMultiValue != nil {
b.randaoMixesMultiValue.Detach(b)
}
if b.balancesMultiValue != nil {
b.balancesMultiValue.Detach(b)
}
if b.inactivityScoresMultiValue != nil {
b.inactivityScoresMultiValue.Detach(b)
}
if b.validatorsMultiValue != nil {
b.validatorsMultiValue.Detach(b)
}
state.Count.Sub(1)
@@ -1587,145 +1306,94 @@ func finalizerCleanup(b *BeaconState) {
func (b *BeaconState) blockRootsRootSelector(field types.FieldIndex) ([32]byte, error) {
if b.rebuildTrie[field] {
if features.Get().EnableExperimentalState {
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.blockRootsMultiValue,
}, fieldparams.BlockRootsLength)
if err != nil {
return [32]byte{}, err
}
} else {
err := b.resetFieldTrie(field, b.blockRoots, fieldparams.BlockRootsLength)
if err != nil {
return [32]byte{}, err
}
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.blockRootsMultiValue,
}, fieldparams.BlockRootsLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
if features.Get().EnableExperimentalState {
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.blockRootsMultiValue,
})
} else {
return b.recomputeFieldTrie(field, b.blockRoots)
}
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.blockRootsMultiValue,
})
}
func (b *BeaconState) stateRootsRootSelector(field types.FieldIndex) ([32]byte, error) {
if b.rebuildTrie[field] {
if features.Get().EnableExperimentalState {
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.stateRootsMultiValue,
}, fieldparams.StateRootsLength)
if err != nil {
return [32]byte{}, err
}
} else {
err := b.resetFieldTrie(field, b.stateRoots, fieldparams.StateRootsLength)
if err != nil {
return [32]byte{}, err
}
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.stateRootsMultiValue,
}, fieldparams.StateRootsLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
if features.Get().EnableExperimentalState {
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.stateRootsMultiValue,
})
} else {
return b.recomputeFieldTrie(field, b.stateRoots)
}
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.stateRootsMultiValue,
})
}
func (b *BeaconState) validatorsRootSelector(field types.FieldIndex) ([32]byte, error) {
if b.rebuildTrie[field] {
if features.Get().EnableExperimentalState {
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: b,
MultiValueSlice: b.validatorsMultiValue,
}, fieldparams.ValidatorRegistryLimit)
if err != nil {
return [32]byte{}, err
}
} else {
err := b.resetFieldTrie(field, b.validators, fieldparams.ValidatorRegistryLimit)
if err != nil {
return [32]byte{}, err
}
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: b,
MultiValueSlice: b.validatorsMultiValue,
}, fieldparams.ValidatorRegistryLimit)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
if features.Get().EnableExperimentalState {
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: b,
MultiValueSlice: b.validatorsMultiValue,
})
} else {
return b.recomputeFieldTrie(field, b.validators)
}
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[*ethpb.Validator]{
Identifiable: b,
MultiValueSlice: b.validatorsMultiValue,
})
}
func (b *BeaconState) balancesRootSelector(field types.FieldIndex) ([32]byte, error) {
if b.rebuildTrie[field] {
if features.Get().EnableExperimentalState {
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[uint64]{
Identifiable: b,
MultiValueSlice: b.balancesMultiValue,
}, stateutil.ValidatorLimitForBalancesChunks())
if err != nil {
return [32]byte{}, err
}
} else {
err := b.resetFieldTrie(field, b.balances, stateutil.ValidatorLimitForBalancesChunks())
if err != nil {
return [32]byte{}, err
}
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[uint64]{
Identifiable: b,
MultiValueSlice: b.balancesMultiValue,
}, stateutil.ValidatorLimitForBalancesChunks())
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
if features.Get().EnableExperimentalState {
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[uint64]{
Identifiable: b,
MultiValueSlice: b.balancesMultiValue,
})
} else {
return b.recomputeFieldTrie(field, b.balances)
}
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[uint64]{
Identifiable: b,
MultiValueSlice: b.balancesMultiValue,
})
}
func (b *BeaconState) randaoMixesRootSelector(field types.FieldIndex) ([32]byte, error) {
if b.rebuildTrie[field] {
if features.Get().EnableExperimentalState {
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.randaoMixesMultiValue,
}, fieldparams.RandaoMixesLength)
if err != nil {
return [32]byte{}, err
}
} else {
err := b.resetFieldTrie(field, b.randaoMixes, fieldparams.RandaoMixesLength)
if err != nil {
return [32]byte{}, err
}
err := b.resetFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.randaoMixesMultiValue,
}, fieldparams.RandaoMixesLength)
if err != nil {
return [32]byte{}, err
}
delete(b.rebuildTrie, field)
return b.stateFieldLeaves[field].TrieRoot()
}
if features.Get().EnableExperimentalState {
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.randaoMixesMultiValue,
})
} else {
return b.recomputeFieldTrie(field, b.randaoMixes)
}
return b.recomputeFieldTrie(field, mvslice.MultiValueSliceComposite[[32]byte]{
Identifiable: b,
MultiValueSlice: b.randaoMixesMultiValue,
})
}

View File

@@ -6,7 +6,6 @@ import (
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
statenative "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
"github.com/OffchainLabs/prysm/v6/config/features"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
@@ -805,10 +804,6 @@ func TestBeaconState_ValidatorMutation_Bellatrix(t *testing.T) {
}
func TestBeaconState_InitializeInactivityScoresCorrectly_Deneb(t *testing.T) {
resetCfg := features.InitWithReset(&features.Flags{
EnableExperimentalState: true,
})
defer resetCfg()
st, _ := util.DeterministicGenesisStateDeneb(t, 200)
_, err := st.HashTreeRoot(t.Context())
require.NoError(t, err)

View File

@@ -15,5 +15,5 @@ func VerifyBeaconStateValidatorAtIndexReadOnlyHandlesNilSlice(t *testing.T, fact
require.NoError(t, err)
_, err = st.ValidatorAtIndexReadOnly(0)
assert.Equal(t, state.ErrNilValidatorsInState, err)
assert.ErrorContains(t, "index 0 out of bounds", err)
}

View File

@@ -0,0 +1,3 @@
### Changed
- Makes the multivalue slice permanent in the state and removes old paths.

View File

@@ -40,7 +40,6 @@ const disabledFeatureFlag = "Disabled feature flag"
// Flags is a struct to represent which features the client will perform on runtime.
type Flags struct {
// Feature related flags.
EnableExperimentalState bool // EnableExperimentalState turns on the latest and greatest (but potentially unstable) changes to the beacon state.
WriteSSZStateTransitions bool // WriteSSZStateTransitions to tmp directory.
EnablePeerScorer bool // EnablePeerScorer enables experimental peer scoring in p2p.
EnableLightClient bool // EnableLightClient enables light client APIs.
@@ -189,12 +188,6 @@ func ConfigureBeaconChain(ctx *cli.Context) error {
return err
}
cfg.EnableExperimentalState = true
if ctx.Bool(disableExperimentalState.Name) {
logEnabled(disableExperimentalState)
cfg.EnableExperimentalState = false
}
if ctx.Bool(writeSSZStateTransitionsFlag.Name) {
logEnabled(writeSSZStateTransitionsFlag)
cfg.WriteSSZStateTransitions = true

View File

@@ -103,6 +103,11 @@ var (
Usage: deprecatedUsage,
Hidden: true,
}
deprecatedDisableExperimentalState = &cli.BoolFlag{
Name: "disable-experimental-state",
Usage: deprecatedUsage,
Hidden: true,
}
)
// Deprecated flags for both the beacon node and validator client.
@@ -124,6 +129,7 @@ var deprecatedFlags = []cli.Flag{
deprecatedInteropGenesisTimeFlag,
deprecatedEnableQuic,
deprecatedAttestTimely,
deprecatedDisableExperimentalState,
}
var upcomingDeprecation = []cli.Flag{

View File

@@ -33,10 +33,6 @@ var (
Name: "dev",
Usage: "Enables experimental features still in development. These features may not be stable.",
}
disableExperimentalState = &cli.BoolFlag{
Name: "disable-experimental-state",
Usage: "Turns off the latest and greatest changes to the beacon state. Disabling this is safe to do after the feature has been enabled.",
}
writeSSZStateTransitionsFlag = &cli.BoolFlag{
Name: "interop-write-ssz-state-transitions",
Usage: "Writes SSZ states to disk after attempted state transitio.",
@@ -240,7 +236,6 @@ var E2EValidatorFlags = []string{
// BeaconChainFlags contains a list of all the feature flags that apply to the beacon-chain client.
var BeaconChainFlags = combinedFlags([]cli.Flag{
devModeFlag,
disableExperimentalState,
writeSSZStateTransitionsFlag,
saveInvalidBlockTempFlag,
saveInvalidBlobTempFlag,

View File

@@ -15,7 +15,6 @@ var (
// ErrUnsupportedField is returned when a getter/setter access is not supported.
ErrUnsupportedField = errors.New("unsupported getter")
// ErrOutOfBounds is returned when a slice or array index does not exist.
ErrOutOfBounds = errors.New("index out of bounds")
)
// ErrNotSupported constructs a message informing about an unsupported field access.

View File

@@ -101,6 +101,9 @@ import (
// fragmented.
const fragmentationLimit = 50000
// ErrOutOfBounds happens when the provided index is higher than the largest index of the slice.
var ErrOutOfBounds = errors.New("out of bounds")
// Id is an object identifier.
type Id = uint64
@@ -255,7 +258,7 @@ func (s *Slice[V]) At(obj Identifiable, index uint64) (V, error) {
if index >= uint64(len(s.sharedItems)+len(s.appendedItems)) {
var def V
return def, fmt.Errorf("index %d out of bounds", index)
return def, fmt.Errorf("index %d %w", index, ErrOutOfBounds)
}
isOriginal := index < uint64(len(s.sharedItems))
@@ -282,7 +285,7 @@ func (s *Slice[V]) At(obj Identifiable, index uint64) (V, error) {
}
}
var def V
return def, fmt.Errorf("index %d out of bounds", index)
return def, fmt.Errorf("index %d %w", index, ErrOutOfBounds)
}
}
@@ -292,7 +295,7 @@ func (s *Slice[V]) UpdateAt(obj Identifiable, index uint64, val V) error {
defer s.lock.Unlock()
if index >= uint64(len(s.sharedItems)+len(s.appendedItems)) {
return fmt.Errorf("index %d out of bounds", index)
return fmt.Errorf("index %d %w", index, ErrOutOfBounds)
}
isOriginal := index < uint64(len(s.sharedItems))
@@ -560,7 +563,7 @@ func (s *Slice[V]) updateAppendedItem(obj Identifiable, index uint64, val V) err
}
}
if !found {
return fmt.Errorf("index %d out of bounds", index)
return fmt.Errorf("index %d %w", index, ErrOutOfBounds)
}
newValue := true
@@ -606,7 +609,7 @@ func (e EmptyMVSlice[V]) Len(_ Identifiable) int {
func (e EmptyMVSlice[V]) At(_ Identifiable, index uint64) (V, error) {
if index >= uint64(len(e.fullSlice)) {
var def V
return def, errors.Errorf("index %d out of bounds", index)
return def, fmt.Errorf("index %d %w", index, ErrOutOfBounds)
}
return e.fullSlice[index], nil
}

View File

@@ -476,6 +476,20 @@ func TestFragmentation_IndividualAndAppendedReferences(t *testing.T) {
assert.Equal(t, true, s.IsFragmented())
}
func TestNil(t *testing.T) {
obj := &testObject{}
s := &Slice[int]{}
s.Init(nil)
assert.Equal(t, 0, s.Len(obj))
assert.DeepEqual(t, []int{}, s.Value(obj))
_, err := s.At(obj, 0)
assert.NotNil(t, err)
s.Append(obj, 1)
assert.Equal(t, 1, s.Len(obj))
assert.DeepEqual(t, []int{1}, s.Value(obj))
}
// Share the slice between 2 objects.
// Index 0: Shared value
// Index 1: Different individual value

View File

@@ -3,13 +3,13 @@ package fuzz
import "runtime/debug"
// FreeMemory calls debug.FreeOSMemory() every 10 loop iterations.
// This is very useful in tests that fuzz a proto beacon state
// and initialize a native state from that proto state inside the loop.
// This is very useful in tests that initialize a native state from a proto state inside a loop.
// Most commonly this happens in tests that make use of fuzzing.
// The reason is that fields of the native beacon state which are multi-value
// slices always create a slice of proper length for that field, even if
// the fuzzer creates a smaller slice. Because the beacon state keeps
// a reference to the multi-value slice, the multi-value slice is not garbage
// collected fast enough during fuzzing, leading to memory bloat.
// the proto state's slice has a smaller length. Because the beacon state keeps
// a reference to the multi-value slice object, the multi-value slice is not garbage
// collected fast enough, leading to memory bloat.
// Freeing memory manually every 10 iterations keeps the in-use memory low.
// The tradeoff is longer test times.
func FreeMemory(iteration int) {