mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-23 11:57:18 +00:00
Add back State To ComputeProposerIndex (#5674)
* add back state * fix tests * change method signatures * lint * Merge branch 'master' into addBackState * Merge branch 'master' into addBackState * terence's review * preston's review * add back comment
This commit is contained in:
parent
84e51a5236
commit
81a7bc7e05
@ -372,11 +372,10 @@ func precomputeProposerIndices(state *stateTrie.BeaconState, activeIndices []uin
|
||||
return nil, errors.Wrap(err, "could not generate seed")
|
||||
}
|
||||
slot := StartSlot(e)
|
||||
vals := state.Validators()
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(slot+i)...)
|
||||
seedWithSlotHash := hashFunc(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(vals, activeIndices, seedWithSlotHash)
|
||||
index, err := ComputeProposerIndex(state, activeIndices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -743,7 +743,7 @@ func TestPrecomputeProposerIndices_Ok(t *testing.T) {
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(state.Validators(), indices, seedWithSlotHash)
|
||||
index, err := ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -179,11 +179,63 @@ func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
return 0, errors.Wrap(err, "could not update committee cache")
|
||||
}
|
||||
|
||||
return ComputeProposerIndex(state.Validators(), indices, seedWithSlotHash)
|
||||
return ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
}
|
||||
|
||||
// ComputeProposerIndex returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// This method is more efficient than ComputeProposerIndexWithValidators as it uses the read only validator
|
||||
// abstraction to retrieve validator related data. Whereas the other method requires a whole copy of the validator
|
||||
// set.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Hash) -> ValidatorIndex:
|
||||
// """
|
||||
// Return from ``indices`` a random index sampled by effective balance.
|
||||
// """
|
||||
// assert len(indices) > 0
|
||||
// MAX_RANDOM_BYTE = 2**8 - 1
|
||||
// i = 0
|
||||
// while True:
|
||||
// candidate_index = indices[compute_shuffled_index(ValidatorIndex(i % len(indices)), len(indices), seed)]
|
||||
// random_byte = hash(seed + int_to_bytes(i // 32, length=8))[i % 32]
|
||||
// effective_balance = state.validators[candidate_index].effective_balance
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// return ValidatorIndex(candidate_index)
|
||||
// i += 1
|
||||
func ComputeProposerIndex(bState *stateTrie.BeaconState, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
length := uint64(len(activeIndices))
|
||||
if length == 0 {
|
||||
return 0, errors.New("empty active indices list")
|
||||
}
|
||||
maxRandomByte := uint64(1<<8 - 1)
|
||||
hashFunc := hashutil.CustomSHA256Hasher()
|
||||
|
||||
for i := uint64(0); ; i++ {
|
||||
candidateIndex, err := ComputeShuffledIndex(i%length, length, seed, true /* shuffle */)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
candidateIndex = activeIndices[candidateIndex]
|
||||
if int(candidateIndex) >= bState.NumValidators() {
|
||||
return 0, errors.New("active index out of range")
|
||||
}
|
||||
b := append(seed[:], bytesutil.Bytes8(i/32)...)
|
||||
randomByte := hashFunc(b)[i%32]
|
||||
v, err := bState.ValidatorAtIndexReadOnly(candidateIndex)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
effectiveBal := v.EffectiveBalance()
|
||||
|
||||
if effectiveBal*maxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) {
|
||||
return candidateIndex, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ComputeProposerIndexWithValidators returns the index sampled by effective balance, which is used to calculate proposer.
|
||||
//
|
||||
// Note: This method signature deviates slightly from the spec recommended definition. The full
|
||||
// state object is not required to compute the proposer index.
|
||||
//
|
||||
@ -202,7 +254,8 @@ func BeaconProposerIndex(state *stateTrie.BeaconState) (uint64, error) {
|
||||
// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte:
|
||||
// return ValidatorIndex(candidate_index)
|
||||
// i += 1
|
||||
func ComputeProposerIndex(validators []*ethpb.Validator, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
// Deprecated: Prefer using the beacon state with ComputeProposerIndex to avoid an unnecessary copy of the validator set.
|
||||
func ComputeProposerIndexWithValidators(validators []*ethpb.Validator, activeIndices []uint64, seed [32]byte) (uint64, error) {
|
||||
length := uint64(len(activeIndices))
|
||||
if length == 0 {
|
||||
return 0, errors.New("empty active indices list")
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
@ -184,6 +186,62 @@ func TestBeaconProposerIndex_OK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestComputeProposerIndex_Compatibility(t *testing.T) {
|
||||
validators := make([]*ethpb.Validator, params.BeaconConfig().MinGenesisActiveValidatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = ðpb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
indices, err := ActiveValidatorIndices(state, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var proposerIndices []uint64
|
||||
seed, err := Seed(state, 0, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndex(state, indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proposerIndices = append(proposerIndices, index)
|
||||
}
|
||||
|
||||
var wantedProposerIndices []uint64
|
||||
seed, err = Seed(state, 0, params.BeaconConfig().DomainBeaconProposer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
|
||||
seedWithSlot := append(seed[:], bytesutil.Bytes8(i)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
index, err := ComputeProposerIndexWithValidators(state.Validators(), indices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedProposerIndices = append(wantedProposerIndices, index)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(wantedProposerIndices, proposerIndices) {
|
||||
t.Error("Wanted proposer indices from ComputeProposerIndexWithValidators does not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelayedActivationExitEpoch_OK(t *testing.T) {
|
||||
epoch := uint64(9999)
|
||||
got := ActivationExitEpoch(epoch)
|
||||
@ -541,7 +599,13 @@ func TestComputeProposerIndex(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := ComputeProposerIndex(tt.args.validators, tt.args.indices, tt.args.seed)
|
||||
bState := &pb.BeaconState{Validators: tt.args.validators}
|
||||
stTrie, err := beaconstate.InitializeFromProtoUnsafe(bState)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
got, err := ComputeProposerIndex(stTrie, tt.args.indices, tt.args.seed)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ComputeProposerIndex() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -291,7 +291,7 @@ func archivedValidatorCommittee(
|
||||
for slot := startSlot; slot < startSlot+params.BeaconConfig().SlotsPerEpoch; slot++ {
|
||||
seedWithSlot := append(proposerSeed[:], bytesutil.Bytes8(slot)...)
|
||||
seedWithSlotHash := hashutil.Hash(seedWithSlot)
|
||||
i, err := helpers.ComputeProposerIndex(activeVals, activeIndices, seedWithSlotHash)
|
||||
i, err := helpers.ComputeProposerIndexWithValidators(activeVals, activeIndices, seedWithSlotHash)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not check proposer at slot %d", slot)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user