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

V2 auto init vp #633

Merged
merged 5 commits into from
Oct 11, 2024
Merged
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/prysmaticlabs/prysm/v5 v5.0.3
github.com/rivo/tview v0.0.0-20230208211350-7dfff1ce7854 // DO NOT UPGRADE
github.com/rocket-pool/node-manager-core v0.5.0
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20240709170030-c27aeb5fb99b
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20241009181157-ebb8c8b0bf54
github.com/shirou/gopsutil/v3 v3.24.3
github.com/tyler-smith/go-bip39 v1.1.0
github.com/wealdtech/go-ens/v3 v3.6.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,8 @@ github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd h1:p9K
github.com/rocket-pool/go-merkletree v1.0.1-0.20220406020931-c262d9b976dd/go.mod h1:UE9fof8P7iESVtLn1K9CTSkNRYVFHZHlf96RKbU33kA=
github.com/rocket-pool/node-manager-core v0.5.0 h1:98PnHb67mgOKTHMQlRql5KINYM+5NGYV3n4GYChZuec=
github.com/rocket-pool/node-manager-core v0.5.0/go.mod h1:Clii5aca9PvR4HoAlUs8dh2OsJbDDnJ4yL5EaQE1gSo=
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20240709170030-c27aeb5fb99b h1:39UmJzNR71/OMIzblEY9wq+3nojGa/gQOJJpLBa6XcE=
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20240709170030-c27aeb5fb99b/go.mod h1:pcY43H/m5pjr7zacrsKVaXnXfKKi1UV08VDPUwxbJkc=
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20241009181157-ebb8c8b0bf54 h1:869F7HFTkCHUNxAj6WwtapWEL8DiVfy918DviPz57dY=
github.com/rocket-pool/rocketpool-go/v2 v2.0.0-b2.0.20241009181157-ebb8c8b0bf54/go.mod h1:pcY43H/m5pjr7zacrsKVaXnXfKKi1UV08VDPUwxbJkc=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo=
Expand Down
3 changes: 2 additions & 1 deletion rocketpool-daemon/common/rewards/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package rewards

import (
"context"
"errors"
"fmt"
"io"
"math"
Expand Down Expand Up @@ -374,7 +375,7 @@ func DownloadRewardsFile(cfg *config.SmartNodeConfig, i *sharedtypes.IntervalInf
errBuilder.WriteString(fmt.Sprintf("Downloading files with timeout %v failed.\n", timeout))
}

return fmt.Errorf(errBuilder.String())
return errors.New(errBuilder.String())
}

// Gets the start slot for the given interval
Expand Down
155 changes: 155 additions & 0 deletions rocketpool-daemon/node/auto-init-voting-power.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package node

import (
"context"
"fmt"
"log/slog"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/rocket-pool/node-manager-core/beacon"
"github.com/rocket-pool/node-manager-core/eth"
"github.com/rocket-pool/node-manager-core/log"
"github.com/rocket-pool/node-manager-core/node/wallet"
"github.com/rocket-pool/rocketpool-go/v2/node"
"github.com/rocket-pool/rocketpool-go/v2/rocketpool"
"github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/gas"
"github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/services"
"github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/state"
"github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/tx"
"github.com/rocket-pool/smartnode/v2/shared/config"
"github.com/rocket-pool/smartnode/v2/shared/keys"
)

type AutoInitVotingPower struct {
ctx context.Context
sp *services.ServiceProvider
logger *slog.Logger
cfg *config.SmartNodeConfig
w *wallet.Wallet
rp *rocketpool.RocketPool
bc beacon.IBeaconClient
gasThreshold float64
maxFee *big.Int
maxPriorityFee *big.Int
nodeAddress common.Address
}

// Auto Initialize Vote Power
func NewAutoInitVotingPower(ctx context.Context, sp *services.ServiceProvider, logger *log.Logger) *AutoInitVotingPower {
cfg := sp.GetConfig()
log := logger.With(slog.String(keys.TaskKey, "Auto Initialize Vote Power"))
maxFee, maxPriorityFee := getAutoTxInfo(cfg, log)
return &AutoInitVotingPower{
ctx: ctx,
sp: sp,
logger: log,
cfg: cfg,
w: sp.GetWallet(),
rp: sp.GetRocketPool(),
bc: sp.GetBeaconClient(),
gasThreshold: cfg.AutoInitVPThreshold.Value,
maxFee: maxFee,
maxPriorityFee: maxPriorityFee,
}
}

func (t *AutoInitVotingPower) Run(state *state.NetworkState) error {
// Log
t.logger.Info("Checking for node initialized voting power...")

// Create Node Binding
t.nodeAddress, _ = t.w.GetAddress()
node, err := node.NewNode(t.rp, t.nodeAddress)
if err != nil {
return fmt.Errorf("error creating node binding for node %s: %w", t.nodeAddress.Hex(), err)
}

// Check if voting is initialized
err = t.rp.Query(nil, nil, node.IsVotingInitialized)
if err != nil {
return fmt.Errorf("error checking if voting is initialized for node %s: %w", t.nodeAddress.Hex(), err)
}
votingInitialized := node.IsVotingInitialized.Get()

// Create the tx and submit if voting isn't initialized
if !votingInitialized {
txSubmission, err := t.createInitializeVotingTx()
if err != nil {
return fmt.Errorf("error preparing submission to initialize voting for node %s: %w", t.nodeAddress.Hex(), err)
}
err = t.initializeVotingPower(txSubmission)
if err != nil {
return fmt.Errorf("error initializing voting power for node %s: %w", t.nodeAddress.Hex(), err)
}
return nil
}

return nil
}

