From 73e9d73151e8200eb4c4b32419f285fb7c5879d0 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Sun, 4 Aug 2024 16:30:12 -0700 Subject: [PATCH 01/36] Change rp p iv to let users choose between setting a delegate or not --- client/pdao.go | 11 ++- rocketpool-cli/commands/pdao/commands.go | 2 +- .../commands/pdao/initialize-voting.go | 51 +++++++++- rocketpool-daemon/api/pdao/handler.go | 1 + .../pdao/initialize-voting-with-delegate.go | 97 +++++++++++++++++++ .../api/pdao/initialize-voting.go | 13 +-- 6 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 rocketpool-daemon/api/pdao/initialize-voting-with-delegate.go diff --git a/client/pdao.go b/client/pdao.go index 6e807a898..6b4c3626e 100644 --- a/client/pdao.go +++ b/client/pdao.go @@ -195,12 +195,17 @@ func (r *PDaoRequester) ProposeSetting(contractName rocketpool.ContractName, set return client.SendGetRequest[api.ProtocolDaoProposeSettingData](r, "setting/propose", "ProposeSetting", args) } -// Initialize voting so the node can vote on Protocol DAO proposals -func (r *PDaoRequester) InitializeVoting(delegate common.Address) (*types.ApiResponse[api.ProtocolDaoInitializeVotingData], error) { +// Initialize voting with delegate unlocks the node's voting power and sets the delegate in one transasction +func (r *PDaoRequester) InitializeVotingWithDelegate(delegate common.Address) (*types.ApiResponse[api.ProtocolDaoInitializeVotingData], error) { args := map[string]string{ "delegate": delegate.Hex(), } - return client.SendGetRequest[api.ProtocolDaoInitializeVotingData](r, "initialize-voting", "InitializeVoting", args) + return client.SendGetRequest[api.ProtocolDaoInitializeVotingData](r, "initialize-voting-with-delegate", "InitializeVotingWithDelegate", args) +} + +// Initialize voting so the node can vote on Protocol DAO proposals +func (r *PDaoRequester) InitializeVoting() (*types.ApiResponse[api.ProtocolDaoInitializeVotingData], error) { + return client.SendGetRequest[api.ProtocolDaoInitializeVotingData](r, "initialize-voting", "InitializeVoting", nil) } // Set the delegate for voting on Protocol DAO proposals diff --git a/rocketpool-cli/commands/pdao/commands.go b/rocketpool-cli/commands/pdao/commands.go index 0d66caa55..bd240503a 100644 --- a/rocketpool-cli/commands/pdao/commands.go +++ b/rocketpool-cli/commands/pdao/commands.go @@ -160,7 +160,7 @@ func RegisterCommands(app *cli.App, name string, aliases []string) { Usage: "Unlocks a node operator's voting power (only required for node operators who registered before governance structure was in place)", Action: func(c *cli.Context) error { // Run - return initializeVoting(c) + return initializeVotingPrompt(c) }, }, diff --git a/rocketpool-cli/commands/pdao/initialize-voting.go b/rocketpool-cli/commands/pdao/initialize-voting.go index 32ec1b3fe..fb6a72bba 100644 --- a/rocketpool-cli/commands/pdao/initialize-voting.go +++ b/rocketpool-cli/commands/pdao/initialize-voting.go @@ -10,6 +10,13 @@ import ( "github.com/urfave/cli/v2" ) +func initializeVotingPrompt(c *cli.Context) error { + if utils.Confirm(fmt.Sprintf("Would you like to specify a delegate that can vote on your behalf on Protocol DAO proposals?")) { + return initializeVotingWithDelegate(c) + } + return initializeVoting(c) +} + func initializeVoting(c *cli.Context) error { // Get RP client rp, err := client.NewClientFromCtx(c) @@ -17,6 +24,44 @@ func initializeVoting(c *cli.Context) error { return err } + // Get the TX + response, err := rp.Api.PDao.InitializeVoting() + if err != nil { + return err + } + + // Verify + if response.Data.VotingInitialized { + fmt.Println("Voting has already been initialized for your node.") + return nil + } + + // Run the TX + validated, err := tx.HandleTx(c, rp, response.Data.TxInfo, + "Are you sure you want to initialize voting so you can vote on Protocol DAO proposals?", + "initialize voting", + "Initializing voting...", + ) + if err != nil { + return err + } + if !validated { + return nil + } + + // Log & return + fmt.Printf("Successfully initialized voting. Your node can now vote on Protocol DAO proposals.") + return nil + +} + +func initializeVotingWithDelegate(c *cli.Context) error { + // Get RP client + rp, err := client.NewClientFromCtx(c) + if err != nil { + return err + } + // Get the address delegateAddressString := c.String("address") if delegateAddressString == "" { @@ -28,7 +73,7 @@ func initializeVoting(c *cli.Context) error { } // Get the TX - response, err := rp.Api.PDao.InitializeVoting(delegateAddress) + response, err := rp.Api.PDao.InitializeVotingWithDelegate(delegateAddress) if err != nil { return err } @@ -41,7 +86,7 @@ func initializeVoting(c *cli.Context) error { // Run the TX validated, err := tx.HandleTx(c, rp, response.Data.TxInfo, - "Are you sure you want to initialize voting so you can vote on Protocol DAO proposals?", + "Are you sure you want to initialize voting?", "initialize voting", "Initializing voting...", ) @@ -53,6 +98,6 @@ func initializeVoting(c *cli.Context) error { } // Log & return - fmt.Printf("Successfully initialized voting. Your node can now vote on Protocol DAO proposals.") + fmt.Printf("Successfully initialized voting.") return nil } diff --git a/rocketpool-daemon/api/pdao/handler.go b/rocketpool-daemon/api/pdao/handler.go index c43536c38..dccada70b 100644 --- a/rocketpool-daemon/api/pdao/handler.go +++ b/rocketpool-daemon/api/pdao/handler.go @@ -44,6 +44,7 @@ func NewProtocolDaoHandler(logger *log.Logger, ctx context.Context, serviceProvi &protocolDaoSettingsContextFactory{h}, &protocolDaoProposeSettingContextFactory{h}, &protocolDaoInitializeVotingContextFactory{h}, + &protocolDaoInitializeVotingWithDelegateContextFactory{h}, &protocolDaoSetVotingDelegateContextFactory{h}, &protocolDaoCurrentVotingDelegateContextFactory{h}, &protocolDaoGetStatusContextFactory{h}, diff --git a/rocketpool-daemon/api/pdao/initialize-voting-with-delegate.go b/rocketpool-daemon/api/pdao/initialize-voting-with-delegate.go new file mode 100644 index 000000000..2922763dd --- /dev/null +++ b/rocketpool-daemon/api/pdao/initialize-voting-with-delegate.go @@ -0,0 +1,97 @@ +package pdao + +import ( + "errors" + "fmt" + "net/url" + _ "time/tzdata" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/gorilla/mux" + batch "github.com/rocket-pool/batch-query" + "github.com/rocket-pool/rocketpool-go/v2/node" + "github.com/rocket-pool/rocketpool-go/v2/rocketpool" + + "github.com/rocket-pool/node-manager-core/api/server" + "github.com/rocket-pool/node-manager-core/api/types" + "github.com/rocket-pool/node-manager-core/eth" + "github.com/rocket-pool/node-manager-core/utils/input" + "github.com/rocket-pool/smartnode/v2/shared/types/api" +) + +// =============== +// === Factory === +// =============== + +type protocolDaoInitializeVotingWithDelegateContextFactory struct { + handler *ProtocolDaoHandler +} + +func (f *protocolDaoInitializeVotingWithDelegateContextFactory) Create(args url.Values) (*protocolDaoInitializeVotingWithDelegateContext, error) { + c := &protocolDaoInitializeVotingWithDelegateContext{ + handler: f.handler, + } + inputErrs := []error{ + server.ValidateArg("delegate", args, input.ValidateAddress, &c.delegate), + } + return c, errors.Join(inputErrs...) +} + +func (f *protocolDaoInitializeVotingWithDelegateContextFactory) RegisterRoute(router *mux.Router) { + server.RegisterSingleStageRoute[*protocolDaoInitializeVotingWithDelegateContext, api.ProtocolDaoInitializeVotingData]( + router, "initialize-voting-with-delegate", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, + ) +} + +// =============== +// === Context === +// =============== + +type protocolDaoInitializeVotingWithDelegateContext struct { + handler *ProtocolDaoHandler + rp *rocketpool.RocketPool + + delegate common.Address + node *node.Node +} + +func (c *protocolDaoInitializeVotingWithDelegateContext) Initialize() (types.ResponseStatus, error) { + sp := c.handler.serviceProvider + c.rp = sp.GetRocketPool() + nodeAddress, _ := sp.GetWallet().GetAddress() + + // Requirements + status, err := sp.RequireNodeRegistered(c.handler.ctx) + if err != nil { + return status, err + } + + // Bindings + c.node, err = node.NewNode(c.rp, nodeAddress) + if err != nil { + return types.ResponseStatus_Error, fmt.Errorf("error creating node %s binding: %w", nodeAddress.Hex(), err) + } + return types.ResponseStatus_Success, nil +} + +func (c *protocolDaoInitializeVotingWithDelegateContext) GetState(mc *batch.MultiCaller) { + eth.AddQueryablesToMulticall(mc, + c.node.IsVotingInitialized, + ) +} + +func (c *protocolDaoInitializeVotingWithDelegateContext) PrepareData(data *api.ProtocolDaoInitializeVotingData, opts *bind.TransactOpts) (types.ResponseStatus, error) { + data.VotingInitialized = c.node.IsVotingInitialized.Get() + data.CanInitialize = !(data.VotingInitialized) + + // Get TX info + if data.CanInitialize { + txInfo, err := c.node.InitializeVotingWithDelegate(c.delegate, opts) + if err != nil { + return types.ResponseStatus_Error, fmt.Errorf("error getting TX info for InitializeVotingWithDelegate: %w", err) + } + data.TxInfo = txInfo + } + return types.ResponseStatus_Success, nil +} diff --git a/rocketpool-daemon/api/pdao/initialize-voting.go b/rocketpool-daemon/api/pdao/initialize-voting.go index a6a8df5f8..e20b1226a 100644 --- a/rocketpool-daemon/api/pdao/initialize-voting.go +++ b/rocketpool-daemon/api/pdao/initialize-voting.go @@ -1,13 +1,11 @@ package pdao import ( - "errors" "fmt" "net/url" _ "time/tzdata" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/gorilla/mux" batch "github.com/rocket-pool/batch-query" "github.com/rocket-pool/rocketpool-go/v2/node" @@ -16,7 +14,6 @@ import ( "github.com/rocket-pool/node-manager-core/api/server" "github.com/rocket-pool/node-manager-core/api/types" "github.com/rocket-pool/node-manager-core/eth" - "github.com/rocket-pool/node-manager-core/utils/input" "github.com/rocket-pool/smartnode/v2/shared/types/api" ) @@ -32,10 +29,7 @@ func (f *protocolDaoInitializeVotingContextFactory) Create(args url.Values) (*pr c := &protocolDaoInitializeVotingContext{ handler: f.handler, } - inputErrs := []error{ - server.ValidateArg("delegate", args, input.ValidateAddress, &c.delegate), - } - return c, errors.Join(inputErrs...) + return c, nil } func (f *protocolDaoInitializeVotingContextFactory) RegisterRoute(router *mux.Router) { @@ -52,8 +46,7 @@ type protocolDaoInitializeVotingContext struct { handler *ProtocolDaoHandler rp *rocketpool.RocketPool - delegate common.Address - node *node.Node + node *node.Node } func (c *protocolDaoInitializeVotingContext) Initialize() (types.ResponseStatus, error) { @@ -87,7 +80,7 @@ func (c *protocolDaoInitializeVotingContext) PrepareData(data *api.ProtocolDaoIn // Get TX info if data.CanInitialize { - txInfo, err := c.node.InitializeVotingWithDelegate(c.delegate, opts) + txInfo, err := c.node.InitializeVoting(opts) if err != nil { return types.ResponseStatus_Error, fmt.Errorf("error getting TX info for InitializeVoting: %w", err) } From f80fe65e4a88aaa2ac7d9ad23c4d28189a7e33c4 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Sun, 4 Aug 2024 18:38:07 -0700 Subject: [PATCH 02/36] Fix linter issue --- rocketpool-cli/commands/pdao/initialize-voting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-cli/commands/pdao/initialize-voting.go b/rocketpool-cli/commands/pdao/initialize-voting.go index fb6a72bba..924c81ea6 100644 --- a/rocketpool-cli/commands/pdao/initialize-voting.go +++ b/rocketpool-cli/commands/pdao/initialize-voting.go @@ -11,7 +11,7 @@ import ( ) func initializeVotingPrompt(c *cli.Context) error { - if utils.Confirm(fmt.Sprintf("Would you like to specify a delegate that can vote on your behalf on Protocol DAO proposals?")) { + if utils.Confirm("Would you like to specify a delegate that can vote on your behalf on Protocol DAO proposals?") { return initializeVotingWithDelegate(c) } return initializeVoting(c) From 8f6ae06338a522681a38730d2dd6c37ea270655d Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 20 Aug 2024 14:12:48 -0400 Subject: [PATCH 03/36] Update initialize voting text in V2 --- .../commands/pdao/initialize-voting.go | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/rocketpool-cli/commands/pdao/initialize-voting.go b/rocketpool-cli/commands/pdao/initialize-voting.go index 924c81ea6..de1786920 100644 --- a/rocketpool-cli/commands/pdao/initialize-voting.go +++ b/rocketpool-cli/commands/pdao/initialize-voting.go @@ -2,19 +2,44 @@ package pdao import ( "fmt" + "strings" "github.com/rocket-pool/node-manager-core/utils/input" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils" + cliutils "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/tx" "github.com/urfave/cli/v2" ) func initializeVotingPrompt(c *cli.Context) error { - if utils.Confirm("Would you like to specify a delegate that can vote on your behalf on Protocol DAO proposals?") { + fmt.Println("Thanks for initializing your voting power!") + fmt.Println("") + fmt.Println("You have two options:") + fmt.Println("") + fmt.Println("1. Vote directly (delegate vote power to yourself)") + fmt.Println(" This will allow you to vote on proposals directly,") + fmt.Println(" allowing you to personally shape the direction of the protocol.") + fmt.Println("") + fmt.Println("2. Delegate your vote") + fmt.Println(" This will delegate your vote power to someone you trust,") + fmt.Println(" giving them the power to vote on your behalf. You will have the option to override.") + fmt.Println("") + fmt.Printf("You can see a list of existing public delegates at %s,\n", "https://delegates.rocketpool.net") + fmt.Println("however, you can delegate to any node address.") + fmt.Println("") + fmt.Printf("Learn more about how this all works via: %s\n", "https://docs.rocketpool.net/guides/houston/participate#participating-in-on-chain-pdao-proposals") + fmt.Println("") + + inputString := cliutils.Prompt("Please type `direct` or `delegate` to continue:", "^(?i)(direct|delegate)$", "Please type `direct` or `delegate` to continue:") + switch strings.ToLower(inputString) { + case "direct": + return initializeVoting(c) + case "delegate": return initializeVotingWithDelegate(c) } - return initializeVoting(c) + return nil + } func initializeVoting(c *cli.Context) error { From 15cc00e2b70aa9b20cadccc3c0a0a13125f957ba Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 20 Aug 2024 15:23:00 -0400 Subject: [PATCH 04/36] Fix linter issue --- rocketpool-daemon/common/rewards/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/common/rewards/utils.go b/rocketpool-daemon/common/rewards/utils.go index 470229fd8..291e9d266 100644 --- a/rocketpool-daemon/common/rewards/utils.go +++ b/rocketpool-daemon/common/rewards/utils.go @@ -374,7 +374,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 fmt.Errorf("%s", errBuilder.String()) } // Gets the start slot for the given interval From 60cdbc0c67cf282607e5a259f22548734b064a42 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 26 Aug 2024 14:44:42 -0400 Subject: [PATCH 05/36] Fixed Printlns --- rocketpool-cli/commands/pdao/initialize-voting.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rocketpool-cli/commands/pdao/initialize-voting.go b/rocketpool-cli/commands/pdao/initialize-voting.go index de1786920..aea6e59bc 100644 --- a/rocketpool-cli/commands/pdao/initialize-voting.go +++ b/rocketpool-cli/commands/pdao/initialize-voting.go @@ -14,22 +14,22 @@ import ( func initializeVotingPrompt(c *cli.Context) error { fmt.Println("Thanks for initializing your voting power!") - fmt.Println("") + fmt.Println() fmt.Println("You have two options:") - fmt.Println("") + fmt.Println() fmt.Println("1. Vote directly (delegate vote power to yourself)") fmt.Println(" This will allow you to vote on proposals directly,") fmt.Println(" allowing you to personally shape the direction of the protocol.") - fmt.Println("") + fmt.Println() fmt.Println("2. Delegate your vote") fmt.Println(" This will delegate your vote power to someone you trust,") fmt.Println(" giving them the power to vote on your behalf. You will have the option to override.") - fmt.Println("") + fmt.Println() fmt.Printf("You can see a list of existing public delegates at %s,\n", "https://delegates.rocketpool.net") fmt.Println("however, you can delegate to any node address.") - fmt.Println("") + fmt.Println() fmt.Printf("Learn more about how this all works via: %s\n", "https://docs.rocketpool.net/guides/houston/participate#participating-in-on-chain-pdao-proposals") - fmt.Println("") + fmt.Println() inputString := cliutils.Prompt("Please type `direct` or `delegate` to continue:", "^(?i)(direct|delegate)$", "Please type `direct` or `delegate` to continue:") switch strings.ToLower(inputString) { From 69942c4636dca2979db10d859d045befdbed8655 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Thu, 29 Aug 2024 20:44:03 -0400 Subject: [PATCH 06/36] Add check to exit when bond reduction is disabled --- rocketpool-cli/commands/minipool/reduce-bond.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rocketpool-cli/commands/minipool/reduce-bond.go b/rocketpool-cli/commands/minipool/reduce-bond.go index e29948325..2e3022330 100644 --- a/rocketpool-cli/commands/minipool/reduce-bond.go +++ b/rocketpool-cli/commands/minipool/reduce-bond.go @@ -26,6 +26,12 @@ func reduceBondAmount(c *cli.Context) error { return err } + // Print message and exit if bond reductions are disabled + if details.Data.BondReductionDisabled { + fmt.Println("Cannot perform a bond reduction: bond reductions are currently disabled") + return nil + } + // Check the fee distributor if !details.Data.IsFeeDistributorInitialized { fmt.Println("Minipools cannot have their bonds reduced until your fee distributor has been initialized.") From 7044cbc393af41afb2d3158ce476bb9dcb1da3df Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 20 Aug 2024 15:23:00 -0400 Subject: [PATCH 07/36] Fix linter issue --- rocketpool-daemon/common/rewards/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/common/rewards/utils.go b/rocketpool-daemon/common/rewards/utils.go index 470229fd8..291e9d266 100644 --- a/rocketpool-daemon/common/rewards/utils.go +++ b/rocketpool-daemon/common/rewards/utils.go @@ -374,7 +374,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 fmt.Errorf("%s", errBuilder.String()) } // Gets the start slot for the given interval From 0413823acc3e0e02769ff06f5fede2a3a70e9b34 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 20 Aug 2024 15:23:00 -0400 Subject: [PATCH 08/36] Fix linter issue --- rocketpool-daemon/common/rewards/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/common/rewards/utils.go b/rocketpool-daemon/common/rewards/utils.go index 470229fd8..291e9d266 100644 --- a/rocketpool-daemon/common/rewards/utils.go +++ b/rocketpool-daemon/common/rewards/utils.go @@ -374,7 +374,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 fmt.Errorf("%s", errBuilder.String()) } // Gets the start slot for the given interval From 528919b3170cb727b9b5bbcf1d3821a95b4f8a8e Mon Sep 17 00:00:00 2001 From: Jacob Shufro Date: Thu, 29 Aug 2024 17:46:43 -0400 Subject: [PATCH 09/36] Allow a local script to be passed to rocketpool service install --- rocketpool-cli/client/service.go | 111 +++++++++++------- rocketpool-cli/commands/service/commands.go | 1 + .../service/install-update-tracker.go | 2 +- rocketpool-cli/commands/service/install.go | 6 +- 4 files changed, 74 insertions(+), 46 deletions(-) diff --git a/rocketpool-cli/client/service.go b/rocketpool-cli/client/service.go index 4346ad080..da9471b0d 100644 --- a/rocketpool-cli/client/service.go +++ b/rocketpool-cli/client/service.go @@ -33,55 +33,44 @@ func (c *Client) downloadAndRun( url string, verbose bool, version string, - useLocalInstaller bool, extraFlags []string, ) error { var script []byte - flags := []string{ - "-v", shellescape.Quote(version), + // Download the installation script + resp, err := http.Get(fmt.Sprintf(url, version)) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected http status downloading %s script: %d", name, resp.StatusCode) } - flags = append(flags, extraFlags...) - if useLocalInstaller { - // Make sure it exists - _, err := os.Stat(name) - if errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("local script [%s] does not exist", name) - } - if err != nil { - return fmt.Errorf("error checking script [%s]: %w", name, err) - } + // Sanity check that the script octet length matches content-length + script, err = io.ReadAll(resp.Body) + if err != nil { + return err + } - // Read it - script, err = os.ReadFile(name) - if err != nil { - return fmt.Errorf("error reading local script [%s]: %w", name, err) - } + if fmt.Sprint(len(script)) != resp.Header.Get("content-length") { + return fmt.Errorf("downloaded script length %d did not match content-length header %s", len(script), resp.Header.Get("content-length")) + } - // Set the "local mode" flag - flags = append(flags, "-l") - } else { - // Download the installation script - resp, err := http.Get(fmt.Sprintf(url, version)) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("unexpected http status downloading %s script: %d", name, resp.StatusCode) - } + return c.runScript(script, version, verbose, extraFlags) +} - // Sanity check that the script octet length matches content-length - script, err = io.ReadAll(resp.Body) - if err != nil { - return err - } +func (c *Client) runScript( + script []byte, + version string, + verbose bool, + extraFlags []string, +) error { - if fmt.Sprint(len(script)) != resp.Header.Get("content-length") { - return fmt.Errorf("downloaded script length %d did not match content-length header %s", len(script), resp.Header.Get("content-length")) - } + flags := []string{ + "-v", shellescape.Quote(version), } + flags = append(flags, extraFlags...) // Get the escalation command escalationCmd, err := c.getEscalationCommand() @@ -134,8 +123,29 @@ func (c *Client) downloadAndRun( return nil } +func readLocalScript(path string) ([]byte, error) { + // Make sure it exists + _, err := os.Stat(path) + if errors.Is(err, os.ErrNotExist) { + return nil, fmt.Errorf("local script [%s] does not exist", path) + } + if err != nil { + return nil, fmt.Errorf("error checking script [%s]: %w", path, err) + } + + // Read it + script, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading local script [%s]: %w", path, err) + } + + return script, nil +} + // Install the Rocket Pool service -func (c *Client) InstallService(verbose bool, noDeps bool, version string, path string, useLocalInstaller bool) error { +// installScriptPath is optional. If unset, the install script is downloaded from github. +func (c *Client) InstallService(verbose bool, noDeps bool, version string, path string, installScriptPath string) error { + // Get installation script flags flags := []string{} if path != "" { @@ -145,12 +155,29 @@ func (c *Client) InstallService(verbose bool, noDeps bool, version string, path flags = append(flags, "-d") } - return c.downloadAndRun(installerName, installerURL, verbose, version, useLocalInstaller, flags) + if installScriptPath != "" { + script, err := readLocalScript(installScriptPath) + if err != nil { + return err + } + // Set the "local mode" flag + flags = append(flags, "-l") + return c.runScript(script, version, verbose, flags) + } + + return c.downloadAndRun(installerName, installerURL, verbose, version, flags) } // Install the update tracker -func (c *Client) InstallUpdateTracker(verbose bool, version string, useLocalInstaller bool) error { - return c.downloadAndRun(updateTrackerInstallerName, updateTrackerURL, verbose, version, useLocalInstaller, nil) +func (c *Client) InstallUpdateTracker(verbose bool, version string, installScriptPath string) error { + if installScriptPath != "" { + script, err := readLocalScript(installScriptPath) + if err != nil { + return err + } + return c.runScript(script, version, verbose, nil) + } + return c.downloadAndRun(updateTrackerInstallerName, updateTrackerURL, verbose, version, nil) } // Start the Rocket Pool service diff --git a/rocketpool-cli/commands/service/commands.go b/rocketpool-cli/commands/service/commands.go index 6bc112ca5..f57d9745c 100644 --- a/rocketpool-cli/commands/service/commands.go +++ b/rocketpool-cli/commands/service/commands.go @@ -342,6 +342,7 @@ func RegisterCommands(app *cli.App, name string, aliases []string) { cliutils.YesFlag, installUpdateTrackerVerboseFlag, installUpdateTrackerVersionFlag, + installLocalFlag, }, Action: func(c *cli.Context) error { // Validate args diff --git a/rocketpool-cli/commands/service/install-update-tracker.go b/rocketpool-cli/commands/service/install-update-tracker.go index 73550c911..7affa87d9 100644 --- a/rocketpool-cli/commands/service/install-update-tracker.go +++ b/rocketpool-cli/commands/service/install-update-tracker.go @@ -41,7 +41,7 @@ func installUpdateTracker(c *cli.Context) error { } // Install service - err = rp.InstallUpdateTracker(c.Bool(installUpdateTrackerVerboseFlag.Name), c.String(installUpdateTrackerVersionFlag.Name), c.Bool(installLocalFlag.Name)) + err = rp.InstallUpdateTracker(c.Bool(installUpdateTrackerVerboseFlag.Name), c.String(installUpdateTrackerVersionFlag.Name), c.String(installLocalFlag.Name)) if err != nil { return err } diff --git a/rocketpool-cli/commands/service/install.go b/rocketpool-cli/commands/service/install.go index 694a4be47..680e23e62 100644 --- a/rocketpool-cli/commands/service/install.go +++ b/rocketpool-cli/commands/service/install.go @@ -37,10 +37,10 @@ var ( Aliases: []string{"u"}, Usage: "Certain configuration values are reset when the Smart Node is updated, such as Docker container tags; use this flag to force that reset, even if the Smart Node hasn't been updated", } - installLocalFlag *cli.BoolFlag = &cli.BoolFlag{ + installLocalFlag *cli.StringFlag = &cli.StringFlag{ Name: "local-script", Aliases: []string{"l"}, - Usage: fmt.Sprintf("Use a local installer script instead of pulling it down from the source repository. The script and the installer package must be in your current working directory.%sMake sure you absolutely trust the script before using this flag.%s", terminal.ColorRed, terminal.ColorReset), + Usage: fmt.Sprintf("Use a local installer script instead of pulling it down from the source repository. The script and the installer package must be in your current working directory.\n%sMake sure you absolutely trust the script before using this flag.%s", terminal.ColorRed, terminal.ColorReset), } ) @@ -67,7 +67,7 @@ func installService(c *cli.Context) error { c.Bool(installNoDepsFlag.Name), c.String(installVersionFlag.Name), c.String(installPathFlag.Name), - c.Bool(installLocalFlag.Name), + c.String(installLocalFlag.Name), ) if err != nil { return err From af5ba088f25ca15f2e774a6113325baf0976a86c Mon Sep 17 00:00:00 2001 From: Jacob Shufro Date: Thu, 29 Aug 2024 18:25:03 -0400 Subject: [PATCH 10/36] Update lint error fix for semantics --- rocketpool-daemon/common/rewards/utils.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rocketpool-daemon/common/rewards/utils.go b/rocketpool-daemon/common/rewards/utils.go index 291e9d266..b9b1f43e6 100644 --- a/rocketpool-daemon/common/rewards/utils.go +++ b/rocketpool-daemon/common/rewards/utils.go @@ -2,6 +2,7 @@ package rewards import ( "context" + "errors" "fmt" "io" "math" @@ -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("%s", errBuilder.String()) + return errors.New(errBuilder.String()) } // Gets the start slot for the given interval From 40132bbd3eeeed795dd7bb388e9c0248ccb84791 Mon Sep 17 00:00:00 2001 From: Jacob Shufro Date: Thu, 29 Aug 2024 19:37:47 -0400 Subject: [PATCH 11/36] Use paths that work on OSX and Linux --- install/deploy/templates/eth1.tmpl | 4 ++-- install/deploy/templates/eth2.tmpl | 4 ++-- install/deploy/templates/mev-boost.tmpl | 4 ++-- install/deploy/templates/validator.tmpl | 4 ++-- install/install.sh | 15 +++++++-------- install/packages/debian/debian/rules | 6 +++--- rocketpool-cli/client/compose.go | 8 ++++---- v2.md | 4 ++-- 8 files changed, 24 insertions(+), 25 deletions(-) diff --git a/install/deploy/templates/eth1.tmpl b/install/deploy/templates/eth1.tmpl index 6451c9447..1657b186d 100644 --- a/install/deploy/templates/eth1.tmpl +++ b/install/deploy/templates/eth1.tmpl @@ -16,7 +16,7 @@ services: ports: [ "{{$p2p}}:{{$p2p}}/udp", "{{$p2p}}:{{$p2p}}/tcp"{{.GetEcOpenApiPorts}} ] volumes: - {{.ExecutionClientDataVolume}}:/ethclient - - /usr/share/rocketpool/scripts:/usr/share/rocketpool/scripts:ro + - /opt/rocketpool/scripts:/opt/rocketpool/scripts:ro - /var/lib/rocketpool/data/{{.ProjectName}}:/secrets networks: - net @@ -49,7 +49,7 @@ services: - RP_GETH_ARCHIVE_MODE={{.LocalExecutionClient.Geth.ArchiveMode}} {{- end}} entrypoint: sh - command: "/usr/share/rocketpool/scripts/{{.GetEcStartScript}}" + command: "/opt/rocketpool/scripts/{{.GetEcStartScript}}" cap_drop: - all cap_add: diff --git a/install/deploy/templates/eth2.tmpl b/install/deploy/templates/eth2.tmpl index d755a2f34..d11e8182f 100644 --- a/install/deploy/templates/eth2.tmpl +++ b/install/deploy/templates/eth2.tmpl @@ -24,7 +24,7 @@ services: {{- end}} volumes: - {{.BeaconNodeDataVolume}}:/ethclient - - /usr/share/rocketpool/scripts:/usr/share/rocketpool/scripts:ro + - /opt/rocketpool/scripts:/opt/rocketpool/scripts:ro - /var/lib/rocketpool/data/{{.ProjectName}}:/secrets:ro networks: - net @@ -61,7 +61,7 @@ services: - BN_P2P_QUIC_PORT={{.LocalBeaconClient.Lighthouse.P2pQuicPort}} {{- end}} entrypoint: sh - command: "/usr/share/rocketpool/scripts/{{.GetBnStartScript}}" + command: "/opt/rocketpool/scripts/{{.GetBnStartScript}}" cap_drop: - all cap_add: diff --git a/install/deploy/templates/mev-boost.tmpl b/install/deploy/templates/mev-boost.tmpl index 113566a3c..9382606d2 100644 --- a/install/deploy/templates/mev-boost.tmpl +++ b/install/deploy/templates/mev-boost.tmpl @@ -12,7 +12,7 @@ services: restart: unless-stopped ports: [{{.GetMevBoostOpenPorts}}] volumes: - - /usr/share/rocketpool/scripts:/usr/share/rocketpool/scripts:ro + - /opt/rocketpool/scripts:/opt/rocketpool/scripts:ro networks: - net environment: @@ -20,7 +20,7 @@ services: - MEV_BOOST_PORT={{.MevBoost.Port}} - MEV_BOOST_RELAYS={{.MevBoost.GetRelayString}} entrypoint: sh - command: "/usr/share/rocketpool/scripts/{{.GetMevBoostStartScript}}" + command: "/opt/rocketpool/scripts/{{.GetMevBoostStartScript}}" cap_drop: - all cap_add: diff --git a/install/deploy/templates/validator.tmpl b/install/deploy/templates/validator.tmpl index d4fed0a8e..20913db98 100644 --- a/install/deploy/templates/validator.tmpl +++ b/install/deploy/templates/validator.tmpl @@ -13,7 +13,7 @@ services: restart: unless-stopped stop_grace_period: 3m volumes: - - /usr/share/rocketpool/scripts:/usr/share/rocketpool/scripts:ro + - /opt/rocketpool/scripts:/opt/rocketpool/scripts:ro - {{.GetValidatorsFolderPath}}:{{.GetValidatorsFolderPath}} - {{.GetAddonsFolderPath}}:{{.GetAddonsFolderPath}} networks: @@ -45,7 +45,7 @@ services: - TEKU_SHUT_DOWN_WHEN_SLASHED={{.ValidatorClient.Teku.UseSlashingProtection}} {{- end}} entrypoint: sh - command: "/usr/share/rocketpool/scripts/{{.GetVcStartScript}}" + command: "/opt/rocketpool/scripts/{{.GetVcStartScript}}" cap_drop: - all cap_add: diff --git a/install/install.sh b/install/install.sh index e97106912..244d948ba 100755 --- a/install/install.sh +++ b/install/install.sh @@ -336,12 +336,11 @@ install() { fi # Create rocket pool dir & files - RP_BIN_PATH=/usr/bin/rocketpool - RP_SHARE_PATH=/usr/share/rocketpool + RP_SYS_PATH=/opt/rocketpool RP_VAR_PATH=/var/lib/rocketpool progress 4 "Creating Rocket Pool directory structure..." - { mkdir -p "$RP_SHARE_PATH" || fail "Could not create the Rocket Pool resources directory."; } >&2 + { mkdir -p "$RP_SYS_PATH" || fail "Could not create the Rocket Pool resources directory."; } >&2 { mkdir -p "$RP_VAR_PATH/data" || fail "Could not create the Rocket Pool system data directory."; } >&2 { chmod 0700 "$RP_VAR_PATH/data" || fail "Could not set the Rocket Pool data directory permissions."; } >&2 @@ -359,11 +358,11 @@ install() { # Copy package files progress 6 "Copying package files to Rocket Pool system directory..." - { cp -r "$PACKAGE_FILES_PATH/addons" "$RP_SHARE_PATH" || fail "Could not copy addons folder to the Rocket Pool system directory."; } >&2 - { cp -r "$PACKAGE_FILES_PATH/override" "$RP_SHARE_PATH" || fail "Could not copy override folder to the Rocket Pool system directory."; } >&2 - { cp -r "$PACKAGE_FILES_PATH/scripts" "$RP_SHARE_PATH" || fail "Could not copy scripts folder to the Rocket Pool system directory."; } >&2 - { cp -r "$PACKAGE_FILES_PATH/templates" "$RP_SHARE_PATH" || fail "Could not copy templates folder to the Rocket Pool system directory."; } >&2 - { find "$RP_SHARE_PATH/scripts" -name "*.sh" -exec chmod +x {} \; 2>/dev/null || fail "Could not set executable permissions on package files."; } >&2 + { cp -r "$PACKAGE_FILES_PATH/addons" "$RP_SYS_PATH" || fail "Could not copy addons folder to the Rocket Pool system directory."; } >&2 + { cp -r "$PACKAGE_FILES_PATH/override" "$RP_SYS_PATH" || fail "Could not copy override folder to the Rocket Pool system directory."; } >&2 + { cp -r "$PACKAGE_FILES_PATH/scripts" "$RP_SYS_PATH" || fail "Could not copy scripts folder to the Rocket Pool system directory."; } >&2 + { cp -r "$PACKAGE_FILES_PATH/templates" "$RP_SYS_PATH" || fail "Could not copy templates folder to the Rocket Pool system directory."; } >&2 + { find "$RP_SYS_PATH/scripts" -name "*.sh" -exec chmod +x {} \; 2>/dev/null || fail "Could not set executable permissions on package files."; } >&2 # Clean up unnecessary files from old installations diff --git a/install/packages/debian/debian/rules b/install/packages/debian/debian/rules index 4377cd077..1c421ea7c 100755 --- a/install/packages/debian/debian/rules +++ b/install/packages/debian/debian/rules @@ -38,8 +38,8 @@ override_dh_auto_install: # Create the folder structure and copy the deploy files over install -dm 0700 debian/rocketpool/var/lib/rocketpool/data install -dm 0700 debian/rocketpool/var/lib/rocketpool/global - mkdir -p debian/rocketpool/usr/share/rocketpool/ - cp -r deploy/* debian/rocketpool/usr/share/rocketpool/ - chmod -R +x debian/rocketpool/usr/share/rocketpool/scripts + mkdir -p debian/rocketpool/opt/rocketpool/ + cp -r deploy/* debian/rocketpool/opt/rocketpool/ + chmod -R +x debian/rocketpool/opt/rocketpool/scripts override_dh_auto_test: diff --git a/rocketpool-cli/client/compose.go b/rocketpool-cli/client/compose.go index 1c1d65671..7b30b7d31 100644 --- a/rocketpool-cli/client/compose.go +++ b/rocketpool-cli/client/compose.go @@ -18,10 +18,10 @@ import ( ) const ( - templatesDir string = "/usr/share/rocketpool/templates" - addonsSourceDir string = "/usr/share/rocketpool/addons" - overrideSourceDir string = "/usr/share/rocketpool/override" - nativeScriptsSourceDir string = "/usr/share/rocketpool/scripts/native" + templatesDir string = "/opt/rocketpool/templates" + addonsSourceDir string = "/opt/rocketpool/addons" + overrideSourceDir string = "/opt/rocketpool/override" + nativeScriptsSourceDir string = "/opt/rocketpool/scripts/native" overrideDir string = "override" runtimeDir string = "runtime" extraScrapeJobsDir string = "extra-scrape-jobs" diff --git a/v2.md b/v2.md index 5552a46d3..71352ce59 100644 --- a/v2.md +++ b/v2.md @@ -17,7 +17,7 @@ NOTE: for actual installation instructions, please see the [section below](#inst - The Smart Node now comes in a `.deb` package, so users running Debian or Debian-derivative distributions can now install it via `sudo apt install rocketpool` and update it via `sudo apt update && sudo apt dist-upgrade` once the Rocket Pool repository is set up. - Packages for other distributions, such as RHEL or Fedora, will be introduced at a later date. - For now, users not on Debian-based systems can install via the traditional `rocketpool service install` command. It will still pull the necessary files from GitHub as it did before. -- Installation no longer puts all core system files into your `~/.rocketpool` directory. System files (such as Docker compose templates and execution scripts) are now put into `/usr/share/rocketpool`. The CLI binary is now installed to `/usr/bin/rocketpool`. +- Installation no longer puts all core system files into your `~/.rocketpool` directory. System files (such as Docker compose templates and execution scripts) are now put into `/opt/rocketpool`. The CLI binary is now installed to `/usr/bin/rocketpool`. - Runtime files, such as your Docker compose overrides and logging, are still put into `~/.rocketpool` by default. - Installation via the CLI can optionally now be done with local install scripts and packages on your filesystem instead of needing to reach out to GitHub. This is helpful in places where GitHub can't be accessed. - (*For developers*) The old `smartnode-install` repository has been migrated into the `smartnode` repository. @@ -264,7 +264,7 @@ Running the Smart Node is, for all practical purposes, the same as it was in `v1 - Use `rocketpool service node-logs api` to view the new API logs - Use `rocketpool service node-logs tasks` to view the node task loop logs (previously `rocketpool service logs node`) - Use `rocketpool service node-logs watchtower` to view the watchtower task loop logs (`rocketpool service logs watchtower`) -- The "non-modifiable" files like Docker compose templates and scripts are now in `/usr/share/rocketpool` instead of your user home directory (though personal files like overrides are still in your home directory) +- The "non-modifiable" files like Docker compose templates and scripts are now in `/opt/rocketpool` instead of your user home directory (though personal files like overrides are still in your home directory) - The CLI (if installed via the package manager) is now at `/usr/bin/rocketpool` instead of `~/bin/rocketpool` - Some CLI commands have moved and/or have new flags (see the overview section above) - Commands that involve selecting multiple items (such as distributing minipool balances) will now let you select arbitrary options, and submit all of the transactions at once. The overall flow will feel much faster. From 0ef750ffcb974f5602b0c2e8a98583c2e814f25e Mon Sep 17 00:00:00 2001 From: SolezOfScience Date: Sat, 3 Aug 2024 14:07:31 -0700 Subject: [PATCH 12/36] Addressing smartnode-issues-601 Addressing rocket-pool/smartnode#601 on v2 branch --- install/deploy/scripts/start-mev-boost.sh | 27 ++++++++++++++++++++--- install/deploy/templates/mev-boost.tmpl | 1 + 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/install/deploy/scripts/start-mev-boost.sh b/install/deploy/scripts/start-mev-boost.sh index bfbc64706..3a222ce41 100755 --- a/install/deploy/scripts/start-mev-boost.sh +++ b/install/deploy/scripts/start-mev-boost.sh @@ -1,6 +1,26 @@ #!/bin/sh -# Set up the network-based flag +parse_additional_flags() { + # Initialize an empty string for additional arguments + ADDITIONAL_ARGS="" + + # Check if the environment variable MEV_BOOST_ADDITIONAL_FLAGS is not empty + if [ -n "$MEV_BOOST_ADDITIONAL_FLAGS" ]; then + # Split the input string into an array of key-value pairs using comma as the delimiter + IFS=',' read -r -a pairs <<< "$MEV_BOOST_ADDITIONAL_FLAGS" + + # Iterate over each key-value pair + for pair in "${pairs[@]}"; do + # Extract the key and value from the current pair + key=$(echo "$pair" | cut -d'=' -f1) + value=$(echo "$pair" | cut -d'=' -f2) + + # Append the key-value pair to the ADDITIONAL_ARGS string + ADDITIONAL_ARGS="$ADDITIONAL_ARGS -${key} ${value}" + done + fi +} + if [ "$NETWORK" = "mainnet" ]; then MEV_NETWORK="mainnet" elif [ "$NETWORK" = "holesky" ]; then @@ -12,5 +32,6 @@ else exit 1 fi -# Run MEV-boost -exec /app/mev-boost -${MEV_NETWORK} -addr 0.0.0.0:${MEV_BOOST_PORT} -relay-check -relays ${MEV_BOOST_RELAYS} \ No newline at end of file +parse_additional_flags + +exec /app/mev-boost -${MEV_NETWORK} -addr 0.0.0.0:${MEV_BOOST_PORT} -relay-check -relays ${MEV_BOOST_RELAYS} ${ADDITIONAL_ARGS} diff --git a/install/deploy/templates/mev-boost.tmpl b/install/deploy/templates/mev-boost.tmpl index 113566a3c..f4fb4d3be 100644 --- a/install/deploy/templates/mev-boost.tmpl +++ b/install/deploy/templates/mev-boost.tmpl @@ -19,6 +19,7 @@ services: - NETWORK={{.Network}} - MEV_BOOST_PORT={{.MevBoost.Port}} - MEV_BOOST_RELAYS={{.MevBoost.GetRelayString}} + - MEV_BOOST_ADDITIONAL_FLAGS={{.MevBoost.AdditionalFlags}} entrypoint: sh command: "/usr/share/rocketpool/scripts/{{.GetMevBoostStartScript}}" cap_drop: From 76440160cd8fbbb49927db0b8247dd5e6defce85 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 3 Sep 2024 18:42:07 -0400 Subject: [PATCH 13/36] Fixed segfault by populating nil pointer --- rocketpool-daemon/api/node/set-rpl-withdrawal-address.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rocketpool-daemon/api/node/set-rpl-withdrawal-address.go b/rocketpool-daemon/api/node/set-rpl-withdrawal-address.go index 2cbd3b9c1..ab98a9547 100644 --- a/rocketpool-daemon/api/node/set-rpl-withdrawal-address.go +++ b/rocketpool-daemon/api/node/set-rpl-withdrawal-address.go @@ -82,6 +82,7 @@ func (c *nodeSetRplWithdrawalAddressContext) GetState(mc *batch.MultiCaller) { c.node.IsRplWithdrawalAddressSet, c.node.RplWithdrawalAddress, c.node.PrimaryWithdrawalAddress, + c.node.RplStake, ) } @@ -90,6 +91,7 @@ func (c *nodeSetRplWithdrawalAddressContext) PrepareData(data *api.NodeSetRplWit data.PrimaryAddressDiffers = (c.node.PrimaryWithdrawalAddress.Get() != c.nodeAddress || isRplWithdrawalAddressSet) data.RplAddressDiffers = (isRplWithdrawalAddressSet && c.node.RplWithdrawalAddress.Get() != c.nodeAddress) data.CanSet = !(data.PrimaryAddressDiffers || data.RplAddressDiffers) + data.RplStake = c.node.RplStake.Get() if data.CanSet { txInfo, err := c.node.SetRplWithdrawalAddress(c.address, c.confirm, opts) From 3ca70c6f97141e91417aac568b3792d0237473fb Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 9 Sep 2024 11:12:35 -0400 Subject: [PATCH 14/36] Populate empty data field --- rocketpool-daemon/api/minipool/rescue-dissolved-details.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rocketpool-daemon/api/minipool/rescue-dissolved-details.go b/rocketpool-daemon/api/minipool/rescue-dissolved-details.go index 3083d2fb0..ef12c71db 100644 --- a/rocketpool-daemon/api/minipool/rescue-dissolved-details.go +++ b/rocketpool-daemon/api/minipool/rescue-dissolved-details.go @@ -89,6 +89,7 @@ func (c *minipoolRescueDissolvedDetailsContext) PrepareData(addresses []common.A MinipoolState: mpCommon.Status.Formatted(), IsFinalized: mpCommon.IsFinalised.Get(), MinipoolVersion: mpCommon.Version, + BeaconBalance: big.NewInt(0), } if mpDetails.MinipoolState != rptypes.MinipoolStatus_Dissolved || mpDetails.IsFinalized { From a347fcec2e066fadfae3f66fc24ebe72d9e8289a Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 10 Sep 2024 16:16:22 -0400 Subject: [PATCH 15/36] Populate empty data fields in odao and security proposals --- rocketpool-daemon/api/odao/proposals.go | 1 + rocketpool-daemon/api/security/proposals.go | 1 + 2 files changed, 2 insertions(+) diff --git a/rocketpool-daemon/api/odao/proposals.go b/rocketpool-daemon/api/odao/proposals.go index 9ffbe1c4b..54920fa5a 100644 --- a/rocketpool-daemon/api/odao/proposals.go +++ b/rocketpool-daemon/api/odao/proposals.go @@ -93,6 +93,7 @@ func (c *oracleDaoProposalsContext) PrepareData(data *api.OracleDaoProposalsData for _, odaoProp := range odaoProps { prop := api.OracleDaoProposalDetails{ ID: odaoProp.ID, + DAO: "rocketDAONodeTrustedProposals", ProposerAddress: odaoProp.ProposerAddress.Get(), Message: odaoProp.Message.Get(), CreatedTime: odaoProp.CreatedTime.Formatted(), diff --git a/rocketpool-daemon/api/security/proposals.go b/rocketpool-daemon/api/security/proposals.go index d0c172da9..d6f50094d 100644 --- a/rocketpool-daemon/api/security/proposals.go +++ b/rocketpool-daemon/api/security/proposals.go @@ -98,6 +98,7 @@ func (c *securityProposalsContext) PrepareData(data *api.SecurityProposalsData, for _, scProp := range scProps { prop := api.SecurityProposalDetails{ ID: scProp.ID, + DAO: "rocketDAOSecurityProposals", ProposerAddress: scProp.ProposerAddress.Get(), Message: scProp.Message.Get(), CreatedTime: scProp.CreatedTime.Formatted(), From c4daa2f28f3b198ec681b21b61857beccfc0bf35 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 10 Sep 2024 13:58:16 -0700 Subject: [PATCH 16/36] Populate state field in odao proposals --- rocketpool-daemon/api/odao/proposals.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rocketpool-daemon/api/odao/proposals.go b/rocketpool-daemon/api/odao/proposals.go index 54920fa5a..0ec0a5058 100644 --- a/rocketpool-daemon/api/odao/proposals.go +++ b/rocketpool-daemon/api/odao/proposals.go @@ -106,6 +106,7 @@ func (c *oracleDaoProposalsContext) PrepareData(data *api.OracleDaoProposalsData IsCancelled: odaoProp.IsCancelled.Get(), IsExecuted: odaoProp.IsExecuted.Get(), Payload: odaoProp.Payload.Get(), + State: odaoProp.State.Formatted(), } prop.PayloadStr, err = odaoProp.GetPayloadAsString() if err != nil { From ae991125521083528f0aa05aa0fd42253ff5fc0d Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Wed, 11 Sep 2024 16:37:24 -0700 Subject: [PATCH 17/36] Removed a hardcoded value in stake rpl --- rocketpool-cli/commands/node/stake-rpl.go | 5 ++++- rocketpool-daemon/api/node/stake-rpl.go | 13 +++++++++++++ shared/types/api/node.go | 12 +++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/rocketpool-cli/commands/node/stake-rpl.go b/rocketpool-cli/commands/node/stake-rpl.go index 0452d5c89..9b1be902c 100644 --- a/rocketpool-cli/commands/node/stake-rpl.go +++ b/rocketpool-cli/commands/node/stake-rpl.go @@ -128,7 +128,10 @@ func nodeStakeRpl(c *cli.Context) error { // Run the stake TX validated, err := tx.HandleTx(c, rp, stakeResponse.Data.StakeTxInfo, - fmt.Sprintf("Are you sure you want to stake %.6f RPL? You will not be able to unstake this RPL until you exit your validators and close your minipools, or reach over 100%% collateral!", math.RoundDown(eth.WeiToEth(amountWei), 6)), + fmt.Sprintf("Are you sure you want to stake %.6f RPL? You will not be able to unstake this RPL until you exit your validators and close your minipools, or reach %.6f staked RPL (%.0f%% of bonded eth)!", + math.RoundDown(eth.WeiToEth(amountWei), 6), + math.RoundDown(eth.WeiToEth(status.Data.MaximumRplStake), 6), + eth.WeiToEth(status.Data.MaximumStakeFraction)*100), "staking RPL", "Staking RPL...", ) diff --git a/rocketpool-daemon/api/node/stake-rpl.go b/rocketpool-daemon/api/node/stake-rpl.go index 912044255..0ca8de00c 100644 --- a/rocketpool-daemon/api/node/stake-rpl.go +++ b/rocketpool-daemon/api/node/stake-rpl.go @@ -10,12 +10,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/gorilla/mux" batch "github.com/rocket-pool/batch-query" + "github.com/rocket-pool/rocketpool-go/v2/dao/protocol" "github.com/rocket-pool/rocketpool-go/v2/node" "github.com/rocket-pool/rocketpool-go/v2/rocketpool" "github.com/rocket-pool/rocketpool-go/v2/tokens" "github.com/rocket-pool/node-manager-core/api/server" "github.com/rocket-pool/node-manager-core/api/types" + "github.com/rocket-pool/node-manager-core/eth" "github.com/rocket-pool/node-manager-core/utils/input" "github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/utils" "github.com/rocket-pool/smartnode/v2/shared/types/api" @@ -60,6 +62,7 @@ type nodeStakeRplContext struct { node *node.Node balance *big.Int allowance *big.Int + pSettings *protocol.ProtocolDaoSettings } func (c *nodeStakeRplContext) Initialize() (types.ResponseStatus, error) { @@ -86,6 +89,11 @@ func (c *nodeStakeRplContext) Initialize() (types.ResponseStatus, error) { if err != nil { return types.ResponseStatus_Error, fmt.Errorf("error creating RocketNodeStaking binding: %w", err) } + pMgr, err := protocol.NewProtocolDaoManager(c.rp) + if err != nil { + return types.ResponseStatus_Error, fmt.Errorf("error creating pDAO manager binding: %w", err) + } + c.pSettings = pMgr.Settings c.nsAddress = rns.Address return types.ResponseStatus_Success, nil } @@ -93,12 +101,17 @@ func (c *nodeStakeRplContext) Initialize() (types.ResponseStatus, error) { func (c *nodeStakeRplContext) GetState(mc *batch.MultiCaller) { c.rpl.BalanceOf(mc, &c.balance, c.nodeAddress) c.rpl.GetAllowance(mc, &c.allowance, c.nodeAddress, c.nsAddress) + eth.AddQueryablesToMulticall(mc, + c.node.MaximumRplStake, + ) } func (c *nodeStakeRplContext) PrepareData(data *api.NodeStakeRplData, opts *bind.TransactOpts) (types.ResponseStatus, error) { data.InsufficientBalance = (c.amount.Cmp(c.balance) > 0) data.Allowance = c.allowance data.CanStake = !(data.InsufficientBalance) + data.MaximumStakeFraction = c.pSettings.Node.MaximumPerMinipoolStake.Raw() + data.MaximumRplStake = c.node.MaximumRplStake.Get() if data.CanStake { if c.allowance.Cmp(c.amount) < 0 { diff --git a/shared/types/api/node.go b/shared/types/api/node.go index db751f790..9d7416be9 100644 --- a/shared/types/api/node.go +++ b/shared/types/api/node.go @@ -151,11 +151,13 @@ type NodeSwapRplData struct { } type NodeStakeRplData struct { - CanStake bool `json:"canStake"` - InsufficientBalance bool `json:"insufficientBalance"` - Allowance *big.Int `json:"allowance"` - ApproveTxInfo *eth.TransactionInfo `json:"approveTxInfo"` - StakeTxInfo *eth.TransactionInfo `json:"stakeTxInfo"` + CanStake bool `json:"canStake"` + InsufficientBalance bool `json:"insufficientBalance"` + Allowance *big.Int `json:"allowance"` + ApproveTxInfo *eth.TransactionInfo `json:"approveTxInfo"` + StakeTxInfo *eth.TransactionInfo `json:"stakeTxInfo"` + MaximumStakeFraction *big.Int `json:"maximumStakeFraction"` + MaximumRplStake *big.Int `json:"maximumRplStake"` } type NodeSetStakeRplForAllowedData struct { From 8121d6ace011b49d9444e1e9d2f71f929f7557b1 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 17 Sep 2024 23:32:08 -0700 Subject: [PATCH 18/36] Fixed a bug in odao setting/propose --- rocketpool-daemon/api/odao/propose-settings.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/api/odao/propose-settings.go b/rocketpool-daemon/api/odao/propose-settings.go index 24d357ae5..bb8bac478 100644 --- a/rocketpool-daemon/api/odao/propose-settings.go +++ b/rocketpool-daemon/api/odao/propose-settings.go @@ -132,7 +132,7 @@ func (c *oracleDaoProposeSettingContext) PrepareData(data *api.OracleDaoProposeS data.TxInfo = txInfo } } - return types.ResponseStatus_Error, nil + return types.ResponseStatus_Success, nil } func (c *oracleDaoProposeSettingContext) createProposalTx(category oracle.SettingsCategory, opts *bind.TransactOpts) (bool, *eth.TransactionInfo, error, error) { From 31b5a34f023000b3f8f8da7c17fde94ba74cd86d Mon Sep 17 00:00:00 2001 From: Jacob Shufro Date: Fri, 20 Sep 2024 06:11:17 -0400 Subject: [PATCH 19/36] Fix issue with root mounted as rprivate --- install/deploy/templates/exporter.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/deploy/templates/exporter.tmpl b/install/deploy/templates/exporter.tmpl index 2f8553032..a8175cb22 100644 --- a/install/deploy/templates/exporter.tmpl +++ b/install/deploy/templates/exporter.tmpl @@ -29,7 +29,7 @@ services: - "/sys:/host/sys:ro,rslave" - "/var/lib/node_exporter/textfile_collector:/host/textfile_collector:ro" {{- if .Metrics.Exporter.RootFs.Value }} - - "/:/rootfs:ro" + - "/:/rootfs:ro,rslave" {{- end}} network_mode: host networks: From 0ac7025e231eac91c8a18e24918531538619563d Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 23 Sep 2024 19:48:39 -0700 Subject: [PATCH 20/36] Corrected balance comparison for eth withdrawal --- rocketpool-daemon/api/node/withdraw-eth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/api/node/withdraw-eth.go b/rocketpool-daemon/api/node/withdraw-eth.go index b811586b0..fb5b1c863 100644 --- a/rocketpool-daemon/api/node/withdraw-eth.go +++ b/rocketpool-daemon/api/node/withdraw-eth.go @@ -89,7 +89,7 @@ func (c *nodeWithdrawEthContext) PrepareData(data *api.NodeWithdrawEthData, opts ethBalance := c.node.DonatedEthBalance.Get() hasDifferentPrimaryWithdrawalAddress := c.nodeAddress != c.node.PrimaryWithdrawalAddress.Get() - data.InsufficientBalance = (c.amount.Cmp(ethBalance) >= 0) + data.InsufficientBalance = (c.amount.Cmp(ethBalance) > 0) data.HasDifferentPrimaryWithdrawalAddress = hasDifferentPrimaryWithdrawalAddress // Update & return response From 13ca2b7f08b678ad2612865c4be80b8aea0cca6d Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 23 Sep 2024 20:47:01 -0700 Subject: [PATCH 21/36] Fixed comparison of MinNodeFee and MaxNodeFee --- rocketpool-cli/commands/node/deposit.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-cli/commands/node/deposit.go b/rocketpool-cli/commands/node/deposit.go index dddf496e4..f15762906 100644 --- a/rocketpool-cli/commands/node/deposit.go +++ b/rocketpool-cli/commands/node/deposit.go @@ -136,7 +136,7 @@ func newDepositPrompts(c *cli.Context, rp *client.Client, soloConversionPubkey * } } else { // Prompt for min node fee - if nodeFeeResponse.Data.MinNodeFee == nodeFeeResponse.Data.MaxNodeFee { + if nodeFeeResponse.Data.MinNodeFee.Cmp(nodeFeeResponse.Data.MaxNodeFee) == 0 { fmt.Printf("Your minipool will use the current fixed commission rate of %.2f%%.\n", eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee)*100) minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee) } else { From 9a0970809b5fefe5b7d516e17fdb2ec1303676bd Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:58:22 -0300 Subject: [PATCH 22/36] bump version to 2.0.0-b4 --- assets/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/version.json b/assets/version.json index f58ff60eb..fd52c2425 100644 --- a/assets/version.json +++ b/assets/version.json @@ -1,3 +1,3 @@ { - "Version": "2.0.0-b3" + "Version": "2.0.0-b4" } From 9ceb3687b81aa4a7f7103231b2ccf75022bc0ce8 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:31:45 -0300 Subject: [PATCH 23/36] Fix register route --- rocketpool-daemon/api/odao/cancel-proposal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/api/odao/cancel-proposal.go b/rocketpool-daemon/api/odao/cancel-proposal.go index b0b9aa62a..0206557f8 100644 --- a/rocketpool-daemon/api/odao/cancel-proposal.go +++ b/rocketpool-daemon/api/odao/cancel-proposal.go @@ -40,7 +40,7 @@ func (f *oracleDaoCancelProposalContextFactory) Create(args url.Values) (*oracle func (f *oracleDaoCancelProposalContextFactory) RegisterRoute(router *mux.Router) { server.RegisterSingleStageRoute[*oracleDaoCancelProposalContext, api.OracleDaoCancelProposalData]( - router, "proposal/execute", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, + router, "proposal/cancel", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, ) } From f3a58f95cbc324078fba20c1c7a045aa7d1c2b71 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:32:00 -0300 Subject: [PATCH 24/36] Fix InvalidState check --- rocketpool-daemon/api/odao/execute-proposals.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/api/odao/execute-proposals.go b/rocketpool-daemon/api/odao/execute-proposals.go index 515f79815..d6061bb79 100644 --- a/rocketpool-daemon/api/odao/execute-proposals.go +++ b/rocketpool-daemon/api/odao/execute-proposals.go @@ -110,7 +110,7 @@ func (c *oracleDaoExecuteProposalsContext) PrepareData(dataBatch *types.DataBatc data := &dataBatch.Batch[i] state := prop.State.Formatted() data.DoesNotExist = (c.ids[i] > c.dpm.ProposalCount.Formatted()) - data.InvalidState = !(state == rptypes.ProposalState_Pending || state == rptypes.ProposalState_Active) + data.InvalidState = state == rptypes.ProposalState_Pending || state == rptypes.ProposalState_Active data.CanExecute = !(data.DoesNotExist || data.InvalidState) // Get the tx From 3ef24635ed4e6b40146c1022656fa90ddef8e641 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:36:27 -0300 Subject: [PATCH 25/36] Only valid state for execution is if the proposal succeeded --- rocketpool-daemon/api/odao/execute-proposals.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rocketpool-daemon/api/odao/execute-proposals.go b/rocketpool-daemon/api/odao/execute-proposals.go index d6061bb79..e806a315f 100644 --- a/rocketpool-daemon/api/odao/execute-proposals.go +++ b/rocketpool-daemon/api/odao/execute-proposals.go @@ -110,7 +110,7 @@ func (c *oracleDaoExecuteProposalsContext) PrepareData(dataBatch *types.DataBatc data := &dataBatch.Batch[i] state := prop.State.Formatted() data.DoesNotExist = (c.ids[i] > c.dpm.ProposalCount.Formatted()) - data.InvalidState = state == rptypes.ProposalState_Pending || state == rptypes.ProposalState_Active + data.InvalidState = state != rptypes.ProposalState_Succeeded data.CanExecute = !(data.DoesNotExist || data.InvalidState) // Get the tx From 3f47790be7217cb63e992765b69396306525d5da Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:38:13 -0300 Subject: [PATCH 26/36] Add missing patchnotes --- assets/patchnotes/2.0.0-b4.tmpl | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 assets/patchnotes/2.0.0-b4.tmpl diff --git a/assets/patchnotes/2.0.0-b4.tmpl b/assets/patchnotes/2.0.0-b4.tmpl new file mode 100644 index 000000000..ce65c8139 --- /dev/null +++ b/assets/patchnotes/2.0.0-b4.tmpl @@ -0,0 +1,13 @@ +{{.ColorGreen}}=== Smart Node v{{.RocketPoolVersion}} ==={{.ColorReset}} + +Changes you should be aware of before starting: + +{{.ColorGreen}}=== Welcome to the v2.0 Beta! ==={{.ColorReset}} +Welcome to Smart Node v2! This is a completely redesigned Smart Node from the ground up, taking advantage of years of lessons learned and user feedback. The list of features and changes is far too long to list here, but here are some highlights: +- Support for installing and updating via Debian's `apt` package manager (other package managers coming soon!) +- Support for printing transaction data or signed transactions without submitting them to the network +- Passwordless mode: an opt-in feature that will no longer save your node wallet's password to disk +- Overhauled Smart Node service with an HTTP API, support for batching Ethereum queries and transactions together, a new logging system, and consolidation of the api / node / watchtower containers into one +- And much more! + +To learn all about what's changed in Smart Node v2 and how to use it, take a look at our guide: https://github.com/rocket-pool/smartnode/blob/v2/v2.md From fb0c74ed057f77db3c44af9cf3509b9bd006d7ef Mon Sep 17 00:00:00 2001 From: Fornax <23104993+0xfornax@users.noreply.github.com> Date: Wed, 25 Sep 2024 22:45:13 -0300 Subject: [PATCH 27/36] changelog for v2.0.0-b4 --- install/packages/debian/debian/changelog | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/install/packages/debian/debian/changelog b/install/packages/debian/debian/changelog index b05936161..058158c02 100644 --- a/install/packages/debian/debian/changelog +++ b/install/packages/debian/debian/changelog @@ -1,4 +1,17 @@ -rocketpool (2.0.0~b3) UNRELEASED; urgency=medium +rocketpool (2.0.0~b4) unstable; urgency=medium + + * Fixed a bug while rescuing dissolved minipools + * Fixed a bug while setting the RPL withdrawal address + * Updated the initialize voting command to mirror V1's behaviour + * Added a check to handle a case where bond reductions are disabled + * Updated the initialize voting command text + * Updated the node status text to mirror V1 + * Fixed a bug while submitting odao proposals + * Fixed a bug with the odao and security list/detail commands (eg. rocketpool security proposal details or rocketpool odao proposals list) + + -- Rocket Pool Mon, 23 Sep 2024 01:23:54 +0000 + +rocketpool (2.0.0~b3) unstable; urgency=medium * Fixed the `minipool close` issue. * Fixed the client mode logic. From 211851eef8caae7f36f45fa05c674492f9605753 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Wed, 25 Sep 2024 18:01:52 -0700 Subject: [PATCH 28/36] Add warning to stake and deposit, Add getter method to check VotingInitialized --- client/pdao.go | 5 ++ rocketpool-cli/commands/node/deposit.go | 6 ++ rocketpool-cli/commands/node/stake-rpl.go | 8 +- rocketpool-cli/commands/node/utils.go | 23 ++++++ rocketpool-daemon/api/pdao/handler.go | 1 + .../api/pdao/is-voting-initialized.go | 80 +++++++++++++++++++ shared/types/api/pdao.go | 4 + 7 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 rocketpool-daemon/api/pdao/is-voting-initialized.go diff --git a/client/pdao.go b/client/pdao.go index 6b4c3626e..a05f2d091 100644 --- a/client/pdao.go +++ b/client/pdao.go @@ -239,3 +239,8 @@ func (r *PDaoRequester) SetSignallingAddress(signallingAddress common.Address, s func (r *PDaoRequester) ClearSignallingAddress() (*types.ApiResponse[types.TxInfoData], error) { return client.SendGetRequest[types.TxInfoData](r, "clear-signalling-address", "ClearSignallingAddress", nil) } + +// IsVotingInitialized checks if a node has initialized voting power +func (r *PDaoRequester) IsVotingInitialized() (*types.ApiResponse[api.ProtocolDaoIsVotingInitializedData], error) { + return client.SendGetRequest[api.ProtocolDaoIsVotingInitializedData](r, "is-voting-initialized", "IsVotingInitialized", nil) +} diff --git a/rocketpool-cli/commands/node/deposit.go b/rocketpool-cli/commands/node/deposit.go index f15762906..93650caa2 100644 --- a/rocketpool-cli/commands/node/deposit.go +++ b/rocketpool-cli/commands/node/deposit.go @@ -23,6 +23,7 @@ const ( maxSlippageFlag string = "max-slippage" saltFlag string = "salt" defaultMaxNodeFeeSlippage float64 = 0.01 // 1% below current network fee + depositWarningMessage string = "NOTE: by creating a new minipool, your node will automatically initialize voting power to itself. If you would like to delegate your on-chain voting power, you should run the command `rocketpool pdao initialize-voting` before creating a new minipool." ) type deposit struct { @@ -44,6 +45,11 @@ func newDepositPrompts(c *cli.Context, rp *client.Client, soloConversionPubkey * return nil, nil } + err = warnIfVotingUninitialized(rp, c, depositWarningMessage) + if err != nil { + return nil, err + } + // Check if the fee distributor has been initialized feeDistributorResponse, err := rp.Api.Node.InitializeFeeDistributor() if err != nil { diff --git a/rocketpool-cli/commands/node/stake-rpl.go b/rocketpool-cli/commands/node/stake-rpl.go index 9b1be902c..793dd73e9 100644 --- a/rocketpool-cli/commands/node/stake-rpl.go +++ b/rocketpool-cli/commands/node/stake-rpl.go @@ -17,7 +17,8 @@ import ( ) const ( - swapFlag string = "swap" + swapFlag string = "swap" + stakeRPLWarningMessage string = "NOTE: by staking RPL, your node will automatically initialize voting power to itself. If you would like to delegate your on-chain voting power, you should run the command `rocketpool pdao initialize-voting` before staking RPL." ) func nodeStakeRpl(c *cli.Context) error { @@ -33,6 +34,11 @@ func nodeStakeRpl(c *cli.Context) error { return err } + err = warnIfVotingUninitialized(rp, c, stakeRPLWarningMessage) + if err != nil { + return err + } + // If a custom nonce is set, print the multi-transaction warning if rp.Context.Nonce.Cmp(common.Big0) > 0 { utils.PrintMultiTransactionNonceWarning() diff --git a/rocketpool-cli/commands/node/utils.go b/rocketpool-cli/commands/node/utils.go index 51bbecb36..ab5abe720 100644 --- a/rocketpool-cli/commands/node/utils.go +++ b/rocketpool-cli/commands/node/utils.go @@ -21,6 +21,7 @@ import ( "github.com/rocket-pool/node-manager-core/utils/math" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils" + "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/terminal" "github.com/rocket-pool/smartnode/v2/rocketpool-cli/utils/tx" ) @@ -380,3 +381,25 @@ func SwapRpl(c *cli.Context, rp *client.Client, amountWei *big.Int) error { fmt.Printf("Successfully swapped %.6f legacy RPL for new RPL.\n", math.RoundDown(eth.WeiToEth(amountWei), 6)) return nil } + +// Display a warning if hotfix is live and voting is uninitialized +func warnIfVotingUninitialized(rp *client.Client, c *cli.Context, warningMessage string) error { + // TODO check if houston hotfix is deployed + + // Check if voting is initialized + votingInitializedResponse, err := rp.Api.PDao.IsVotingInitialized() + if err != nil { + return err + } + + if !votingInitializedResponse.Data.VotingInitialized { + fmt.Println("Your voting power hasn't been initialized yet. Please visit https://docs.rocketpool.net/guides/houston/participate#initializing-voting to learn more.") + // Post a warning about initializing voting + if !(c.Bool("yes") || utils.Confirm(fmt.Sprintf("%s%s%s\nWould you like to continue?", terminal.ColorYellow, warningMessage, terminal.ColorReset))) { + fmt.Println("Cancelled.") + return fmt.Errorf("operation cancelled by user") + } + } + + return nil +} diff --git a/rocketpool-daemon/api/pdao/handler.go b/rocketpool-daemon/api/pdao/handler.go index dccada70b..0f720a162 100644 --- a/rocketpool-daemon/api/pdao/handler.go +++ b/rocketpool-daemon/api/pdao/handler.go @@ -50,6 +50,7 @@ func NewProtocolDaoHandler(logger *log.Logger, ctx context.Context, serviceProvi &protocolDaoGetStatusContextFactory{h}, &protocolDaoClearSignallingAddressFactory{h}, &protocolDaoSetSignallingAddressFactory{h}, + &protocolDaoIsVotingInitializedContextFactory{h}, } return h } diff --git a/rocketpool-daemon/api/pdao/is-voting-initialized.go b/rocketpool-daemon/api/pdao/is-voting-initialized.go new file mode 100644 index 000000000..04b9d49b8 --- /dev/null +++ b/rocketpool-daemon/api/pdao/is-voting-initialized.go @@ -0,0 +1,80 @@ +package pdao + +import ( + "fmt" + "net/url" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/gorilla/mux" + batch "github.com/rocket-pool/batch-query" + "github.com/rocket-pool/node-manager-core/eth" + "github.com/rocket-pool/rocketpool-go/v2/node" + "github.com/rocket-pool/rocketpool-go/v2/rocketpool" + + "github.com/rocket-pool/node-manager-core/api/server" + "github.com/rocket-pool/node-manager-core/api/types" + "github.com/rocket-pool/smartnode/v2/shared/types/api" +) + +// =============== +// === Factory === +// =============== + +type protocolDaoIsVotingInitializedContextFactory struct { + handler *ProtocolDaoHandler +} + +func (f *protocolDaoIsVotingInitializedContextFactory) Create(args url.Values) (*protocolDaoIsVotingInitializedContext, error) { + c := &protocolDaoIsVotingInitializedContext{ + handler: f.handler, + } + return c, nil +} + +func (f *protocolDaoIsVotingInitializedContextFactory) RegisterRoute(router *mux.Router) { + server.RegisterSingleStageRoute[*protocolDaoIsVotingInitializedContext, api.ProtocolDaoIsVotingInitializedData]( + router, "is-voting-initialized", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, + ) +} + +// =============== +// === Context === +// =============== + +type protocolDaoIsVotingInitializedContext struct { + handler *ProtocolDaoHandler + rp *rocketpool.RocketPool + + node *node.Node +} + +func (c *protocolDaoIsVotingInitializedContext) Initialize() (types.ResponseStatus, error) { + sp := c.handler.serviceProvider + c.rp = sp.GetRocketPool() + nodeAddress, _ := sp.GetWallet().GetAddress() + + // Requirements + status, err := sp.RequireNodeRegistered(c.handler.ctx) + if err != nil { + return status, err + } + + // Bindings + c.node, err = node.NewNode(c.rp, nodeAddress) + if err != nil { + return types.ResponseStatus_Error, fmt.Errorf("error creating node %s binding: %w", nodeAddress.Hex(), err) + } + return types.ResponseStatus_Success, nil +} + +func (c *protocolDaoIsVotingInitializedContext) GetState(mc *batch.MultiCaller) { + eth.AddQueryablesToMulticall(mc, + c.node.IsVotingInitialized, + ) +} + +func (c *protocolDaoIsVotingInitializedContext) PrepareData(data *api.ProtocolDaoIsVotingInitializedData, opts *bind.TransactOpts) (types.ResponseStatus, error) { + data.VotingInitialized = c.node.IsVotingInitialized.Get() + + return types.ResponseStatus_Success, nil +} diff --git a/shared/types/api/pdao.go b/shared/types/api/pdao.go index 7d5b28774..d8bc78dda 100644 --- a/shared/types/api/pdao.go +++ b/shared/types/api/pdao.go @@ -325,3 +325,7 @@ type SnapshotResponseData struct { Error string `json:"error"` ActiveSnapshotProposals []*sharedtypes.SnapshotProposal `json:"activeSnapshotProposals"` } + +type ProtocolDaoIsVotingInitializedData struct { + VotingInitialized bool `json:"votingInitialized"` +} From 87a489ac36d6d0c7237e91ed3c406630e19105de Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Wed, 25 Sep 2024 23:47:15 -0700 Subject: [PATCH 29/36] Add update check for Houston Hotfix 1.3.1 --- client/network.go | 5 ++ rocketpool-cli/commands/node/deposit.go | 1 + rocketpool-cli/commands/node/stake-rpl.go | 1 + rocketpool-cli/commands/node/utils.go | 24 ++++--- rocketpool-daemon/api/network/handler.go | 1 + .../api/network/is-hotfix-deployed.go | 62 +++++++++++++++++++ .../common/state/update-checks.go | 10 +++ shared/types/api/network.go | 4 ++ 8 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 rocketpool-daemon/api/network/is-hotfix-deployed.go diff --git a/client/network.go b/client/network.go index 7f12278b6..9e2a692cc 100644 --- a/client/network.go +++ b/client/network.go @@ -90,3 +90,8 @@ func (r *NetworkRequester) Stats() (*types.ApiResponse[api.NetworkStatsData], er func (r *NetworkRequester) TimezoneMap() (*types.ApiResponse[api.NetworkTimezonesData], error) { return client.SendGetRequest[api.NetworkTimezonesData](r, "timezone-map", "TimezoneMap", nil) } + +// Get the timezone map +func (r *NetworkRequester) IsHoustonHotfixDeployed() (*types.ApiResponse[api.NetworkHotfixDeployedData], error) { + return client.SendGetRequest[api.NetworkHotfixDeployedData](r, "is-hotfix-deployed", "IsHoustonHotfixDeployed", nil) +} diff --git a/rocketpool-cli/commands/node/deposit.go b/rocketpool-cli/commands/node/deposit.go index 93650caa2..3b363f110 100644 --- a/rocketpool-cli/commands/node/deposit.go +++ b/rocketpool-cli/commands/node/deposit.go @@ -45,6 +45,7 @@ func newDepositPrompts(c *cli.Context, rp *client.Client, soloConversionPubkey * return nil, nil } + // If hotfix is live and voting isn't initialized, display a warning err = warnIfVotingUninitialized(rp, c, depositWarningMessage) if err != nil { return nil, err diff --git a/rocketpool-cli/commands/node/stake-rpl.go b/rocketpool-cli/commands/node/stake-rpl.go index 793dd73e9..b5f78d4c0 100644 --- a/rocketpool-cli/commands/node/stake-rpl.go +++ b/rocketpool-cli/commands/node/stake-rpl.go @@ -34,6 +34,7 @@ func nodeStakeRpl(c *cli.Context) error { return err } + // If hotfix is live and voting isn't initialized, display a warning err = warnIfVotingUninitialized(rp, c, stakeRPLWarningMessage) if err != nil { return err diff --git a/rocketpool-cli/commands/node/utils.go b/rocketpool-cli/commands/node/utils.go index ab5abe720..0e3ec2b4c 100644 --- a/rocketpool-cli/commands/node/utils.go +++ b/rocketpool-cli/commands/node/utils.go @@ -384,20 +384,24 @@ func SwapRpl(c *cli.Context, rp *client.Client, amountWei *big.Int) error { // Display a warning if hotfix is live and voting is uninitialized func warnIfVotingUninitialized(rp *client.Client, c *cli.Context, warningMessage string) error { - // TODO check if houston hotfix is deployed - - // Check if voting is initialized - votingInitializedResponse, err := rp.Api.PDao.IsVotingInitialized() + hotfix, err := rp.Api.Network.IsHoustonHotfixDeployed() if err != nil { return err } - if !votingInitializedResponse.Data.VotingInitialized { - fmt.Println("Your voting power hasn't been initialized yet. Please visit https://docs.rocketpool.net/guides/houston/participate#initializing-voting to learn more.") - // Post a warning about initializing voting - if !(c.Bool("yes") || utils.Confirm(fmt.Sprintf("%s%s%s\nWould you like to continue?", terminal.ColorYellow, warningMessage, terminal.ColorReset))) { - fmt.Println("Cancelled.") - return fmt.Errorf("operation cancelled by user") + if hotfix.Data.IsHoustonHotfixDeployed { + // Check if voting is initialized + votingInitializedResponse, err := rp.Api.PDao.IsVotingInitialized() + if err != nil { + return fmt.Errorf("error checking if voting is initialized: %w", err) + } + if !votingInitializedResponse.Data.VotingInitialized { + fmt.Println("Your voting power hasn't been initialized yet. Please visit https://docs.rocketpool.net/guides/houston/participate#initializing-voting to learn more.") + // Post a warning about initializing voting + if !(c.Bool("yes") || utils.Confirm(fmt.Sprintf("%s%s%s\nWould you like to continue?", terminal.ColorYellow, warningMessage, terminal.ColorReset))) { + fmt.Println("Cancelled.") + return fmt.Errorf("operation cancelled by user") + } } } diff --git a/rocketpool-daemon/api/network/handler.go b/rocketpool-daemon/api/network/handler.go index 2c1a41716..2417944d6 100644 --- a/rocketpool-daemon/api/network/handler.go +++ b/rocketpool-daemon/api/network/handler.go @@ -34,6 +34,7 @@ func NewNetworkHandler(logger *log.Logger, ctx context.Context, serviceProvider &networkPriceContextFactory{h}, &networkStatsContextFactory{h}, &networkTimezoneContextFactory{h}, + &networkHotfixDeployedContextFactory{h}, } return h } diff --git a/rocketpool-daemon/api/network/is-hotfix-deployed.go b/rocketpool-daemon/api/network/is-hotfix-deployed.go new file mode 100644 index 000000000..701f19866 --- /dev/null +++ b/rocketpool-daemon/api/network/is-hotfix-deployed.go @@ -0,0 +1,62 @@ +package network + +import ( + "fmt" + "net/url" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/gorilla/mux" + "github.com/rocket-pool/node-manager-core/api/server" + "github.com/rocket-pool/node-manager-core/api/types" + "github.com/rocket-pool/smartnode/v2/rocketpool-daemon/common/state" + "github.com/rocket-pool/smartnode/v2/shared/types/api" +) + +// =============== +// === Factory === +// =============== + +type networkHotfixDeployedContextFactory struct { + handler *NetworkHandler +} + +func (f *networkHotfixDeployedContextFactory) Create(args url.Values) (*networkHotfixDeployedContext, error) { + c := &networkHotfixDeployedContext{ + handler: f.handler, + } + return c, nil +} + +func (f *networkHotfixDeployedContextFactory) RegisterRoute(router *mux.Router) { + server.RegisterQuerylessGet[*networkHotfixDeployedContext, api.NetworkHotfixDeployedData]( + router, "is-hotfix-deployed", f, f.handler.logger.Logger, f.handler.serviceProvider.ServiceProvider, + ) +} + +// =============== +// === Context === +// =============== + +type networkHotfixDeployedContext struct { + handler *NetworkHandler +} + +func (c *networkHotfixDeployedContext) PrepareData(data *api.NetworkHotfixDeployedData, opts *bind.TransactOpts) (types.ResponseStatus, error) { + sp := c.handler.serviceProvider + rp := sp.GetRocketPool() + + // Requirements + status, err := sp.RequireRocketPoolContracts(c.handler.ctx) + if err != nil { + return status, err + } + + // Bindings + houstonHotfixDeployed, err := state.IsHoustonHotfixDeployed(rp, nil) + if err != nil { + return types.ResponseStatus_Error, fmt.Errorf("error getting the protocol version: %w", err) + } + data.IsHoustonHotfixDeployed = houstonHotfixDeployed + + return types.ResponseStatus_Success, nil +} diff --git a/rocketpool-daemon/common/state/update-checks.go b/rocketpool-daemon/common/state/update-checks.go index a0f869345..681144dfa 100644 --- a/rocketpool-daemon/common/state/update-checks.go +++ b/rocketpool-daemon/common/state/update-checks.go @@ -38,3 +38,13 @@ func IsHoustonDeployed(rp *rocketpool.RocketPool, opts *bind.CallOpts) (bool, er constraint, _ := version.NewConstraint(">= 1.3.0") return constraint.Check(currentVersion), nil } + +// Check if Houston Hotfix has been deployed +func IsHoustonHotfixDeployed(rp *rocketpool.RocketPool, opts *bind.CallOpts) (bool, error) { + currentVersion, err := rp.GetProtocolVersion(opts) + if err != nil { + return false, err + } + constraint, _ := version.NewConstraint(">= 1.3.1") + return constraint.Check(currentVersion), nil +} diff --git a/shared/types/api/network.go b/shared/types/api/network.go index 44e077d30..e04702b99 100644 --- a/shared/types/api/network.go +++ b/shared/types/api/network.go @@ -102,3 +102,7 @@ func (ndcid *NetworkDepositContractInfoData) PrintMismatch() bool { fmt.Printf("\tYour Beacon client is using deposit contract %s on chain %d.%s\n", ndcid.BeaconDepositContract.Hex(), ndcid.BeaconNetwork, terminal.ColorReset) return true } + +type NetworkHotfixDeployedData struct { + IsHoustonHotfixDeployed bool `json:"isHoustonHotfixDeployed"` +} From 171c72cb284240fcf0fdf9757724a20f25c16b5e Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 30 Sep 2024 23:33:10 -0700 Subject: [PATCH 30/36] Consolidate fields, handle the priofee > maxfee case in task loop --- rocketpool-daemon/node/defend-pdao-props.go | 25 +++---- .../node/distribute-minipools.go | 31 +++++---- rocketpool-daemon/node/node.go | 26 +++++++ rocketpool-daemon/node/promote-minipools.go | 50 +++++++------- rocketpool-daemon/node/reduce-bonds.go | 68 +++++++++---------- .../node/stake-prelaunch-minipools.go | 62 +++++++++-------- rocketpool-daemon/node/verify-pdao-props.go | 41 +++++------ 7 files changed, 169 insertions(+), 134 deletions(-) diff --git a/rocketpool-daemon/node/defend-pdao-props.go b/rocketpool-daemon/node/defend-pdao-props.go index 242098d0b..9235e59d3 100644 --- a/rocketpool-daemon/node/defend-pdao-props.go +++ b/rocketpool-daemon/node/defend-pdao-props.go @@ -39,9 +39,7 @@ type DefendPdaoProps struct { rp *rocketpool.RocketPool bc beacon.IBeaconClient rs *config.RocketPoolResources - gasThreshold float64 - maxFee *big.Int - maxPriorityFee *big.Int + gasSettings *GasSettings gasLimit uint64 nodeAddress common.Address propMgr *proposals.ProposalManager @@ -56,6 +54,12 @@ func NewDefendPdaoProps(ctx context.Context, sp *services.ServiceProvider, logge cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Defend PDAO Proposals")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) + gasSettings := &GasSettings{ + maxFee: maxFee, + maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + return &DefendPdaoProps{ ctx: ctx, sp: sp, @@ -65,9 +69,7 @@ func NewDefendPdaoProps(ctx context.Context, sp *services.ServiceProvider, logge rp: sp.GetRocketPool(), bc: sp.GetBeaconClient(), rs: cfg.GetRocketPoolResources(), - gasThreshold: cfg.AutoTxGasThreshold.Value, - maxFee: maxFee, - maxPriorityFee: maxPriorityFee, + gasSettings: gasSettings, lastScannedBlock: nil, intervalSize: big.NewInt(int64(config.EventLogInterval)), } @@ -226,21 +228,20 @@ func (t *DefendPdaoProps) defendProposal(prop defendableProposal) error { } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return err } } // Print the gas info - if !gas.PrintAndCheckGasInfo(txInfo.SimulationResult, true, t.gasThreshold, t.logger, maxFee, t.gasLimit) { + if !gas.PrintAndCheckGasInfo(txInfo.SimulationResult, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee, t.gasLimit) { t.logger.Warn("NOTICE: Challenge responses bypass the automatic TX gas threshold, responding for safety.") } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) opts.GasLimit = txInfo.SimulationResult.SafeGasLimit // Print TX info and wait for it to be included in a block diff --git a/rocketpool-daemon/node/distribute-minipools.go b/rocketpool-daemon/node/distribute-minipools.go index 382bc75f4..d565547f1 100644 --- a/rocketpool-daemon/node/distribute-minipools.go +++ b/rocketpool-daemon/node/distribute-minipools.go @@ -36,11 +36,9 @@ type DistributeMinipools struct { bc beacon.IBeaconClient d *client.Client mpMgr *minipool.MinipoolManager - gasThreshold float64 distributeThreshold *big.Int eight *big.Int - maxFee *big.Int - maxPriorityFee *big.Int + gasSettings *GasSettings } // Create distribute minipools task @@ -48,9 +46,14 @@ func NewDistributeMinipools(sp *services.ServiceProvider, logger *log.Logger) *D cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Distribute Minipools")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) - gasThreshold := cfg.AutoTxGasThreshold.Value - if gasThreshold == 0 { + gasSettings := &GasSettings{ + maxFee: maxFee, + maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + + if gasSettings.gasThreshold == 0 { logger.Info("Automatic tx gas threshold is 0, disabling auto-distribute.") } @@ -74,10 +77,8 @@ func NewDistributeMinipools(sp *services.ServiceProvider, logger *log.Logger) *D rp: sp.GetRocketPool(), bc: sp.GetBeaconClient(), d: sp.GetDocker().(*client.Client), - gasThreshold: gasThreshold, distributeThreshold: distributeThreshold, - maxFee: maxFee, - maxPriorityFee: maxPriorityFee, + gasSettings: gasSettings, eight: eth.EthToWei(8), } } @@ -85,7 +86,7 @@ func NewDistributeMinipools(sp *services.ServiceProvider, logger *log.Logger) *D // Distribute minipools func (t *DistributeMinipools) Run(state *state.NetworkState) error { // Check if auto-distributing is disabled - if t.gasThreshold == 0 { + if t.gasSettings.gasThreshold == 0 { return nil } @@ -201,18 +202,18 @@ func (t *DistributeMinipools) distributeMinipools(submissions []*eth.Transaction } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return err } } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) // Print the gas info - if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasThreshold, t.logger, maxFee) { + if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee) { return nil } diff --git a/rocketpool-daemon/node/node.go b/rocketpool-daemon/node/node.go index 0242dcc88..2ebc1481a 100644 --- a/rocketpool-daemon/node/node.go +++ b/rocketpool-daemon/node/node.go @@ -88,6 +88,12 @@ type TaskLoop struct { secondsDelta float64 } +type GasSettings struct { + maxFee *big.Int + maxPriorityFee *big.Int + gasThreshold float64 +} + func NewTaskLoop(sp *services.ServiceProvider, wg *sync.WaitGroup) *TaskLoop { logger := sp.GetTasksLogger() ctx := logger.CreateContextWithLogger(sp.GetBaseContext()) @@ -465,3 +471,23 @@ func calculateTotalEffectiveStakeForNetwork(state *state.NetworkState) *big.Int } return total } + +// Applies GasFeeCap and GasTipCap to opts and handles a case where the user-inputted maxPriorityFee is greater than the oracle based maxFee +// If so, maxPriorityFee is appplied to opts as the min(maxPriorityFee, 25% of the oracle based maxFee) +func (g *GasSettings) ApplyTo(opts *bind.TransactOpts) *bind.TransactOpts { + opts.GasFeeCap = g.maxFee + // If maxPriorityFee < maxFee, apply maxPriorityFee to opts + if g.maxPriorityFee.Cmp(g.maxFee) < 0 { + opts.GasTipCap = g.maxPriorityFee + return opts + } + quarterMaxFee := new(big.Int).Div(g.maxFee, big.NewInt(4)) + // Otherwise apply maxPriorityFee to opts as min(priorityFee, 25% of the oracle based maxFee) + if g.maxPriorityFee.Cmp(quarterMaxFee) < 0 { + opts.GasTipCap = g.maxPriorityFee + } else { + opts.GasTipCap = quarterMaxFee + } + return opts + +} diff --git a/rocketpool-daemon/node/promote-minipools.go b/rocketpool-daemon/node/promote-minipools.go index 4d88192b3..d0f8580bd 100644 --- a/rocketpool-daemon/node/promote-minipools.go +++ b/rocketpool-daemon/node/promote-minipools.go @@ -27,16 +27,14 @@ import ( // Promote minipools task type PromoteMinipools struct { - sp *services.ServiceProvider - logger *slog.Logger - alerter *alerting.Alerter - cfg *config.SmartNodeConfig - w *wallet.Wallet - rp *rocketpool.RocketPool - mpMgr *minipool.MinipoolManager - gasThreshold float64 - maxFee *big.Int - maxPriorityFee *big.Int + sp *services.ServiceProvider + logger *slog.Logger + alerter *alerting.Alerter + cfg *config.SmartNodeConfig + w *wallet.Wallet + rp *rocketpool.RocketPool + mpMgr *minipool.MinipoolManager + gasSettings *GasSettings } // Create promote minipools task @@ -44,16 +42,20 @@ func NewPromoteMinipools(sp *services.ServiceProvider, logger *log.Logger) *Prom cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Promote Minipools")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) - return &PromoteMinipools{ - sp: sp, - logger: log, - alerter: alerting.NewAlerter(cfg, logger), - cfg: cfg, - w: sp.GetWallet(), - rp: sp.GetRocketPool(), - gasThreshold: cfg.AutoTxGasThreshold.Value, + gasSettings := &GasSettings{ maxFee: maxFee, maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + + return &PromoteMinipools{ + sp: sp, + logger: log, + alerter: alerting.NewAlerter(cfg, logger), + cfg: cfg, + w: sp.GetWallet(), + rp: sp.GetRocketPool(), + gasSettings: gasSettings, } } @@ -179,19 +181,19 @@ func (t *PromoteMinipools) promoteMinipools(submissions []*eth.TransactionSubmis } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return err } } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) // Print the gas info forceSubmissions := []*eth.TransactionSubmission{} - if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasThreshold, t.logger, maxFee) { + if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee) { // Check for the timeout buffers for i, mpd := range minipools { creationTime := time.Unix(mpd.StatusTime.Int64(), 0) diff --git a/rocketpool-daemon/node/reduce-bonds.go b/rocketpool-daemon/node/reduce-bonds.go index 319c4fde5..086630578 100644 --- a/rocketpool-daemon/node/reduce-bonds.go +++ b/rocketpool-daemon/node/reduce-bonds.go @@ -35,16 +35,14 @@ const ( // Reduce bonds task type ReduceBonds struct { - sp *services.ServiceProvider - logger *slog.Logger - alerter *alerting.Alerter - cfg *config.SmartNodeConfig - w *wallet.Wallet - rp *rocketpool.RocketPool - mpMgr *minipool.MinipoolManager - gasThreshold float64 - maxFee *big.Int - maxPriorityFee *big.Int + sp *services.ServiceProvider + logger *slog.Logger + alerter *alerting.Alerter + cfg *config.SmartNodeConfig + w *wallet.Wallet + rp *rocketpool.RocketPool + mpMgr *minipool.MinipoolManager + gasSettings *GasSettings } // Create reduce bonds task @@ -52,29 +50,32 @@ func NewReduceBonds(sp *services.ServiceProvider, logger *log.Logger) *ReduceBon cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Reduce Bonds")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) - gasThreshold := cfg.AutoTxGasThreshold.Value - if gasThreshold == 0 { + gasSettings := &GasSettings{ + maxFee: maxFee, + maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + + if gasSettings.gasThreshold == 0 { log.Info("Automatic tx gas threshold is 0, disabling auto-reduce.") } return &ReduceBonds{ - sp: sp, - logger: log, - alerter: alerting.NewAlerter(cfg, logger), - cfg: cfg, - w: sp.GetWallet(), - rp: sp.GetRocketPool(), - gasThreshold: gasThreshold, - maxFee: maxFee, - maxPriorityFee: maxPriorityFee, + sp: sp, + logger: log, + alerter: alerting.NewAlerter(cfg, logger), + cfg: cfg, + w: sp.GetWallet(), + rp: sp.GetRocketPool(), + gasSettings: gasSettings, } } // Reduce bonds func (t *ReduceBonds) Run(state *state.NetworkState) error { // Check if auto-bond-reduction is disabled - if t.gasThreshold == 0 { + if t.gasSettings.gasThreshold == 0 { return nil } @@ -212,21 +213,20 @@ func (t *ReduceBonds) forceFeeDistribution(state *state.NetworkState) (bool, err } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return false, err } } // Print the gas info - if !gas.PrintAndCheckGasInfo(txInfo.SimulationResult, true, t.gasThreshold, t.logger, maxFee, txInfo.SimulationResult.SafeGasLimit) { + if !gas.PrintAndCheckGasInfo(txInfo.SimulationResult, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee, txInfo.SimulationResult.SafeGasLimit) { return false, nil } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) opts.GasLimit = txInfo.SimulationResult.SafeGasLimit // Print TX info and wait for it to be included in a block @@ -342,18 +342,18 @@ func (t *ReduceBonds) reduceBonds(submissions []*eth.TransactionSubmission, mini } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return err } } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) // Print the gas info - if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasThreshold, t.logger, maxFee) { + if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee) { for _, mp := range minipools { timeSinceReductionStart := latestBlockTime.Sub(mp.ReduceBondTime.Formatted()) remainingTime := windowDuration - timeSinceReductionStart diff --git a/rocketpool-daemon/node/stake-prelaunch-minipools.go b/rocketpool-daemon/node/stake-prelaunch-minipools.go index a6856396b..64fafa51c 100644 --- a/rocketpool-daemon/node/stake-prelaunch-minipools.go +++ b/rocketpool-daemon/node/stake-prelaunch-minipools.go @@ -31,19 +31,17 @@ import ( // Stake prelaunch minipools task type StakePrelaunchMinipools struct { - sp *services.ServiceProvider - logger *slog.Logger - alerter *alerting.Alerter - cfg *config.SmartNodeConfig - w *wallet.Wallet - vMgr *validator.ValidatorManager - rp *rocketpool.RocketPool - bc beacon.IBeaconClient - d *client.Client - mpMgr *minipool.MinipoolManager - gasThreshold float64 - maxFee *big.Int - maxPriorityFee *big.Int + sp *services.ServiceProvider + logger *slog.Logger + alerter *alerting.Alerter + cfg *config.SmartNodeConfig + w *wallet.Wallet + vMgr *validator.ValidatorManager + rp *rocketpool.RocketPool + bc beacon.IBeaconClient + d *client.Client + mpMgr *minipool.MinipoolManager + gasSettings *GasSettings } // Create stake prelaunch minipools task @@ -51,19 +49,23 @@ func NewStakePrelaunchMinipools(sp *services.ServiceProvider, logger *log.Logger cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Prelaunch Stake")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) - return &StakePrelaunchMinipools{ - sp: sp, - logger: log, - alerter: alerting.NewAlerter(cfg, logger), - cfg: sp.GetConfig(), - w: sp.GetWallet(), - vMgr: sp.GetValidatorManager(), - rp: sp.GetRocketPool(), - bc: sp.GetBeaconClient(), - d: sp.GetDocker().(*client.Client), - gasThreshold: cfg.AutoTxGasThreshold.Value, + gasSettings := &GasSettings{ maxFee: maxFee, maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + + return &StakePrelaunchMinipools{ + sp: sp, + logger: log, + alerter: alerting.NewAlerter(cfg, logger), + cfg: sp.GetConfig(), + w: sp.GetWallet(), + vMgr: sp.GetValidatorManager(), + rp: sp.GetRocketPool(), + bc: sp.GetBeaconClient(), + d: sp.GetDocker().(*client.Client), + gasSettings: gasSettings, } } @@ -230,20 +232,20 @@ func (t *StakePrelaunchMinipools) stakeMinipools(submissions []*eth.TransactionS } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return false, err } } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) // Print the gas info forceSubmissions := []*eth.TransactionSubmission{} forceMinipools := []*rpstate.NativeMinipoolDetails{} - if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasThreshold, t.logger, maxFee) { + if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee) { // Check for the timeout buffers for i, mpd := range minipools { prelaunchTime := time.Unix(mpd.StatusTime.Int64(), 0) diff --git a/rocketpool-daemon/node/verify-pdao-props.go b/rocketpool-daemon/node/verify-pdao-props.go index 776b9cba1..d0432f71a 100644 --- a/rocketpool-daemon/node/verify-pdao-props.go +++ b/rocketpool-daemon/node/verify-pdao-props.go @@ -39,16 +39,15 @@ type defeat struct { } type VerifyPdaoProps 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 + ctx context.Context + sp *services.ServiceProvider + logger *slog.Logger + cfg *config.SmartNodeConfig + w *wallet.Wallet + rp *rocketpool.RocketPool + bc beacon.IBeaconClient + // gasThreshold float64 + gasSettings *GasSettings nodeAddress common.Address propMgr *proposals.ProposalManager pdaoMgr *protocol.ProtocolDaoManager @@ -64,6 +63,12 @@ func NewVerifyPdaoProps(ctx context.Context, sp *services.ServiceProvider, logge cfg := sp.GetConfig() log := logger.With(slog.String(keys.TaskKey, "Verify PDAO Proposals")) maxFee, maxPriorityFee := getAutoTxInfo(cfg, log) + gasSettings := &GasSettings{ + maxFee: maxFee, + maxPriorityFee: maxPriorityFee, + gasThreshold: cfg.AutoTxGasThreshold.Value, + } + return &VerifyPdaoProps{ ctx: ctx, sp: sp, @@ -72,9 +77,7 @@ func NewVerifyPdaoProps(ctx context.Context, sp *services.ServiceProvider, logge w: sp.GetWallet(), rp: sp.GetRocketPool(), bc: sp.GetBeaconClient(), - gasThreshold: cfg.AutoTxGasThreshold.Value, - maxFee: maxFee, - maxPriorityFee: maxPriorityFee, + gasSettings: gasSettings, lastScannedBlock: nil, intervalSize: big.NewInt(int64(config.EventLogInterval)), validPropCache: map[uint64]bool{}, @@ -402,18 +405,18 @@ func (t *VerifyPdaoProps) submitTxs(submissions []*eth.TransactionSubmission) er } // Get the max fee - maxFee := t.maxFee - if maxFee == nil || maxFee.Uint64() == 0 { - maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) + if t.gasSettings.maxFee == nil || t.gasSettings.maxFee.Uint64() == 0 { + t.gasSettings.maxFee, err = gas.GetMaxFeeWeiForDaemon(t.logger) if err != nil { return err } } - opts.GasFeeCap = maxFee - opts.GasTipCap = t.maxPriorityFee + + // Set GasFeeCap and GasTipCap + t.gasSettings.ApplyTo(opts) // Print the gas info - if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasThreshold, t.logger, maxFee) { + if !gas.PrintAndCheckGasInfoForBatch(submissions, true, t.gasSettings.gasThreshold, t.logger, t.gasSettings.maxFee) { return nil } From dcc80b1bb1bbcceb9b67ee98f13c126412017527 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Tue, 1 Oct 2024 13:46:37 -0700 Subject: [PATCH 31/36] Add test cases for ApplyTo --- rocketpool-daemon/node/applyto_test.go | 81 ++++++++++++++++++++++++++ rocketpool-daemon/node/node.go | 3 +- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 rocketpool-daemon/node/applyto_test.go diff --git a/rocketpool-daemon/node/applyto_test.go b/rocketpool-daemon/node/applyto_test.go new file mode 100644 index 000000000..2d6c5c373 --- /dev/null +++ b/rocketpool-daemon/node/applyto_test.go @@ -0,0 +1,81 @@ +package node + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" +) + +func TestApplyTo(t *testing.T) { + tests := []struct { + name string + maxPriorityFee *big.Int + maxFee *big.Int + expectedGasFeeCap *big.Int + expectedGasTipCap *big.Int + }{ + { + name: "maxPriorityFee less than maxFee", + maxPriorityFee: big.NewInt(50), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(50), + }, + { + name: "maxPriorityFee equal to maxFee", + maxPriorityFee: big.NewInt(100), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(25), + }, + { + name: "maxPriorityFee greater than maxFee", + maxPriorityFee: big.NewInt(150), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(25), + }, + { + name: "maxPriorityFee less than 25%% of maxFee", + maxPriorityFee: big.NewInt(20), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(20), + }, + { + name: "maxPriorityFee equal to 25%% of maxFee", + maxPriorityFee: big.NewInt(25), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(25), + }, + { + name: "maxPriorityFee less than maxFee but greater than 25%% of maxFee", + maxPriorityFee: big.NewInt(30), + maxFee: big.NewInt(100), + expectedGasFeeCap: big.NewInt(100), + expectedGasTipCap: big.NewInt(30), + }, + } + + for _, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + g := &GasSettings{ + maxFee: testCase.maxFee, + maxPriorityFee: testCase.maxPriorityFee, + } + + opts := &bind.TransactOpts{} + + g.ApplyTo(opts) + + if opts.GasFeeCap.Cmp(testCase.expectedGasFeeCap) != 0 { + t.Errorf("expected GasFeeCap %s, got %s", testCase.expectedGasFeeCap.String(), opts.GasFeeCap.String()) + } + if opts.GasTipCap.Cmp(testCase.expectedGasTipCap) != 0 { + t.Errorf("expected GasTipCap %s, got %s", testCase.expectedGasTipCap.String(), opts.GasTipCap.String()) + } + }) + } +} diff --git a/rocketpool-daemon/node/node.go b/rocketpool-daemon/node/node.go index 2ebc1481a..190c7d87b 100644 --- a/rocketpool-daemon/node/node.go +++ b/rocketpool-daemon/node/node.go @@ -482,7 +482,8 @@ func (g *GasSettings) ApplyTo(opts *bind.TransactOpts) *bind.TransactOpts { return opts } quarterMaxFee := new(big.Int).Div(g.maxFee, big.NewInt(4)) - // Otherwise apply maxPriorityFee to opts as min(priorityFee, 25% of the oracle based maxFee) + + // Otherwise apply maxPriorityFee to opts as min(maxPriorityFee, 25% of the oracle based maxFee) if g.maxPriorityFee.Cmp(quarterMaxFee) < 0 { opts.GasTipCap = g.maxPriorityFee } else { From cd3b049feb0c3c3f89d601e4fe944f4d03cf9c4c Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:02:10 -0300 Subject: [PATCH 32/36] Add devnet signer registry address --- shared/config/resources.go | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/config/resources.go b/shared/config/resources.go index 83e6d0e23..72d4ce3a1 100644 --- a/shared/config/resources.go +++ b/shared/config/resources.go @@ -196,6 +196,7 @@ func newRocketPoolResources(network config.Network) *RocketPoolResources { PreviousRewardsPoolAddresses: []common.Address{ common.HexToAddress("0x4d581a552490fb6fce5F978e66560C8b7E481818"), }, + RocketSignerRegistryAddress: hexToAddressPtr("0x15Da69Dde70998FC045a260f84ad4aB0A2204e76"), PreviousProtocolDaoVerifierAddresses: nil, OptimismPriceMessengerAddress: nil, PolygonPriceMessengerAddress: nil, From d063ac113410f579d8882b646a27115b3552e1e6 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Thu, 3 Oct 2024 15:14:50 -0300 Subject: [PATCH 33/36] Allowing devnet on the betas --- shared/config/smartnode-config.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/shared/config/smartnode-config.go b/shared/config/smartnode-config.go index 86d798bea..1b3c0cf77 100644 --- a/shared/config/smartnode-config.go +++ b/shared/config/smartnode-config.go @@ -6,7 +6,6 @@ import ( "path/filepath" "reflect" "strconv" - "strings" "github.com/alessio/shellescape" "github.com/rocket-pool/node-manager-core/config" @@ -764,17 +763,13 @@ func getNetworkOptions() []*config.ParameterOption[config.Network] { Description: "This is the Holešky (Holešovice) test network, which is the next generation of long-lived testnets for Ethereum. It uses free fake ETH and free fake RPL to make fake validators.\nUse this if you want to practice running the Smart Node in a free, safe environment before moving to Mainnet.", }, Value: config.Network_Holesky, - }, - } - - if strings.HasSuffix(assets.RocketPoolVersion(), "-dev") { - options = append(options, &config.ParameterOption[config.Network]{ + }, { ParameterOptionCommon: &config.ParameterOptionCommon{ Name: "Devnet", Description: "This is a development network used by Rocket Pool engineers to test new features and contract upgrades before they are promoted to a Testnet for staging. You should not use this network unless invited to do so by the developers.", }, Value: Network_Devnet, - }) + }, } return options From ff365e34aa5da9db93fd7526639c0b25ccd3b1f3 Mon Sep 17 00:00:00 2001 From: thomaspanf Date: Mon, 7 Oct 2024 15:11:20 -0700 Subject: [PATCH 34/36] Deprecate service stats --- rocketpool-cli/client/service.go | 17 ----------------- rocketpool-cli/commands/service/commands.go | 6 ++---- rocketpool-cli/commands/service/stats.go | 15 ++++----------- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/rocketpool-cli/client/service.go b/rocketpool-cli/client/service.go index da9471b0d..3e616a004 100644 --- a/rocketpool-cli/client/service.go +++ b/rocketpool-cli/client/service.go @@ -270,23 +270,6 @@ func (c *Client) PrintNodeLogs(composeFiles []string, tail string, logPaths ...s return c.printOutput(cmd) } -// Print the Rocket Pool service stats -func (c *Client) PrintServiceStats(composeFiles []string) error { - // Get service container IDs - cmd, err := c.compose(composeFiles, "ps -q") - if err != nil { - return err - } - containers, err := c.readOutput(cmd) - if err != nil { - return err - } - containerIds := strings.Split(strings.TrimSpace(string(containers)), "\n") - - // Print stats - return c.printOutput(fmt.Sprintf("docker stats %s", strings.Join(containerIds, " "))) -} - // Print the Rocket Pool service compose config func (c *Client) PrintServiceCompose(composeFiles []string) error { cmd, err := c.compose(composeFiles, "config") diff --git a/rocketpool-cli/commands/service/commands.go b/rocketpool-cli/commands/service/commands.go index f57d9745c..f4616261f 100644 --- a/rocketpool-cli/commands/service/commands.go +++ b/rocketpool-cli/commands/service/commands.go @@ -286,13 +286,11 @@ func RegisterCommands(app *cli.App, name string, aliases []string) { { Name: "stats", Aliases: []string{"a"}, - Usage: "View the Rocket Pool service stats", + Usage: "DEPRECATED - No longer supported", Action: func(c *cli.Context) error { - // Validate args - utils.ValidateArgCount(c, 0) // Run command - return serviceStats(c) + return serviceStats() }, }, diff --git a/rocketpool-cli/commands/service/stats.go b/rocketpool-cli/commands/service/stats.go index c510f9284..a6fba56d3 100644 --- a/rocketpool-cli/commands/service/stats.go +++ b/rocketpool-cli/commands/service/stats.go @@ -1,18 +1,11 @@ package service import ( - "github.com/rocket-pool/smartnode/v2/rocketpool-cli/client" - "github.com/urfave/cli/v2" + "fmt" ) // View the Rocket Pool service stats -func serviceStats(c *cli.Context) error { - // Get RP client - rp, err := client.NewClientFromCtx(c) - if err != nil { - return err - } - - // Print service stats - return rp.PrintServiceStats(getComposeFiles(c)) +func serviceStats() error { + fmt.Println("No longer supported - please run `docker stats -a` instead.") + return nil } From f2350b277dcccad8aff5e6085bd7f5140e83e8e0 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:25:29 -0300 Subject: [PATCH 35/36] Fix price/balances submission check. --- rocketpool-daemon/watchtower/submit-network-balances.go | 4 ++-- rocketpool-daemon/watchtower/submit-rpl-price.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rocketpool-daemon/watchtower/submit-network-balances.go b/rocketpool-daemon/watchtower/submit-network-balances.go index 64db327be..31cb68b26 100644 --- a/rocketpool-daemon/watchtower/submit-network-balances.go +++ b/rocketpool-daemon/watchtower/submit-network-balances.go @@ -113,8 +113,8 @@ func (t *SubmitNetworkBalances) Run(state *state.NetworkState) error { } targetBlockNumber := targetBlockHeader.Number.Uint64() - if targetBlockNumber < lastSubmissionBlock { - // No submission needed: target block older or equal to the last submission + if targetBlockNumber > state.ElBlockNumber { + // No submission needed: target block in the future return nil } diff --git a/rocketpool-daemon/watchtower/submit-rpl-price.go b/rocketpool-daemon/watchtower/submit-rpl-price.go index 427557ec0..6047adeaf 100644 --- a/rocketpool-daemon/watchtower/submit-rpl-price.go +++ b/rocketpool-daemon/watchtower/submit-rpl-price.go @@ -102,8 +102,8 @@ func (t *SubmitRplPrice) Run(state *state.NetworkState) error { submissionTimestamp := uint64(nextSubmissionTime.Unix()) targetBlockNumber := targetBlockHeader.Number.Uint64() - if targetBlockNumber < lastSubmissionBlock { - // No submission needed: target block older or equal to the last submission + if targetBlockNumber > state.ElBlockNumber { + // No submission needed: target block in the future return nil } From 3b83c2cfd7f9be09225a0054982cbe15249ac200 Mon Sep 17 00:00:00 2001 From: Fornax <23104993+fornax2@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:19:26 -0300 Subject: [PATCH 36/36] Fix balances last submission block and interval --- go.mod | 2 +- go.sum | 4 ++-- rocketpool-daemon/watchtower/submit-network-balances.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index be5d2e0cf..6bfcddd34 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 88f992faf..631f51e65 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/rocketpool-daemon/watchtower/submit-network-balances.go b/rocketpool-daemon/watchtower/submit-network-balances.go index 31cb68b26..ec3a5cf9a 100644 --- a/rocketpool-daemon/watchtower/submit-network-balances.go +++ b/rocketpool-daemon/watchtower/submit-network-balances.go @@ -100,11 +100,11 @@ func (t *SubmitNetworkBalances) Run(state *state.NetworkState) error { t.logger.Info("Starting network balance check.") // Check the last submission block - lastSubmissionBlock := state.NetworkDetails.PricesBlock + lastSubmissionBlock := state.NetworkDetails.BalancesBlock referenceTimestamp := t.cfg.PriceBalanceSubmissionReferenceTimestamp.Value // Get the duration in seconds for the interval between submissions - submissionIntervalInSeconds := int64(state.NetworkDetails.PricesSubmissionFrequency) + submissionIntervalInSeconds := int64(state.NetworkDetails.BalancesSubmissionFrequency) eth2Config := state.BeaconConfig slotNumber, nextSubmissionTime, targetBlockHeader, err := utils.FindNextSubmissionTarget(t.ctx, t.rp, eth2Config, t.bc, t.ec, lastSubmissionBlock, referenceTimestamp, submissionIntervalInSeconds)