diff --git a/examples/berad/pkg/state-transition/interfaces.go b/examples/berad/pkg/state-transition/interfaces.go index 8408138182..92ffc91ed8 100644 --- a/examples/berad/pkg/state-transition/interfaces.go +++ b/examples/berad/pkg/state-transition/interfaces.go @@ -93,6 +93,9 @@ type ReadOnlyBeaconState[ ValidatorIndexByCometBFTAddress( cometBFTAddress []byte, ) (math.ValidatorIndex, error) + ValidatorIndexByPubkey( + crypto.BLSPubkey, + ) (math.ValidatorIndex, error) } // WriteOnlyBeaconState is the interface for a write-only beacon state. @@ -106,6 +109,7 @@ type WriteOnlyBeaconState[ DecreaseBalance(math.ValidatorIndex, math.Gwei) error IncreaseBalance(math.ValidatorIndex, math.Gwei) error + SetWithdrawalValidator(math.ValidatorIndex) error SetEth1DepositIndex(uint64) error SetFork(ForkT) error SetGenesisValidatorsRoot(root common.Root) error diff --git a/examples/berad/pkg/state-transition/state_processor_staking.go b/examples/berad/pkg/state-transition/state_processor_staking.go index 1f8b96aa94..b4f5676166 100644 --- a/examples/berad/pkg/state-transition/state_processor_staking.go +++ b/examples/berad/pkg/state-transition/state_processor_staking.go @@ -270,10 +270,21 @@ func (sp *StateProcessor[ func (sp *StateProcessor[ _, _, _, BeaconStateT, _, _, _, _, _, _, _, _, _, _, _, _, ]) processForcedWithdrawals( - _ BeaconStateT, - _ transition.ValidatorUpdates, + st BeaconStateT, + valUpdates transition.ValidatorUpdates, ) error { - // TODO: Implement this function. + // Process the forced withdrawals. + for _, valUpdate := range valUpdates { + idx, err := st.ValidatorIndexByPubkey(valUpdate.Pubkey) + if err != nil { + return err + } + + // Set the validator's effective balance to 0. + if err = st.SetWithdrawalValidator(idx); err != nil { + return err + } + } return nil } diff --git a/mod/storage/pkg/beacondb/keys/keys.go b/mod/storage/pkg/beacondb/keys/keys.go index 1efec85e9d..1b8fc5e6a8 100644 --- a/mod/storage/pkg/beacondb/keys/keys.go +++ b/mod/storage/pkg/beacondb/keys/keys.go @@ -43,6 +43,7 @@ const ( GenesisValidatorsRootPrefix NextWithdrawalIndexPrefix NextWithdrawalValidatorIndexPrefix + WithdrawalValidatorsPrefix ForkPrefix ) @@ -70,5 +71,6 @@ const ( GenesisValidatorsRootPrefixHumanReadable = "GenesisValidatorsRootPrefix" NextWithdrawalIndexPrefixHumanReadable = "NextWithdrawalIndexPrefix" NextWithdrawalValidatorIndexPrefixHumanReadable = "NextWithdrawalValidatorIndexPrefix" + WithdrawalValidatorsPrefixHumanReadable = "WithdrawalValidatorsPrefix" ForkPrefixHumanReadable = "ForkPrefix" ) diff --git a/mod/storage/pkg/beacondb/kvstore.go b/mod/storage/pkg/beacondb/kvstore.go index 7680df3256..0bf69dd081 100644 --- a/mod/storage/pkg/beacondb/kvstore.go +++ b/mod/storage/pkg/beacondb/kvstore.go @@ -98,6 +98,11 @@ type KVStore[ // nextWithdrawalValidatorIndex stores the next withdrawal validator index // for each validator. nextWithdrawalValidatorIndex sdkcollections.Item[uint64] + // withdrawalValidators stores the list of validators that need to be + // withdrawn. + withdrawalValidators *sdkcollections.IndexedMap[ + uint64, ValidatorT, index.ValidatorsIndex[ValidatorT], + ] // Randomness // randaoMix stores the randao mix for the current epoch. randaoMix sdkcollections.Map[uint64, []byte] @@ -253,6 +258,14 @@ func New[ keys.NextWithdrawalValidatorIndexPrefixHumanReadable, sdkcollections.Uint64Value, ), + withdrawalValidators: sdkcollections.NewIndexedMap( + schemaBuilder, + sdkcollections.NewPrefix([]byte{keys.WithdrawalValidatorsPrefix}), + keys.WithdrawalValidatorsPrefixHumanReadable, + sdkcollections.Uint64Key, + encoding.SSZValueCodec[ValidatorT]{}, + index.NewValidatorsIndex[ValidatorT](schemaBuilder), + ), totalSlashing: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.TotalSlashingPrefix}), diff --git a/mod/storage/pkg/beacondb/registry.go b/mod/storage/pkg/beacondb/registry.go index 25c0d11655..fd463912e5 100644 --- a/mod/storage/pkg/beacondb/registry.go +++ b/mod/storage/pkg/beacondb/registry.go @@ -50,7 +50,7 @@ func (kv *KVStore[ BeaconBlockHeaderT, Eth1DataT, ExecutionPayloadHeaderT, ForkT, ValidatorT, ValidatorsT, ]) AddValidatorBartio(val ValidatorT) error { - // Get the ne + // Get the next validator index from the sequence. idx, err := kv.validatorIndex.Next(kv.ctx) if err != nil { return err @@ -285,3 +285,38 @@ func (kv *KVStore[ }, ) } + +func (kv *KVStore[ + BeaconBlockHeaderT, Eth1DataT, ExecutionPayloadHeaderT, + ForkT, ValidatorT, ValidatorsT, +]) SetWithdrawalValidator( + idx math.ValidatorIndex, +) error { + val, err := kv.ValidatorByIndex(idx) + if err != nil { + return err + } + + // Set the withdrawal validator. + if err = kv.withdrawalValidators.Set(kv.ctx, idx.Unwrap(), val); err != nil { + return err + } + + // Get the next withdrawal index. + withdrawalIdx, err := kv.nextWithdrawalIndex.Get(kv.ctx) + if err != nil { + return err + } + + // Increment the withdrawal index. + if err = kv.nextWithdrawalIndex.Set(kv.ctx, withdrawalIdx+1); err != nil { + return err + } + + // Set the validator's balance to 0. + val.SetEffectiveBalance(0) + if err = kv.validators.Set(kv.ctx, idx.Unwrap(), val); err != nil { + return err + } + return kv.SetBalance(idx, 0) +} diff --git a/mod/storage/pkg/beacondb/types.go b/mod/storage/pkg/beacondb/types.go index cc401104de..8a22adfc6b 100644 --- a/mod/storage/pkg/beacondb/types.go +++ b/mod/storage/pkg/beacondb/types.go @@ -37,4 +37,6 @@ type Validator[SelfT any] interface { GetEffectiveBalance() math.Gwei // IsActive checks if the validator is active at the given epoch. IsActive(epoch math.Epoch) bool + // SetEffectiveBalance sets the effective balance of the validator. + SetEffectiveBalance(math.Gwei) }