mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-26 05:27:19 +00:00
Add ComputeProposerIndex (#6297)
This is described in
https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_proposer_index.
Part of https://github.com/ledgerwatch/erigon/issues/5965
I compared with the Prysm tests to confirm the implementation is
correct:
2e49fdb3d2/beacon-chain/core/helpers/validators_test.go (L506-L614)
This commit is contained in:
parent
cb04e1166c
commit
d1f6ed29ff
@ -4,6 +4,9 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ledgerwatch/erigon/cl/clparams"
|
||||||
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SHUFFLE_ROUND_COUNT = uint8(90)
|
const SHUFFLE_ROUND_COUNT = uint8(90)
|
||||||
@ -50,3 +53,34 @@ func ComputeShuffledIndex(ind, ind_count uint64, seed [32]byte) (uint64, error)
|
|||||||
}
|
}
|
||||||
return ind, nil
|
return ind, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ComputePropserIndex(state *cltypes.BeaconStateBellatrix, indices []uint64, seed [32]byte) (uint64, error) {
|
||||||
|
if len(indices) == 0 {
|
||||||
|
return 0, fmt.Errorf("must have >0 indices")
|
||||||
|
}
|
||||||
|
maxRandomByte := uint64(1<<8 - 1)
|
||||||
|
i := uint64(0)
|
||||||
|
total := uint64(len(indices))
|
||||||
|
hash := sha256.New()
|
||||||
|
buf := make([]byte, 8)
|
||||||
|
for {
|
||||||
|
shuffled, err := ComputeShuffledIndex(i%total, total, seed)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
candidateIndex := indices[shuffled]
|
||||||
|
if candidateIndex >= uint64(len(state.Validators)) {
|
||||||
|
return 0, fmt.Errorf("candidate index out of range: %d for validator set of length: %d", candidateIndex, len(state.Validators))
|
||||||
|
}
|
||||||
|
binary.LittleEndian.PutUint64(buf, i/32)
|
||||||
|
input := append(seed[:], buf...)
|
||||||
|
hash.Reset()
|
||||||
|
hash.Write(input)
|
||||||
|
randomByte := uint64(hash.Sum(nil)[i%32])
|
||||||
|
effectiveBalance := state.Validators[candidateIndex].EffectiveBalance
|
||||||
|
if effectiveBalance*maxRandomByte >= clparams.MainnetBeaconConfig.MaxEffectiveBalance*randomByte {
|
||||||
|
return candidateIndex, nil
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@ package transition
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ledgerwatch/erigon/cl/cltypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestComputeShuffledIndex(t *testing.T) {
|
func TestComputeShuffledIndex(t *testing.T) {
|
||||||
@ -34,3 +36,102 @@ func TestComputeShuffledIndex(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestComputeProposerIndex(t *testing.T) {
|
||||||
|
seed := [32]byte{}
|
||||||
|
copy(seed[:], []byte("seed"))
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
state *cltypes.BeaconStateBellatrix
|
||||||
|
indices []uint64
|
||||||
|
seed [32]byte
|
||||||
|
expected uint64
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "success",
|
||||||
|
state: &cltypes.BeaconStateBellatrix{
|
||||||
|
Validators: []*cltypes.Validator{
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indices: []uint64{0, 1, 2, 3, 4},
|
||||||
|
seed: seed,
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "single_active_index",
|
||||||
|
state: &cltypes.BeaconStateBellatrix{
|
||||||
|
Validators: []*cltypes.Validator{
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indices: []uint64{3},
|
||||||
|
seed: seed,
|
||||||
|
expected: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "second_half_active",
|
||||||
|
state: &cltypes.BeaconStateBellatrix{
|
||||||
|
Validators: []*cltypes.Validator{
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
indices: []uint64{5, 6, 7, 8, 9},
|
||||||
|
seed: seed,
|
||||||
|
expected: 7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "zero_active_indices",
|
||||||
|
indices: []uint64{},
|
||||||
|
seed: seed,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "active_index_out_of_range",
|
||||||
|
indices: []uint64{100},
|
||||||
|
state: &cltypes.BeaconStateBellatrix{
|
||||||
|
Validators: []*cltypes.Validator{
|
||||||
|
{EffectiveBalance: testBeaconConfig.MaxEffectiveBalance},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
seed: seed,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
got, err := ComputePropserIndex(tc.state, tc.indices, tc.seed)
|
||||||
|
if tc.wantErr {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("unexpected success, wanted error")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if got != tc.expected {
|
||||||
|
t.Errorf("unexpected result: got %d, want %d", got, tc.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user