mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-05 10:32:19 +00:00
24987878e4
* Most of the PR changed files are extra and slightly more complicated unit tests. * Fixed Eth1DataVotes not inheriting genesis * Fixed Attestations simulation using wrong slot when reconstructing partecipation * Fixed Copy() operation on BeaconState on Eth1DataVotes * Used correct ListSSZ type for Eth1DataVotes and HistoricalSummaries * Fixed wrong []uint64 deltas on empty slots
390 lines
13 KiB
Go
390 lines
13 KiB
Go
package state_accessors
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"sync"
|
|
|
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
|
"github.com/ledgerwatch/erigon/cl/cltypes/solid"
|
|
"github.com/ledgerwatch/erigon/ethdb/cbor"
|
|
)
|
|
|
|
// class Validator(Container):
|
|
//
|
|
// pubkey: BLSPubkey
|
|
// withdrawal_credentials: Bytes32 # Commitment to pubkey for withdrawals
|
|
// effective_balance: Gwei # Balance at stake
|
|
// slashed: boolean
|
|
// # Status epochs
|
|
// activation_eligibility_epoch: Epoch # When criteria for activation were met
|
|
// activation_epoch: Epoch
|
|
// exit_epoch: Epoch
|
|
// withdrawable_epoch: Epoch # When validator can withdraw funds
|
|
//
|
|
// StaticValidator is designed to track changes in a validator's attributes over time.
|
|
// It keeps track of attributes such as withdrawal credentials, slashed status, and various epochs
|
|
// that typically change at most twice during the validator's lifespan.
|
|
type StaticValidator struct {
|
|
publicKeys []staticValidatorField[libcommon.Bytes48] // Tracks changes in public keys.
|
|
withdrawalCredentials []staticValidatorField[libcommon.Hash] // Tracks changes in withdrawal credentials.
|
|
slashed []staticValidatorField[bool] // Tracks changes in slashed status.
|
|
activationEligibility []staticValidatorField[uint64] // Tracks changes in activation eligibility epoch.
|
|
activationEpoch []staticValidatorField[uint64] // Tracks changes in activation epoch.
|
|
exitEpoch []staticValidatorField[uint64] // Tracks changes in exit epoch.
|
|
withdrawableEpoch []staticValidatorField[uint64] // Tracks changes in withdrawable epoch.
|
|
}
|
|
|
|
// NewStaticValidatorFromValidator creates a new StaticValidator from a given Validator and Slot,
|
|
// initializing the fields with the current state of the Validator at the given Slot.
|
|
func NewStaticValidatorFromValidator(v solid.Validator, slot uint64) *StaticValidator {
|
|
return &StaticValidator{
|
|
// Initializes each field with the current state of the validator.
|
|
publicKeys: []staticValidatorField[libcommon.Bytes48]{{slot, v.PublicKey()}},
|
|
withdrawalCredentials: []staticValidatorField[libcommon.Hash]{{slot, v.WithdrawalCredentials()}},
|
|
slashed: []staticValidatorField[bool]{{slot, v.Slashed()}},
|
|
activationEligibility: []staticValidatorField[uint64]{{slot, v.ActivationEligibilityEpoch()}},
|
|
activationEpoch: []staticValidatorField[uint64]{{slot, v.ActivationEpoch()}},
|
|
exitEpoch: []staticValidatorField[uint64]{{slot, v.ExitEpoch()}},
|
|
withdrawableEpoch: []staticValidatorField[uint64]{{slot, v.WithdrawableEpoch()}},
|
|
}
|
|
}
|
|
|
|
// AddWithdrawalCredentials adds a new withdrawal credential entry to the validator.
|
|
// This method is used to track changes in withdrawal credentials over time.
|
|
func (s *StaticValidator) AddWithdrawalCredentials(slot uint64, withdrawalCredentials libcommon.Hash) {
|
|
s.withdrawalCredentials = append(s.withdrawalCredentials, staticValidatorField[libcommon.Hash]{slot, withdrawalCredentials})
|
|
}
|
|
|
|
// cborStaticValidator is a struct used for CBOR serialization of StaticValidator data.
|
|
type cborStaticValidator struct {
|
|
PublicKeys []staticValidatorField[libcommon.Bytes48]
|
|
WithdrawalCredentials []staticValidatorField[libcommon.Hash]
|
|
Slashed []staticValidatorField[bool]
|
|
ActivationEligibility []staticValidatorField[uint64]
|
|
ActivationEpoch []staticValidatorField[uint64]
|
|
ExitEpoch []staticValidatorField[uint64]
|
|
WithdrawableEpoch []staticValidatorField[uint64]
|
|
}
|
|
|
|
// Serialize encodes the StaticValidator data into CBOR format and writes it to the given writer.
|
|
func (s *StaticValidator) WriteTo(w io.Writer) error {
|
|
return cbor.Marshal(w, cborStaticValidator{
|
|
PublicKeys: s.publicKeys,
|
|
WithdrawalCredentials: s.withdrawalCredentials,
|
|
Slashed: s.slashed,
|
|
ActivationEligibility: s.activationEligibility,
|
|
ActivationEpoch: s.activationEpoch,
|
|
ExitEpoch: s.exitEpoch,
|
|
WithdrawableEpoch: s.withdrawableEpoch,
|
|
})
|
|
}
|
|
|
|
// Deserialize decodes CBOR data from the given reader and updates the StaticValidator fields.
|
|
func (s *StaticValidator) ReadFrom(r io.Reader) error {
|
|
tmp := &cborStaticValidator{}
|
|
if err := cbor.Unmarshal(&tmp, r); err != nil {
|
|
return err
|
|
}
|
|
s.withdrawalCredentials = tmp.WithdrawalCredentials
|
|
s.slashed = tmp.Slashed
|
|
s.activationEligibility = tmp.ActivationEligibility
|
|
s.activationEpoch = tmp.ActivationEpoch
|
|
s.exitEpoch = tmp.ExitEpoch
|
|
s.withdrawableEpoch = tmp.WithdrawableEpoch
|
|
s.publicKeys = tmp.PublicKeys
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidator) AddSlashed(slot uint64, slashed bool) {
|
|
s.slashed = append(s.slashed, staticValidatorField[bool]{slot, slashed})
|
|
}
|
|
|
|
func (s *StaticValidator) AddActivationEligibility(slot uint64, activationEligibility uint64) {
|
|
s.activationEligibility = append(s.activationEligibility, staticValidatorField[uint64]{slot, activationEligibility})
|
|
}
|
|
|
|
func (s *StaticValidator) AddActivationEpoch(slot uint64, activationEpoch uint64) {
|
|
s.activationEpoch = append(s.activationEpoch, staticValidatorField[uint64]{slot, activationEpoch})
|
|
}
|
|
|
|
func (s *StaticValidator) AddExitEpoch(slot uint64, exitEpoch uint64) {
|
|
s.exitEpoch = append(s.exitEpoch, staticValidatorField[uint64]{slot, exitEpoch})
|
|
}
|
|
|
|
func (s *StaticValidator) AddWithdrawableEpoch(slot uint64, withdrawableEpoch uint64) {
|
|
s.withdrawableEpoch = append(s.withdrawableEpoch, staticValidatorField[uint64]{slot, withdrawableEpoch})
|
|
}
|
|
|
|
func (s *StaticValidator) WithdrawalCredentials(slot uint64) libcommon.Hash {
|
|
currIndex := 0
|
|
for i, v := range s.withdrawalCredentials {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.withdrawalCredentials[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) Slashed(slot uint64) bool {
|
|
currIndex := 0
|
|
for i, v := range s.slashed {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.slashed[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) ActivationEligibilityEpoch(slot uint64) uint64 {
|
|
currIndex := 0
|
|
for i, v := range s.activationEligibility {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.activationEligibility[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) ActivationEpoch(slot uint64) uint64 {
|
|
currIndex := 0
|
|
for i, v := range s.activationEpoch {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.activationEpoch[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) ExitEpoch(slot uint64) uint64 {
|
|
currIndex := 0
|
|
for i, v := range s.exitEpoch {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.exitEpoch[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) WithdrawableEpoch(slot uint64) uint64 {
|
|
currIndex := 0
|
|
for i, v := range s.withdrawableEpoch {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.withdrawableEpoch[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) PublicKey(slot uint64) libcommon.Bytes48 {
|
|
currIndex := 0
|
|
for i, v := range s.publicKeys {
|
|
if v.Slot > slot {
|
|
break
|
|
}
|
|
currIndex = i
|
|
}
|
|
return s.publicKeys[currIndex].Field
|
|
}
|
|
|
|
func (s *StaticValidator) ToValidator(v solid.Validator, slot uint64) {
|
|
v.SetPublicKey(s.PublicKey(slot))
|
|
v.SetWithdrawalCredentials(s.WithdrawalCredentials(slot))
|
|
v.SetSlashed(s.Slashed(slot))
|
|
v.SetActivationEligibilityEpoch(s.ActivationEligibilityEpoch(slot))
|
|
v.SetActivationEpoch(s.ActivationEpoch(slot))
|
|
v.SetExitEpoch(s.ExitEpoch(slot))
|
|
v.SetWithdrawableEpoch(s.WithdrawableEpoch(slot))
|
|
}
|
|
|
|
type staticValidatorField[V any] struct {
|
|
Slot uint64
|
|
Field V
|
|
}
|
|
|
|
// StaticValidatorTable is a structure to manage a collection of StaticValidators.
|
|
// It is used for tracking multiple validators and their state changes.
|
|
type StaticValidatorTable struct {
|
|
validatorTable []*StaticValidator
|
|
slot uint64
|
|
sync sync.RWMutex // Mutex for safe concurrent access.
|
|
}
|
|
|
|
// NewStaticValidatorTable creates a new instance of StaticValidatorTable.
|
|
func NewStaticValidatorTable() *StaticValidatorTable {
|
|
return &StaticValidatorTable{
|
|
validatorTable: make([]*StaticValidator, 0, 2400), // Preallocating memory for efficiency.
|
|
}
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddValidator(v solid.Validator, validatorIndex, slot uint64) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
s.validatorTable = append(s.validatorTable, NewStaticValidatorFromValidator(v, slot))
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddWithdrawalCredentials(validatorIndex, slot uint64, withdrawalCredentials libcommon.Hash) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddWithdrawalCredentials(slot, withdrawalCredentials)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddSlashed(validatorIndex, slot uint64, slashed bool) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddSlashed(slot, slashed)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddActivationEligibility(validatorIndex, slot uint64, activationEligibility uint64) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddActivationEligibility(slot, activationEligibility)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddActivationEpoch(validatorIndex, slot uint64, activationEpoch uint64) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddActivationEpoch(slot, activationEpoch)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddExitEpoch(validatorIndex, slot uint64, exitEpoch uint64) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddExitEpoch(slot, exitEpoch)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) AddWithdrawableEpoch(validatorIndex, slot uint64, withdrawableEpoch uint64) error {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return nil
|
|
}
|
|
if validatorIndex >= uint64(len(s.validatorTable)) {
|
|
return fmt.Errorf("validator index mismatch")
|
|
}
|
|
s.validatorTable[validatorIndex].AddWithdrawableEpoch(slot, withdrawableEpoch)
|
|
return nil
|
|
}
|
|
|
|
func (s *StaticValidatorTable) GetInPlace(validatorIndex uint64, slot uint64, v solid.Validator) {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
s.validatorTable[validatorIndex].ToValidator(v, slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) ForEach(fn func(validatorIndex uint64, validator *StaticValidator) bool) {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
for i, v := range s.validatorTable {
|
|
if !fn(uint64(i), v) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *StaticValidatorTable) WithdrawalCredentials(validatorIndex uint64, slot uint64) libcommon.Hash {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].WithdrawalCredentials(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) Slashed(validatorIndex uint64, slot uint64) bool {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].Slashed(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) ActivationEligibilityEpoch(validatorIndex uint64, slot uint64) uint64 {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].ActivationEligibilityEpoch(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) ActivationEpoch(validatorIndex uint64, slot uint64) uint64 {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].ActivationEpoch(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) ExitEpoch(validatorIndex uint64, slot uint64) uint64 {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].ExitEpoch(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) WithdrawableEpoch(validatorIndex uint64, slot uint64) uint64 {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex].WithdrawableEpoch(slot)
|
|
}
|
|
|
|
func (s *StaticValidatorTable) GetStaticValidator(validatorIndex uint64) *StaticValidator {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.validatorTable[validatorIndex]
|
|
}
|
|
|
|
// This is for versioning
|
|
func (s *StaticValidatorTable) SetSlot(slot uint64) {
|
|
s.sync.Lock()
|
|
defer s.sync.Unlock()
|
|
if slot <= s.slot && s.slot != 0 {
|
|
return
|
|
}
|
|
s.slot = slot
|
|
}
|
|
|
|
func (s *StaticValidatorTable) Slot() uint64 {
|
|
s.sync.RLock()
|
|
defer s.sync.RUnlock()
|
|
return s.slot
|
|
}
|