func (t *AutoInitVotingPower) createInitializeVotingTx() (*eth.TransactionSubmission, error) {
// Get transactor
opts, err := t.w.GetTransactor()
if err != nil {
return nil, err
}

// Bindings
node, err := node.NewNode(t.rp, t.nodeAddress)
if err != nil {
return nil, fmt.Errorf("error creating node %s binding: %w", t.nodeAddress.Hex(), err)
}
// Get the tx info
txInfo, err := node.InitializeVoting(opts)
if err != nil {
return nil, fmt.Errorf("error estimating the gas required to initialize voting for node %s: %w", t.nodeAddress.Hex(), err)
}
if txInfo.SimulationResult.SimulationError != "" {
return nil, fmt.Errorf("simulating initialize voting tx for node %s failed: %s", t.nodeAddress.Hex(), txInfo.SimulationResult.SimulationError)
}

submission, err := eth.CreateTxSubmissionFromInfo(txInfo, nil)
if err != nil {
return nil, fmt.Errorf("error creating submission to initialize voting for node %s: %w", t.nodeAddress.Hex(), err)
}
return submission, nil
}

func (t *AutoInitVotingPower) initializeVotingPower(submission *eth.TransactionSubmission) error {
// Get transactor
opts, err := t.w.GetTransactor()
if err != nil {
return err
}

// Get the max fee
maxFee := t.maxFee
if maxFee == nil || maxFee.Uint64() == 0 {
maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger)
if err != nil {
return err
}
}

// Lower the priority fee when the suggested maxfee is lower than the user requested priority fee
if maxFee.Cmp(t.maxPriorityFee) < 0 {
t.maxPriorityFee = new(big.Int).Div(maxFee, big.NewInt(2))
}

opts.GasFeeCap = maxFee
opts.GasTipCap = t.maxPriorityFee

// Print the gas info
if !gas.PrintAndCheckGasInfo(submission.TxInfo.SimulationResult, true, t.gasThreshold, t.logger, opts.GasFeeCap, 0) {
return nil
}

// Print TX info and wait for them to be included in a block
err = tx.PrintAndWaitForTransaction(t.cfg, t.rp, t.logger, submission.TxInfo, opts)
if err != nil {
return err
}

return nil
}
15 changes: 15 additions & 0 deletions rocketpool-daemon/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type TaskLoop struct {
reduceBonds *ReduceBonds
defendPdaoProps *DefendPdaoProps
verifyPdaoProps *VerifyPdaoProps
autoInitVotingPower *AutoInitVotingPower

// Watchtower metrics
scrubCollector *wc.ScrubCollector
Expand Down Expand Up @@ -127,6 +128,11 @@ func NewTaskLoop(sp *services.ServiceProvider, wg *sync.WaitGroup) *TaskLoop {
t.verifyPdaoProps = NewVerifyPdaoProps(t.ctx, t.sp, t.logger)
}

// Create auto init vp if the threshold is above 0
if t.cfg.AutoInitVPThreshold.Value != 0 {
t.autoInitVotingPower = NewAutoInitVotingPower(t.ctx, t.sp, t.logger)
}

return t
}

Expand Down Expand Up @@ -368,6 +374,15 @@ func (t *TaskLoop) runTasks() bool {
return true
}
}
// Run the auto vote initilization check
if t.autoInitVotingPower != nil {
if err := t.autoInitVotingPower.Run(state); err != nil {
t.logger.Error(err.Error())
}
if utils.SleepWithCancel(t.ctx, taskCooldown) {
return true
}
}

// Run the minipool stake check
if err := t.stakePrelaunchMinipools.Run(state); err != nil {
Expand Down
1 change: 1 addition & 0 deletions shared/config/ids/ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
CheckpointRetentionLimitID string = "checkpointRetentionLimit"
RecordsPathID string = "recordsPath"
VerifyProposalsID string = "verifyProposals"
AutoInitVPThreshold string = "autoInitVPThreshold"

// Subconfig IDs
LoggingID string = "logging"
Expand Down
18 changes: 18 additions & 0 deletions shared/config/smartnode-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type SmartNodeConfig struct {
CheckpointRetentionLimit config.Parameter[uint64]
RecordsPath config.Parameter[string]
VerifyProposals config.Parameter[bool]
AutoInitVPThreshold config.Parameter[float64]

// Logging
Logging *config.LoggerConfig
Expand Down Expand Up @@ -441,6 +442,22 @@ func NewSmartNodeConfig(rpDir string, isNativeMode bool) *SmartNodeConfig {
config.Network_All: false,
},
},

AutoInitVPThreshold: config.Parameter[float64]{
ParameterCommon: &config.ParameterCommon{
ID: ids.AutoInitVPThreshold,
Name: "Auto-Init Vote Power Gas Threshold",
Description: "The Smartnode will regularly check if the node has initialized voting power and attempt to initialize voting power if it isn't initialized.\n\n" +
"This threshold is a limit (in gwei) you can set on this automatic transaction; your node will not attempt to initialize voting power if the network suggested fee is below this limit.\n\n" +
"A value of 0 will disable this task. Disable this if your node was registered post-houston or your vote power is already initialized.\n\n",
AffectsContainers: []config.ContainerID{config.ContainerID_Daemon},
CanBeBlank: false,
OverwriteOnUpgrade: false,
},
Default: map[config.Network]float64{
config.Network_All: float64(5),
},
},
}

// Create the subconfigs
Expand Down Expand Up @@ -477,6 +494,7 @@ func (cfg *SmartNodeConfig) GetParameters() []config.IParameter {
&cfg.Network,
&cfg.ClientMode,
&cfg.VerifyProposals,
&cfg.AutoInitVPThreshold,
&cfg.AutoTxMaxFee,
&cfg.MaxPriorityFee,
&cfg.AutoTxGasThreshold,
Expand Down
Loading