Skip to content

Commit 8e4fcf0

Browse files
committed
Optimize state loading
1 parent 221c51a commit 8e4fcf0

3 files changed

Lines changed: 100 additions & 95 deletions

File tree

‎rocketpool/node/notify-final-balance.go‎

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"github.com/ethereum/go-ethereum/accounts/abi/bind"
1010
"github.com/rocket-pool/smartnode/bindings/megapool"
1111
"github.com/rocket-pool/smartnode/bindings/rocketpool"
12-
"github.com/rocket-pool/smartnode/bindings/types"
1312
"github.com/rocket-pool/smartnode/bindings/utils/eth"
1413
"github.com/urfave/cli"
1514

@@ -19,8 +18,6 @@ import (
1918
rpgas "github.com/rocket-pool/smartnode/shared/services/gas"
2019
"github.com/rocket-pool/smartnode/shared/services/state"
2120
"github.com/rocket-pool/smartnode/shared/services/wallet"
22-
apitypes "github.com/rocket-pool/smartnode/shared/types/api"
23-
"github.com/rocket-pool/smartnode/shared/types/eth2"
2421
"github.com/rocket-pool/smartnode/shared/utils/api"
2522
"github.com/rocket-pool/smartnode/shared/utils/log"
2623
)
@@ -119,58 +116,56 @@ func (t *notifyFinalBalance) run(state *state.NetworkState) error {
119116
return err
120117
}
121118

