Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(blockchain): introducing validator size cap size #2119

Open
wants to merge 15 commits into
base: fix-maximum-number-withdrawals
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions mod/chain-spec/pkg/chain/chain_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ type Spec[
// GetCometBFTConfigForSlot retrieves the CometBFT config for a specific
// slot.
GetCometBFTConfigForSlot(slot SlotT) CometBFTConfigT

// GetValidatorSetCap retrieves the maximum number of validators
// allowed in the active set.
GetValidatorsSetCapSize() uint32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
GetValidatorsSetCapSize() uint32
// GetValidatorSetCap retrieves the maximum number of validators allowed in the active set.
GetValidatorSetCap() uint32

nit + comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems comment was changed, but function name still needs to be changed to GetValidatorSetCap

}

// chainSpec is a concrete implementation of the ChainSpec interface, holding
Expand Down Expand Up @@ -476,3 +480,11 @@ func (c chainSpec[
]) GetCometBFTConfigForSlot(_ SlotT) CometBFTConfigT {
return c.Data.CometValues
}

// GetValidatorSetCap retrieves the maximum number of validators
// allowed in the active set.
func (c chainSpec[
abi87 marked this conversation as resolved.
Show resolved Hide resolved
DomainTypeT, EpochT, ExecutionAddressT, SlotT, CometBFTConfigT,
]) GetValidatorsSetCapSize() uint32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: GetValidatorSetCap

return c.Data.ValidatorSetCapSize
}
3 changes: 3 additions & 0 deletions mod/chain-spec/pkg/chain/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,7 @@ type SpecData[

// CometValues
CometValues CometBFTConfigT `mapstructure:"comet-bft-config"`

// Validators Set config
ValidatorSetCapSize uint32 `mapstructure:"validator-set-cap-size"`
}
1 change: 1 addition & 0 deletions mod/config/pkg/spec/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,6 @@ func BaseSpec() chain.SpecData[
BytesPerBlob: 131072,
KZGCommitmentInclusionProofDepth: 17,
CometValues: cmtConsensusParams,
ValidatorSetCapSize: 256,
}
}
5 changes: 5 additions & 0 deletions mod/consensus-types/pkg/types/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ func (v *Validator) SetEffectiveBalance(balance math.Gwei) {
v.EffectiveBalance = balance
}

// SetWithdrawableEpoch sets the epoch when the validator can withdraw.
func (v *Validator) SetWithdrawableEpoch(e math.Epoch) {
abi87 marked this conversation as resolved.
Show resolved Hide resolved
v.WithdrawableEpoch = e
}

// GetWithdrawableEpoch returns the epoch when the validator can withdraw.
func (v Validator) GetWithdrawableEpoch() math.Epoch {
return v.WithdrawableEpoch
Expand Down
4 changes: 4 additions & 0 deletions mod/state-transition/pkg/core/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ package core
import "github.com/berachain/beacon-kit/mod/errors"

var (
// ErrValidatorSetCapHit is returned when we try and add a validator
// that would breach validator set size cap.
ErrHitValidatorsSetCap = errors.New("hit validator set size cap")

// ErrBlockSlotTooLow is returned when the block slot is too low.
ErrBlockSlotTooLow = errors.New("block slot too low")

Expand Down
11 changes: 2 additions & 9 deletions mod/state-transition/pkg/core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,22 +282,15 @@ func (sp *StateProcessor[
st BeaconStateT,
blk BeaconBlockT,
) error {
// process the freshly created header.
if err := sp.processBlockHeader(st, blk); err != nil {
return err
}

// process the execution payload.
if err := sp.processExecutionPayload(
ctx, st, blk,
); err != nil {
if err := sp.processExecutionPayload(ctx, st, blk); err != nil {
return err
}

// process the withdrawals.
if err := sp.processWithdrawals(
st, blk.GetBody(),
); err != nil {
if err := sp.processWithdrawals(st, blk.GetBody()); err != nil {
return err
}

Expand Down
13 changes: 13 additions & 0 deletions mod/state-transition/pkg/core/state_processor_genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
package core

import (
"fmt"

"github.com/berachain/beacon-kit/mod/primitives/pkg/common"
"github.com/berachain/beacon-kit/mod/primitives/pkg/constants"
"github.com/berachain/beacon-kit/mod/primitives/pkg/encoding/hex"
Expand Down Expand Up @@ -106,6 +108,17 @@ func (sp *StateProcessor[
}
}

// BeaconKit enforces a cap on the validator set size.
// If genesis deposits breaches the cap we return an error.
//#nosec:G701 // can't overflow.
if uint32(len(deposits)) > sp.cs.GetValidatorsSetCapSize() {
return nil, fmt.Errorf("validator set cap %d, deposits count %d: %w",
sp.cs.GetValidatorsSetCapSize(),
len(deposits),
ErrHitValidatorsSetCap,
)
}
Comment on lines +114 to +120
Copy link
Collaborator Author

@abi87 abi87 Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here I assume deposits in genesis maps one to one with genesis validators and we do not have two different updates for the same validator.
Is it a fair assumption @chuck-bear, @itsdevbear?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be necessary to allow multiple deposits per genesis validator if each deposit is capped to some amount like 32


for _, deposit := range deposits {
if err := sp.processDeposit(st, deposit); err != nil {
return nil, err
Expand Down
31 changes: 27 additions & 4 deletions mod/state-transition/pkg/core/state_processor_staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,12 +196,35 @@ func (sp *StateProcessor[
math.Gwei(sp.cs.MaxEffectiveBalance()),
)

// TODO: This is a bug that lives on bArtio. Delete this eventually.
if sp.cs.DepositEth1ChainID() == bArtioChainID {
if err := st.AddValidatorBartio(val); err != nil {
if !sp.processingGenesis {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor optimization which we may drop for readability.
Currently I chose to fail node initialization if genesis has more validators than the validator set cap, so here I can skip the check.
However we may chose to allow genesis have more validators than cap and immediately mark the ready for eviction.
@itsdevbear @chuck-bear thoughts?

// BeaconKit enforces a cap on the validator set size. If a deposit is made
// that would breach the cap, we mark the validator as immediately
// withdrawable, so that it will be evicted in the next block along with
// the amount deposited.
validators, err := st.GetValidators()
if err != nil {
return err
}
} else if err := st.AddValidator(val); err != nil {

//#nosec:G701 // can't overflow.
if uint32(len(validators)) >= sp.cs.GetValidatorsSetCapSize() {
var slot math.Slot
slot, err = st.GetSlot()
if err != nil {
return err
}

epoch := sp.cs.SlotToEpoch(slot)
val.SetWithdrawableEpoch(epoch)
}
}

// TODO: This is a bug that lives on bArtio. Delete this eventually.
if sp.cs.DepositEth1ChainID() == bArtioChainID {
return st.AddValidatorBartio(val)
}
Comment on lines +223 to +225
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replicating here the fix from #2111 to avoid double counting Bartio Validators balances (done implicitly in AddValidatorBartio)


if err := st.AddValidator(val); err != nil {
return err
}

Expand Down
Loading
Loading