Skip to content

Commit

Permalink
send only validators set diffs
Browse files Browse the repository at this point in the history
  • Loading branch information
abi87 committed Nov 9, 2024
1 parent eda7909 commit c6b5586
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 24 deletions.
6 changes: 6 additions & 0 deletions mod/state-transition/pkg/core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ type StateProcessor[
// processingGenesis allows initializing correctly
// eth1 deposit index upon genesis
processingGenesis bool

// prevEpochValidators tracks the set of validators active during
// previous epoch. This is useful at the turn of the epoch to send to
// consensus only the diffs rather than the full updated validator set.
prevEpochValidators []*transition.ValidatorUpdate
}

// NewStateProcessor creates a new state processor.
Expand Down Expand Up @@ -163,6 +168,7 @@ func NewStateProcessor[
executionEngine: executionEngine,
signer: signer,
fGetAddressFromPubKey: fGetAddressFromPubKey,
prevEpochValidators: make([]*transition.ValidatorUpdate, 0),
}
}

Expand Down
21 changes: 2 additions & 19 deletions mod/state-transition/pkg/core/state_processor_staking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
package core_test

import (
"fmt"
"testing"

"github.com/berachain/beacon-kit/mod/config/pkg/spec"
Expand Down Expand Up @@ -214,15 +213,7 @@ func TestTransitionUpdateValidator(t *testing.T) {

newEpochVals, err := sp.Transition(ctx, beaconState, blk)
require.NoError(t, err)
require.Len(t, newEpochVals, len(genDeposits)) // just topped up one validator

// Assuming genesis order is preserved here which is not necessary
// TODO: remove this assumption

// all genesis validators other than the last are unchanged
for i := range len(genDeposits) - 1 {
require.Equal(t, genVals[i], newEpochVals[i], fmt.Sprintf("idx: %d", i))
}
require.Len(t, newEpochVals, 1) // just topped up one validator

expectedBalance = genDeposits[2].Amount + blkDeposit.Amount
expectedEffectiveBalance = expectedBalance
Expand Down Expand Up @@ -400,15 +391,7 @@ func TestTransitionCreateValidator(t *testing.T) {

newEpochVals, err := sp.Transition(ctx, beaconState, blk)
require.NoError(t, err)
require.Len(t, newEpochVals, len(genDeposits)+1)

// Assuming genesis order is preserved here which is not necessary
// TODO: remove this assumption

// all genesis validators are unchanged
for i := range len(genDeposits) {
require.Equal(t, genVals[i], newEpochVals[i], fmt.Sprintf("idx: %d", i))
}
require.Len(t, newEpochVals, 1) // just added 1 validator

expectedBalance = blkDeposit.Amount
expectedEffectiveBalance = expectedBalance
Expand Down
52 changes: 47 additions & 5 deletions mod/state-transition/pkg/core/state_processor_validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@
package core

import (
"github.com/berachain/beacon-kit/mod/primitives/pkg/bytes"
"github.com/berachain/beacon-kit/mod/primitives/pkg/math"
"github.com/berachain/beacon-kit/mod/primitives/pkg/transition"
"github.com/sourcegraph/conc/iter"
)

// processValidatorsSetUpdates returns the validators set updates that
// will be used by consensus
// will be used by consensus.
func (sp *StateProcessor[
_, _, _, BeaconStateT, _, _, _, _, _, _, _, _, ValidatorT, _, _, _, _,
]) processValidatorsSetUpdates(
Expand All @@ -46,10 +47,10 @@ func (sp *StateProcessor[
}
}

// TODO: a more efficient handling would be to only send back to consensus
// updated validators (including evicted ones), rather than the full list

return iter.MapErr(
// We need to inform consensus of the changes incurred by the validator set
// We strive to send only diffs (added,updated or removed validators) and
// avoid re-sending validators that have not changed.
currentValSet, err := iter.MapErr(
activeVals,
func(val *ValidatorT) (*transition.ValidatorUpdate, error) {
v := (*val)
Expand All @@ -59,4 +60,45 @@ func (sp *StateProcessor[
}, nil
},
)
if err != nil {
return nil, err
}

res := make([]*transition.ValidatorUpdate, 0)

prevValsSet := make(map[string]math.Gwei, len(sp.prevEpochValidators))
for _, v := range sp.prevEpochValidators {
prevValsSet[string(v.Pubkey[:])] = v.EffectiveBalance
}

for _, newVal := range currentValSet {
key := string(newVal.Pubkey[:])
oldBal, found := prevValsSet[key]
if !found {
// new validator, we add it with its weight
res = append(res, newVal)
continue
}
if oldBal != newVal.EffectiveBalance {
// validator updated, we add it with new weight
res = append(res, newVal)
}

// consume pre-existing validators
delete(prevValsSet, key)
}

// prevValsSet now contains all evicted validators (and only those)
for pkBytes := range prevValsSet {
//#nosec:G703 // bytes comes from a pk
pk, _ := bytes.ToBytes48([]byte(pkBytes))
res = append(res, &transition.ValidatorUpdate{
Pubkey: pk,
EffectiveBalance: 0, // signal val eviction to consensus
})
}

// rotate validators set to new epoch ones
sp.prevEpochValidators = currentValSet
return res, nil
}

0 comments on commit c6b5586

Please sign in to comment.