Skip to content

Commit bc9151d

Browse files
nisdasprestonvanloon
authored andcommitted
Fix Multivalue Slice Deadlock (#13087)
* fix deadlock * gofmt * lint (cherry picked from commit f91efaf)
1 parent 747d7b5 commit bc9151d

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

beacon-chain/state/state-native/references_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/prysmaticlabs/go-bitfield"
1010
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state"
1111
"github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native/types"
12+
"github.com/prysmaticlabs/prysm/v4/config/features"
1213
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
1314
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
1415
"github.com/prysmaticlabs/prysm/v4/testing/assert"
@@ -1015,6 +1016,43 @@ func TestValidatorReferences_RemainsConsistent_Bellatrix(t *testing.T) {
10151016
}))
10161017
}
10171018

1019+
func TestValidatorReferences_ApplyValidator_BalancesRead(t *testing.T) {
1020+
resetCfg := features.InitWithReset(&features.Flags{
1021+
EnableExperimentalState: true,
1022+
})
1023+
defer resetCfg()
1024+
s, err := InitializeFromProtoUnsafeAltair(&ethpb.BeaconStateAltair{
1025+
Validators: []*ethpb.Validator{
1026+
{PublicKey: []byte{'A'}},
1027+
{PublicKey: []byte{'B'}},
1028+
{PublicKey: []byte{'C'}},
1029+
{PublicKey: []byte{'D'}},
1030+
{PublicKey: []byte{'E'}},
1031+
},
1032+
Balances: []uint64{0, 0, 0, 0, 0},
1033+
})
1034+
require.NoError(t, err)
1035+
a, ok := s.(*BeaconState)
1036+
require.Equal(t, true, ok)
1037+
1038+
// Create a second state.
1039+
copied := a.Copy()
1040+
b, ok := copied.(*BeaconState)
1041+
require.Equal(t, true, ok)
1042+
1043+
// Modify all validators from copied state, it should not deadlock.
1044+
assert.NoError(t, b.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
1045+
b, err := b.BalanceAtIndex(0)
1046+
if err != nil {
1047+
return false, nil, err
1048+
}
1049+
newVal := ethpb.CopyValidator(val)
1050+
newVal.EffectiveBalance += b
1051+
val.EffectiveBalance += b
1052+
return true, val, nil
1053+
}))
1054+
}
1055+
10181056
// assertRefCount checks whether reference count for a given state
10191057
// at a given index is equal to expected amount.
10201058
func assertRefCount(t *testing.T, b *BeaconState, idx types.FieldIndex, want uint) {

beacon-chain/state/state-native/setters_validator.go

-7
Original file line numberDiff line numberDiff line change
@@ -40,30 +40,23 @@ func (b *BeaconState) SetValidators(val []*ethpb.Validator) error {
4040
func (b *BeaconState) ApplyToEveryValidator(f func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error)) error {
4141
var changedVals []uint64
4242
if features.Get().EnableExperimentalState {
43-
b.lock.Lock()
44-
4543
l := b.validatorsMultiValue.Len(b)
4644
for i := 0; i < l; i++ {
4745
v, err := b.validatorsMultiValue.At(b, uint64(i))
4846
if err != nil {
49-
b.lock.Unlock()
5047
return err
5148
}
5249
changed, newVal, err := f(i, v)
5350
if err != nil {
54-
b.lock.Unlock()
5551
return err
5652
}
5753
if changed {
5854
changedVals = append(changedVals, uint64(i))
5955
if err = b.validatorsMultiValue.UpdateAt(b, uint64(i), newVal); err != nil {
60-
b.lock.Unlock()
6156
return errors.Wrapf(err, "could not update validator at index %d", i)
6257
}
6358
}
6459
}
65-
66-
b.lock.Unlock()
6760
} else {
6861
b.lock.Lock()
6962

0 commit comments

Comments
 (0)