122-
// Check if the megapool is deployed
123-
deployed, err := megapool.GetMegapoolDeployed(t.rp, nodeAccount.Address, opts)
124-
if err != nil {
125-
return err
119+
nodeDetails, exists := state.NodeDetailsByAddress[nodeAccount.Address]
120+
if !exists {
121+
return fmt.Errorf("node account %s not found in state", nodeAccount.Address.Hex())
126122
}
127-
if !deployed {
123+
124+
if !nodeDetails.MegapoolDeployed {
128125
return nil
129126
}
130127

131-
// Get the megapool address
132-
megapoolAddress, err := megapool.GetMegapoolExpectedAddress(t.rp, nodeAccount.Address, opts)
133-
if err != nil {
134-
return err
135-
}
128+
megapoolAddress := nodeDetails.MegapoolAddress
136129

137-
// Load the megapool
138130
mp, err := megapool.NewMegaPoolV1(t.rp, megapoolAddress, nil)
139131
if err != nil {
140132
return err
141133
}
142134

143-
// Iterate over megapool validators checking whether they're ready to submit a final balance proof
144-
validatorCount, err := mp.GetValidatorCount(nil)
145-
if err != nil {
146-
return err
147-
}
148-
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts)
149-
if err != nil {
150-
return err
135+
validatorDetailsToProve := make(map[uint32]beacon.ValidatorStatus)
136+
pubkeys := state.MegapoolToPubkeysMap[megapoolAddress]
137+
for _, pubkey := range pubkeys {
138+
validatorDetails, exists := state.MegapoolValidatorDetails[pubkey]
139+
if !exists {
140+
return fmt.Errorf("validator %s not found in state", pubkey.Hex())
141+
}
142+
143+
validatorInfo := state.MegapoolValidatorInfo[pubkey]
144+
145+
if validatorDetails.Status == beacon.ValidatorState_WithdrawalDone && validatorInfo.ValidatorInfo.Exiting && !validatorInfo.ValidatorInfo.Exited && validatorDetails.EffectiveBalance == 0 {
146+
validatorDetailsToProve[validatorInfo.ValidatorId] = validatorDetails
147+
}
151148
}
152149

153-
// Get the beacon state
154-
beaconState, err := services.GetBeaconState(t.bc)
155-
if err != nil {
156-
return err
150+
// Check if there are any validators to notify
151+
if len(validatorDetailsToProve) == 0 {
152+
return nil
157153
}
158154

159-
for i := uint32(0); i < uint32(validatorCount); i++ {
160-
if validatorInfo[i].BeaconStatus.Status == "withdrawal_done" && validatorInfo[i].Exiting && !validatorInfo[i].Exited && validatorInfo[i].BeaconStatus.EffectiveBalance == 0 {
161-
// Log
162-
t.log.Printlnf("The validator ID %d needs a final balance proof", validatorInfo[i].ValidatorId)
155+
// Notify the validators
156+
for validatorId, validatorDetails := range validatorDetailsToProve {
157+
// Log
158+
t.log.Printlnf("The validator id %d needs a final balance proof", validatorId)
163159

164-
t.createFinalBalanceProof(t.rp, mp, validatorInfo[i], state, types.ValidatorPubkey(validatorInfo[i].PubKey), beaconState, opts)
165-
}
160+
t.createFinalBalanceProof(t.rp, mp, state, validatorId, validatorDetails, opts)
166161
}
167162

168163
// Return
169164
return nil
170165

171166
}
172167

173-
func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool, mp megapool.Megapool, validatorInfo apitypes.MegapoolValidatorDetails, state *state.NetworkState, validatorPubkey types.ValidatorPubkey, beaconState eth2.BeaconState, callopts *bind.CallOpts) error {
168+
func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool, mp megapool.Megapool, state *state.NetworkState, validatorId uint32, validatorDetails beacon.ValidatorStatus, callopts *bind.CallOpts) error {
174169

175170
// Get transactor
176171
opts, err := t.w.GetNodeAccountTransactor()
@@ -180,7 +175,7 @@ func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool,
180175

181176
t.log.Printlnf("Crafting a final balance proof. This process can take several seconds and is CPU and memory intensive. If you don't see a [FINISHED] log entry your system may not have enough resources to perform this operation.")
182177

183-
validatorIndexStr, err := t.bc.GetValidatorIndex(validatorPubkey)
178+
validatorIndexStr, err := t.bc.GetValidatorIndex(validatorDetails.Pubkey)
184179
if err != nil {
185180
return err
186181
}
@@ -190,15 +185,15 @@ func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool,
190185
return err
191186
}
192187

193-
slot := validatorInfo.WithdrawableEpoch * 32
188+
slot := validatorDetails.WithdrawableEpoch * 32
194189

195190
withdrawalProof, proofSlot, stateUsed, err := services.GetWithdrawalProofForSlot(t.c, slot, validatorIndex)
196191
if err != nil {
197-
return fmt.Errorf("error getting withdrawal proof for validator 0x%s (index: %d): %w", validatorPubkey.String(), validatorIndex, err)
192+
return fmt.Errorf("error getting withdrawal proof for validator 0x%s (index: %d): %w", validatorDetails.Pubkey.String(), validatorIndex, err)
198193
}
199-
t.log.Printlnf("The Beacon WithdrawalSlot for validator ID %d is: %d", validatorInfo.ValidatorId, withdrawalProof.WithdrawalSlot)
194+
t.log.Printlnf("The Beacon WithdrawalSlot for validator index %d is: %d", validatorDetails.Index, withdrawalProof.WithdrawalSlot)
200195

201-
validatorProof, slotTimestamp, slotProof, err := services.GetValidatorProof(t.c, proofSlot, t.w, state.BeaconConfig, mp.GetAddress(), validatorPubkey, stateUsed)
196+
validatorProof, slotTimestamp, slotProof, err := services.GetValidatorProof(t.c, proofSlot, t.w, state.BeaconConfig, mp.GetAddress(), validatorDetails.Pubkey, stateUsed)
202197
if err != nil {
203198
t.log.Printlnf("There was an error during the proof creation process: %w", err)
204199
return err
@@ -221,9 +216,9 @@ func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool,
221216
t.log.Printlnf("The validator final balance proof has been successfully created.")
222217

223218
// Get the gas limit
224-
gasInfo, err := megapool.EstimateNotifyFinalBalance(rp, mp.GetAddress(), validatorInfo.ValidatorId, slotTimestamp, finalBalanceProof, validatorProof, slotProof, opts)
219+
gasInfo, err := megapool.EstimateNotifyFinalBalance(rp, mp.GetAddress(), validatorId, slotTimestamp, finalBalanceProof, validatorProof, slotProof, opts)
225220
if err != nil {
226-
t.log.Printlnf("Could not estimate the gas required to notify final balance on megapool validator %d: %w", validatorInfo.ValidatorId, err)
221+
t.log.Printlnf("Could not estimate the gas required to notify final balance on megapool validator %d: %w", validatorId, err)
227222
return err
228223
}
229224
gas := big.NewInt(int64(gasInfo.SafeGasLimit))
@@ -246,7 +241,7 @@ func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool,
246241
opts.GasLimit = gas.Uint64()
247242

248243
// Call Notify Final Balance
249-
tx, err := megapool.NotifyFinalBalance(rp, mp.GetAddress(), validatorInfo.ValidatorId, slotTimestamp, finalBalanceProof, validatorProof, slotProof, opts)
244+
tx, err := megapool.NotifyFinalBalance(rp, mp.GetAddress(), validatorId, slotTimestamp, finalBalanceProof, validatorProof, slotProof, opts)
250245
if err != nil {
251246
return err
252247
}
@@ -258,7 +253,7 @@ func (t *notifyFinalBalance) createFinalBalanceProof(rp *rocketpool.RocketPool,
258253
}
259254

260255
// Log
261-
t.log.Printlnf("Successfully notified validator %d final balance.", validatorInfo.ValidatorId)
256+
t.log.Printlnf("Successfully notified validator %d final balance.", validatorId)
262257

263258
// Return
264259
return nil

‎rocketpool/node/notify-validator-exit.go‎

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package node
22

33
import (
4+
"fmt"
45
"math/big"
56

67
"github.com/docker/docker/client"
@@ -118,55 +119,63 @@ func (t *notifyValidatorExit) run(state *state.NetworkState) error {
118119
return err
119120
}
120121

121-
// Check if the megapool is deployed
122-
deployed, err := megapool.GetMegapoolDeployed(t.rp, nodeAccount.Address, opts)
123-
if err != nil {
124-
return err
122+
nodeDetails, exists := state.NodeDetailsByAddress[nodeAccount.Address]
123+
if !exists {
124+
return fmt.Errorf("node account %s not found in state", nodeAccount.Address.Hex())
125125
}
126-
if !deployed {
126+
127+
if !nodeDetails.MegapoolDeployed {
127128
return nil
128129
}
129130

130-
// Get the megapool address
131-
megapoolAddress, err := megapool.GetMegapoolExpectedAddress(t.rp, nodeAccount.Address, opts)
132-
if err != nil {
133-
return err
134-
}
131+
megapoolAddress := nodeDetails.MegapoolAddress
135132

136-
// Load the megapool
137133
mp, err := megapool.NewMegaPoolV1(t.rp, megapoolAddress, nil)
138134
if err != nil {
139135
return err
140136
}
141137

142-
// Iterate over megapool validators checking whether they're ready to notify exit
143-
validatorCount, err := mp.GetValidatorCount(opts)
138+
var currentEpoch uint64
139+
140+
head, err := t.bc.GetBeaconHead()
144141
if err != nil {
145142
return err
146143
}
147-
validatorInfo, err := services.GetMegapoolValidatorDetails(t.rp, t.bc, mp, megapoolAddress, uint32(validatorCount), opts)
144+
currentEpoch = head.Epoch
145+
146+
validatorDetailsToProve := make(map[uint32]beacon.ValidatorStatus)
147+
pubkeys := state.MegapoolToPubkeysMap[megapoolAddress]
148+
for _, pubkey := range pubkeys {
149+
validatorDetails, exists := state.MegapoolValidatorDetails[pubkey]
150+
if !exists {
151+
return fmt.Errorf("validator %s not found in state", pubkey.Hex())
152+
}
153+
154+
validatorInfo := state.MegapoolValidatorInfo[pubkey]
155+
156+
if currentEpoch > validatorDetails.ActivationEpoch && validatorDetails.WithdrawableEpoch < FarFutureEpoch && validatorInfo.ValidatorInfo.Staked && !validatorInfo.ValidatorInfo.Exited && !validatorInfo.ValidatorInfo.Exiting {
157+
validatorDetailsToProve[validatorInfo.ValidatorId] = validatorDetails
158+
}
159+
}
160+
161+
// Check if there are any validators to notify
162+
if len(validatorDetailsToProve) == 0 {
163+
return nil
164+
}
165+
166+
beaconState, err := services.GetBeaconState(t.bc)
148167
if err != nil {
149168
return err
150169
}
151170

152-
for i := uint32(0); i < uint32(validatorCount); i++ {
153-
if validatorInfo[i].Activated && validatorInfo[i].WithdrawableEpoch < FarFutureEpoch && validatorInfo[i].Staked && !validatorInfo[i].Exited && !validatorInfo[i].Exiting {
154-
beaconState, err := services.GetBeaconState(t.bc)
155-
if err != nil {
156-
return err
157-
}
158-
159-
if beaconState.GetValidators()[validatorInfo[i].ValidatorIndex].WithdrawableEpoch < FarFutureEpoch {
171+
for validatorId, validatorDetails := range validatorDetailsToProve {
160172

161-
// Log
162-
t.log.Printlnf("The validator ID %d needs an exit proof", validatorInfo[i].ValidatorId)
173+
// Log
174+
t.log.Printlnf("The validator id %d needs an exit proof", validatorId)
163175

164-
// Call Notify Exit
165-
t.createExitProof(t.rp, beaconState, mp, validatorInfo[i].ValidatorId, state, types.ValidatorPubkey(validatorInfo[i].PubKey), opts)
166-
}
167-
}
176+
// Call Notify Exit
177+
t.createExitProof(t.rp, beaconState, mp, validatorId, state, types.ValidatorPubkey(validatorDetails.Pubkey), opts)
168178
}
169-
170179
// Return
171180
return nil
172181

‎rocketpool/node/stake-megapool-validator.go‎

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package node
22

33
import (
44
"math/big"
5-
"strconv"
65

76
"github.com/docker/docker/client"
87
"github.com/ethereum/go-ethereum/accounts/abi/bind"
@@ -149,38 +148,40 @@ func (t *stakeMegapoolValidator) run(state *state.NetworkState) error {
149148
return err
150149
}
151150

151+
// store validators that need to be staked
152+
validatorsToStake := make(map[uint32]bool)
153+
154+
for i := uint32(0); i < uint32(validatorCount); i++ {
155+
if validatorInfo[i].InPrestake && validatorInfo[i].BeaconStatus.Index != "" {
156+
validatorsToStake[validatorInfo[i].ValidatorId] = true
157+
}
158+
}
159+
160+
// Check if we have any validators to stake
161+
if len(validatorsToStake) == 0 {
162+
return nil
163+
}
164+
165+
// Load the beacon state
152166
beaconState, err := services.GetBeaconState(t.bc)
153167
if err != nil {
154168
return err
155169
}
156-
stakedCount := 0
157-
for i := uint32(0); i < uint32(validatorCount); i++ {
158-
if validatorInfo[i].InPrestake && validatorInfo[i].BeaconStatus.Index != "" {
159-
// Convert str to int
160-
indexInt, err := strconv.Atoi(validatorInfo[i].BeaconStatus.Index)
161-
if err != nil {
162-
return err
163-
}
164-
if indexInt < len(beaconState.GetValidators()) {
165-
// Log
166-
t.log.Printlnf("The validator %d needs to be staked", validatorInfo[i].ValidatorId)
167-
168-
// Call Stake
169-
t.stakeValidator(t.rp, beaconState, mp, validatorInfo[i].ValidatorId, state, types.ValidatorPubkey(validatorInfo[i].PubKey), opts)
170-
stakedCount++
171-
}
172-
}
170+
171+
// Iterate over validators to stake
172+
for validatorId, _ := range validatorsToStake {
173+
// Log
174+
t.log.Printlnf("The validator id %d needs to be staked", validatorId)
175+
176+
// Call Stake
177+
t.stakeValidator(t.rp, beaconState, mp, validatorId, state, types.ValidatorPubkey(validatorInfo[validatorId].PubKey), opts)
173178
}
174179

175-
if stakedCount > 0 {
176-
if err := validator.RestartValidator(t.cfg, t.bc, &t.log, t.d); err != nil {
177-
return err
178-
}
180+
if err := validator.RestartValidator(t.cfg, t.bc, &t.log, t.d); err != nil {
181+
return err
179182
}
180183

181-
// Return
182184
return nil
183-
184185
}
185186

186187
func (t *stakeMegapoolValidator) stakeValidator(rp *rocketpool.RocketPool, beaconState eth2.BeaconState, mp megapool.Megapool, validatorId uint32, state *state.NetworkState, validatorPubkey types.ValidatorPubkey, callopts *bind.CallOpts) error {

0 commit comments

Comments
 (0)