Skip to content
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
8 changes: 2 additions & 6 deletions rocketpool/node/defend-challenge-exit.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,12 @@ func (t *defendChallengeExit) run(state *state.NetworkStateIndex) error {
}

// Iterate over megapool validators checking whether they were incorrectly challenged
validatorCount, err := mp.GetValidatorCount(nil)
if err != nil {
return err
}
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts, false)
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, megapoolAddress, opts, false)
if err != nil {
return err
}

for i := uint32(0); i < uint32(validatorCount); i++ {
for i := uint32(0); i < uint32(len(validatorInfo)); i++ {
exiting := false
if validatorInfo[i].Locked {
if validatorInfo[i].BeaconStatus.WithdrawableEpoch != FarFutureEpoch {
Expand Down
8 changes: 2 additions & 6 deletions rocketpool/node/stake-megapool-validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,15 @@ func (t *stakeMegapoolValidator) run(state *state.NetworkStateIndex) error {
}

// Iterate over megapool validators checking whether they're ready to stake
validatorCount, err := mp.GetValidatorCount(nil)
if err != nil {
return err
}
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts, false)
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, megapoolAddress, opts, false)
if err != nil {
return err
}

// store validators that need to be staked
validatorsToStake := make(map[uint32]types.ValidatorPubkey)

for i := uint32(0); i < uint32(validatorCount); i++ {
for i := uint32(0); i < uint32(len(validatorInfo)); i++ {
if validatorInfo[i].InPrestake && validatorInfo[i].BeaconStatus.Index != "" {
validatorsToStake[validatorInfo[i].ValidatorId] = types.ValidatorPubkey(validatorInfo[i].PubKey)
}
Expand Down
133 changes: 70 additions & 63 deletions shared/services/megapools.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"net/http"
"strconv"
"strings"
"sync"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
Expand All @@ -30,6 +29,8 @@ import (
"github.com/rocket-pool/smartnode/bindings/storage"
"github.com/rocket-pool/smartnode/bindings/tokens"
"github.com/rocket-pool/smartnode/bindings/types"
"github.com/rocket-pool/smartnode/bindings/utils/multicall"
rpstate "github.com/rocket-pool/smartnode/bindings/utils/state"
"github.com/rocket-pool/smartnode/shared/services/beacon"
"github.com/rocket-pool/smartnode/shared/services/wallet"
"github.com/rocket-pool/smartnode/shared/types/api"
Expand Down Expand Up @@ -402,7 +403,7 @@ func GetNodeMegapoolDetails(rp *rocketpool.RocketPool, bc beacon.Client, nodeAcc
return details, err
}

details.Validators, err = GetMegapoolValidatorDetails(rp, bc, mega, megapoolAddress, uint32(details.ValidatorCount), opts, useFinalizedBeaconState)
details.Validators, err = GetMegapoolValidatorDetails(rp, bc, megapoolAddress, opts, useFinalizedBeaconState)
if err != nil {
return details, err
}
Expand Down Expand Up @@ -488,20 +489,17 @@ func CalculateRewards(rp *rocketpool.RocketPool, amount *big.Int, nodeAccount co

}

func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp megapool.Megapool, megapoolAddress common.Address, validatorCount uint32, opts *bind.CallOpts, useFinalizedBeaconState bool) ([]api.MegapoolValidatorDetails, error) {
func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, megapoolAddress common.Address, opts *bind.CallOpts, useFinalizedBeaconState bool) ([]api.MegapoolValidatorDetails, error) {

details := []api.MegapoolValidatorDetails{}

var wg errgroup.Group
var lock sync.Mutex
var currentEpoch uint64

queueDetails, err := GetMegapoolQueueDetails(rp)
if err != nil {
return details, fmt.Errorf("Error getting the megapool queue details: %w", err)
}

// Beacon view: head by default, or the finalized epoch when the caller requested the finalized state
var currentEpoch uint64
var statusOpts *beacon.ValidatorStatusOptions
head, err := bc.GetBeaconHead()
if useFinalizedBeaconState {
Expand All @@ -514,68 +512,77 @@ func GetMegapoolValidatorDetails(rp *rocketpool.RocketPool, bc beacon.Client, mp
currentEpoch = head.Epoch
}

for i := uint32(0); i < validatorCount; i++ {
i := i
wg.Go(func() error {
validatorDetails, err := mp.GetValidatorInfoAndPubkey(i, opts)
if err != nil {
return fmt.Errorf("Error retrieving validator %d details: %v\n", i, err)
}
validator := api.MegapoolValidatorDetails{
ValidatorId: i,
PubKey: types.BytesToValidatorPubkey(validatorDetails.Pubkey),
LastAssignmentTime: time.Unix(int64(validatorDetails.LastAssignmentTime), 0),
LastRequestedValue: validatorDetails.LastRequestedValue,
LastRequestedBond: validatorDetails.LastRequestedBond,
DepositValue: validatorDetails.DepositValue,
Staked: validatorDetails.Staked,
Exited: validatorDetails.Exited,
InQueue: validatorDetails.InQueue,
InPrestake: validatorDetails.InPrestake,
ExpressUsed: validatorDetails.ExpressUsed,
Dissolved: validatorDetails.Dissolved,
Exiting: validatorDetails.Exiting,
Locked: validatorDetails.Locked,
ExitBalance: validatorDetails.ExitBalance,
}
multicallerAddress := common.HexToAddress(cfg.Smartnode.GetMulticallAddress())
mc, err := multicall.NewMultiCaller(rp.Client, multicallerAddress)
if err != nil {
return details, fmt.Errorf("Error creating multicaller: %w", err)
}
contracts := &rpstate.NetworkContracts{Multicaller: mc}
if opts != nil {
contracts.ElBlockNumber = opts.BlockNumber
}
validatorInfos, err := rpstate.GetNodeMegapoolValidators(rp, contracts, megapoolAddress)
if err != nil {
return details, fmt.Errorf("Error retrieving megapool validators: %w", err)
}

// Try to fetch the validator status. If it fails, we assume the first deposit was not processed yet
validator.BeaconStatus, _ = bc.GetValidatorStatus(validator.PubKey, statusOpts)
if validator.Staked {
if currentEpoch > validator.BeaconStatus.ActivationEpoch {
validator.Activated = true
validatorIndex, err := strconv.ParseUint(validator.BeaconStatus.Index, 10, 64)
if err != nil {
return fmt.Errorf("Error parsing the validator index")
}
validator.ValidatorIndex = validatorIndex
validator.WithdrawableEpoch = validator.BeaconStatus.WithdrawableEpoch
}
}
pubkeys := make([]types.ValidatorPubkey, len(validatorInfos))
for i, vi := range validatorInfos {
pubkeys[i] = types.BytesToValidatorPubkey(vi.Pubkey)
}
beaconStatuses, err := bc.GetValidatorStatuses(pubkeys, statusOpts)
if err != nil {
return details, fmt.Errorf("Error retrieving validator beacon statuses: %w", err)
}

for i, vi := range validatorInfos {
pubkey := pubkeys[i]
validator := api.MegapoolValidatorDetails{
ValidatorId: vi.ValidatorId,
PubKey: pubkey,
LastAssignmentTime: time.Unix(int64(vi.ValidatorInfo.LastAssignmentTime), 0),
LastRequestedValue: vi.ValidatorInfo.LastRequestedValue,
LastRequestedBond: vi.ValidatorInfo.LastRequestedBond,
DepositValue: vi.ValidatorInfo.DepositValue,
Staked: vi.ValidatorInfo.Staked,
Exited: vi.ValidatorInfo.Exited,
InQueue: vi.ValidatorInfo.InQueue,
InPrestake: vi.ValidatorInfo.InPrestake,
ExpressUsed: vi.ValidatorInfo.ExpressUsed,
Dissolved: vi.ValidatorInfo.Dissolved,
Exiting: vi.ValidatorInfo.Exiting,
Locked: vi.ValidatorInfo.Locked,
ExitBalance: vi.ValidatorInfo.ExitBalance,
}

// Compute the queue position
if validator.InQueue {
var queueKey string
if validator.ExpressUsed {
queueKey = "deposit.queue.express"
} else {
queueKey = "deposit.queue.standard"
}
validator.QueuePosition, err = calculatePositionInQueue(rp, queueDetails, megapoolAddress, validator.ValidatorId, queueKey, findInQueue)
validator.BeaconStatus = beaconStatuses[pubkey]
if validator.Staked {
if currentEpoch > validator.BeaconStatus.ActivationEpoch {
validator.Activated = true
validatorIndex, err := strconv.ParseUint(validator.BeaconStatus.Index, 10, 64)
if err != nil {
return fmt.Errorf("error getting queue position for validator ID %d: %w", validator.ValidatorId, err)
return details, fmt.Errorf("Error parsing the validator index")
}
validator.ValidatorIndex = validatorIndex
validator.WithdrawableEpoch = validator.BeaconStatus.WithdrawableEpoch
}
lock.Lock()
details = append(details, validator)
lock.Unlock()
return nil
})
}
}

// Wait for data
if err := wg.Wait(); err != nil {
return details, err
// Compute the queue position
if validator.InQueue {
var queueKey string
if validator.ExpressUsed {
queueKey = "deposit.queue.express"
} else {
queueKey = "deposit.queue.standard"
}
validator.QueuePosition, err = calculatePositionInQueue(rp, queueDetails, megapoolAddress, validator.ValidatorId, queueKey, findInQueue)
if err != nil {
return details, fmt.Errorf("error getting queue position for validator ID %d: %w", validator.ValidatorId, err)
}
}

details = append(details, validator)
}

return details, nil
Expand Down
Loading