Skip to content

Commit

Permalink
Cleaned up and optimized proposer index retriaval. (erigontech#6799)
Browse files Browse the repository at this point in the history
  • Loading branch information
Giulio2002 authored and finiteops committed Apr 10, 2023
1 parent 37cc3d7 commit 1c22a4c
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 50 deletions.
28 changes: 2 additions & 26 deletions cmd/erigon-cl/core/state/accessors.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package state

import (
"crypto/sha256"
"encoding/binary"
"fmt"
"sort"
Expand Down Expand Up @@ -182,7 +181,7 @@ func (b *BeaconState) ComputeShuffledIndex(ind, ind_count uint64, seed [32]byte,
return ind, nil
}

func (b *BeaconState) ComputeCommittee(indicies []uint64, seed libcommon.Hash, index, count uint64, preInputs [][32]byte, hashFunc utils.HashFunc) ([]uint64, error) {
func (b *BeaconState) ComputeCommittee(indicies []uint64, seed libcommon.Hash, index, count uint64, hashFunc utils.HashFunc) ([]uint64, error) {
lenIndicies := uint64(len(indicies))
start := (lenIndicies * index) / count
end := (lenIndicies * (index + 1)) / count
Expand Down Expand Up @@ -240,28 +239,7 @@ func (b *BeaconState) GetRandaoMixes(epoch uint64) [32]byte {
}

func (b *BeaconState) GetBeaconProposerIndex() (uint64, error) {
epoch := b.Epoch()

hash := sha256.New()
// Input for the seed hash.
input := b.GetSeed(epoch, clparams.MainnetBeaconConfig.DomainBeaconProposer)
slotByteArray := make([]byte, 8)
binary.LittleEndian.PutUint64(slotByteArray, b.Slot())

// Add slot to the end of the input.
inputWithSlot := append(input[:], slotByteArray...)

// Calculate the hash.
hash.Write(inputWithSlot)
seed := hash.Sum(nil)

indices := b.GetActiveValidatorsIndices(epoch)

// Write the seed to an array.
seedArray := [32]byte{}
copy(seedArray[:], seed)

return b.ComputeProposerIndex(indices, seedArray)
return b.proposerIndex, nil
}

func (b *BeaconState) GetSeed(epoch uint64, domain [4]byte) libcommon.Hash {
Expand Down Expand Up @@ -377,14 +355,12 @@ func (b *BeaconState) GetBeaconCommitee(slot, committeeIndex uint64) ([]uint64,
epoch := b.GetEpochAtSlot(slot)
committeesPerSlot := b.CommitteeCount(epoch)
seed := b.GetSeed(epoch, b.beaconConfig.DomainBeaconAttester)
preInputs := b.ComputeShuffledIndexPreInputs(seed)
hashFunc := utils.OptimizedKeccak256()
committee, err := b.ComputeCommittee(
b.GetActiveValidatorsIndices(epoch),
seed,
(slot%b.beaconConfig.SlotsPerEpoch)*committeesPerSlot+committeeIndex,
committeesPerSlot*b.beaconConfig.SlotsPerEpoch,
preInputs,
hashFunc,
)
if err != nil {
Expand Down
5 changes: 2 additions & 3 deletions cmd/erigon-cl/core/state/accessors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,12 @@ func TestComputeCommittee(t *testing.T) {
epoch := state.Epoch()
indices := state.GetActiveValidatorsIndices(epoch)
seed := state.GetSeed(epoch, clparams.MainnetBeaconConfig.DomainBeaconAttester)
preInputs := state.ComputeShuffledIndexPreInputs(seed)
committees, err := state.ComputeCommittee(indices, seed, 0, 1, preInputs, utils.Keccak256)
committees, err := state.ComputeCommittee(indices, seed, 0, 1, utils.Keccak256)
require.NoError(t, err, "Could not compute committee")

// Test shuffled indices are correct for index 5 committee
index := uint64(5)
committee5, err := state.ComputeCommittee(indices, seed, index, committeeCount, preInputs, utils.Keccak256)
committee5, err := state.ComputeCommittee(indices, seed, index, committeeCount, utils.Keccak256)
require.NoError(t, err, "Could not compute committee")
start := (validatorCount * index) / committeeCount
end := (validatorCount * (index + 1)) / committeeCount
Expand Down
5 changes: 0 additions & 5 deletions cmd/erigon-cl/core/state/mutators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,6 @@ func TestSlashValidator(t *testing.T) {
wantBalances: wantBalances,
wantErr: false,
},
{
description: "fail_no_active_validators",
state: failState,
wantErr: true,
},
}

for _, tc := range testCases {
Expand Down
8 changes: 5 additions & 3 deletions cmd/erigon-cl/core/state/setters.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ func (b *BeaconState) SetGenesisValidatorsRoot(genesisValidatorRoot libcommon.Ha
b.genesisValidatorsRoot = genesisValidatorRoot
}

func (b *BeaconState) SetSlot(slot uint64) {
func (b *BeaconState) SetSlot(slot uint64) error {
b.touchedLeaves[SlotLeafIndex] = true
b.slot = slot
// If there is a new slot update the active balance cache.
b._refreshActiveBalances()
// Also re-update proposer index
return b._updateProposerIndex()
}

func (b *BeaconState) SetFork(fork *cltypes.Fork) {
Expand Down Expand Up @@ -90,10 +92,10 @@ func (b *BeaconState) SetEth1DepositIndex(eth1DepositIndex uint64) {
}

// Should not be called if not for testing
func (b *BeaconState) SetValidators(validators []*cltypes.Validator) {
func (b *BeaconState) SetValidators(validators []*cltypes.Validator) error {
b.touchedLeaves[ValidatorsLeafIndex] = true
b.validators = validators
b.initBeaconState()
return b.initBeaconState()
}

func (b *BeaconState) AddValidator(validator *cltypes.Validator, balance uint64) {
Expand Down
6 changes: 5 additions & 1 deletion cmd/erigon-cl/core/state/ssz.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,11 @@ func (b *BeaconState) EncodeSSZ(buf []byte) ([]byte, error) {

func (b *BeaconState) DecodeSSZWithVersion(buf []byte, version int) error {
// Initialize beacon state
defer b.initBeaconState()
defer func() {
if err := b.initBeaconState(); err != nil {
panic(err)
}
}()

b.version = clparams.StateVersion(version)
if len(buf) < b.EncodingSizeSSZ() {
Expand Down
52 changes: 41 additions & 11 deletions cmd/erigon-cl/core/state/state.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package state

import (
"crypto/sha256"
"encoding/binary"

lru "github.com/hashicorp/golang-lru"
libcommon "github.com/ledgerwatch/erigon-lib/common"

Expand Down Expand Up @@ -61,6 +64,7 @@ type BeaconState struct {
committeeCache *lru.Cache
shuffledSetsCache *lru.Cache
totalActiveBalanceCache uint64
proposerIndex uint64
// Configs
beaconConfig *clparams.BeaconChainConfig
}
Expand Down Expand Up @@ -111,7 +115,33 @@ func (b *BeaconState) _refreshActiveBalances() {
}
}

func (b *BeaconState) initBeaconState() {
func (b *BeaconState) _updateProposerIndex() (err error) {
epoch := b.Epoch()

hash := sha256.New()
// Input for the seed hash.
input := b.GetSeed(epoch, clparams.MainnetBeaconConfig.DomainBeaconProposer)
slotByteArray := make([]byte, 8)
binary.LittleEndian.PutUint64(slotByteArray, b.Slot())

// Add slot to the end of the input.
inputWithSlot := append(input[:], slotByteArray...)

// Calculate the hash.
hash.Write(inputWithSlot)
seed := hash.Sum(nil)

indices := b.GetActiveValidatorsIndices(epoch)

// Write the seed to an array.
seedArray := [32]byte{}
copy(seedArray[:], seed)

b.proposerIndex, err = b.ComputeProposerIndex(indices, seedArray)
return
}

func (b *BeaconState) initBeaconState() error {
if b.touchedLeaves == nil {
b.touchedLeaves = make(map[StateLeafIndex]bool)
}
Expand All @@ -120,18 +150,18 @@ func (b *BeaconState) initBeaconState() {
for i, validator := range b.validators {
b.publicKeyIndicies[validator.PublicKey] = uint64(i)
}
// 5 Epochs at a time is reasonable.
var err error
b.activeValidatorsCache, err = lru.New(5)
if err != nil {
panic(err)
if b.activeValidatorsCache, err = lru.New(5); err != nil {
return err
}
b.shuffledSetsCache, err = lru.New(25)
if err != nil {
panic(err)
if b.shuffledSetsCache, err = lru.New(25); err != nil {
return err
}
b.committeeCache, err = lru.New(256)
if err != nil {
panic(err)
if b.committeeCache, err = lru.New(256); err != nil {
return err
}
if err := b._updateProposerIndex(); err != nil {
return err
}
return nil
}
34 changes: 34 additions & 0 deletions cmd/erigon-cl/core/state/state_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package state_test

import (
"testing"

"github.com/ledgerwatch/erigon/cl/clparams"
"github.com/ledgerwatch/erigon/cl/utils"
"github.com/ledgerwatch/erigon/cmd/erigon-cl/core/state"
eth2_shuffle "github.com/protolambda/eth2-shuffle"
)

func BenchmarkLambdaShuffledIndex(b *testing.B) {
keccakOptimized := utils.OptimizedKeccak256()
eth2ShuffleHash := func(data []byte) []byte {
hashed := keccakOptimized(data)
return hashed[:]
}
seed := [32]byte{2, 35, 6}
for i := 0; i < b.N; i++ {
eth2_shuffle.PermuteIndex(eth2ShuffleHash, uint8(clparams.MainnetBeaconConfig.ShuffleRoundCount), 10, 1000, seed)
}
}

// Faster by ~40%, the effects of it will be felt mostly on computation of the proposer index.
func BenchmarkErigonShuffledIndex(b *testing.B) {
s := state.GetEmptyBeaconState()
keccakOptimized := utils.OptimizedKeccak256()

seed := [32]byte{2, 35, 6}
preInputs := s.ComputeShuffledIndexPreInputs(seed)
for i := 0; i < b.N; i++ {
s.ComputeShuffledIndex(10, 1000, seed, preInputs, keccakOptimized)
}
}
4 changes: 3 additions & 1 deletion cmd/erigon-cl/core/transition/process_slots.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ func (s *StateTransistor) processSlots(slot uint64) error {
}
// TODO: add logic to process epoch updates.
stateSlot += 1
s.state.SetSlot(stateSlot)
if err := s.state.SetSlot(stateSlot); err != nil {
return err
}
}
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/erigon-cl/core/transition/process_slots_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ func TestTransitionSlot(t *testing.T) {

func TestProcessSlots(t *testing.T) {
slot42 := getTestBeaconState()
slot42.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, WithdrawableEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch}, 1)
slot42.SetSlot(42)
testCases := []struct {
description string
Expand Down Expand Up @@ -240,6 +241,7 @@ func TestProcessSlots(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) {
tc.prevState.AddValidator(&cltypes.Validator{ExitEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch, WithdrawableEpoch: clparams.MainnetBeaconConfig.FarFutureEpoch}, 1)
s := New(tc.prevState, &clparams.MainnetBeaconConfig, nil, false)
err := s.processSlots(tc.startSlot + tc.numSlots)
if tc.wantErr {
Expand Down
1 change: 1 addition & 0 deletions cmd/sentinel/sentinel/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func (s *Sentinel) onConnection(net network.Network, conn network.Conn) {
peerId := conn.RemotePeer()
invalid := !s.handshaker.ValidatePeer(peerId)
if invalid {
log.Trace("Handshake was unsuccessful")
s.peers.DisconnectPeer(peerId)
}
}()
Expand Down

0 comments on commit 1c22a4c

Please sign in to comment.