Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion rocketpool-cli/wallet/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) {
Aliases: []string{"a"},
Usage: "Specify an address you'd like you masquerade as",
},
&cli.BoolFlag{
Name: "observe",
Aliases: []string{"o"},
Usage: "Apply masquerade to the node and watchtower loops (requires daemon restart)",
},
},

Action: func(ctx context.Context, c *cli.Command) error {
Expand All @@ -303,7 +308,7 @@ func RegisterCommands(app *cli.Command, name string, aliases []string) {
}

// Run
return masquerade(c.String("address"), c.Bool("yes"))
return masquerade(c.String("address"), c.Bool("yes"), c.Bool("observe"))

},
},
Expand Down
25 changes: 20 additions & 5 deletions rocketpool-cli/wallet/masquerade.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/rocket-pool/smartnode/shared/utils/cli/prompt"
)

func masquerade(addressFlag string, yes bool) error {
func masquerade(addressFlag string, yes bool, observe bool) error {
// Get RP client
rp := rocketpool.NewClient()
defer rp.Close()
Expand All @@ -28,18 +28,33 @@ func masquerade(addressFlag string, yes bool) error {
}

// Prompt for confirmation
if !yes && !prompt.Confirm("Are you sure you want to masquerade as %s?", color.LightBlue(address.Hex())) {
fmt.Println("Cancelled.")
return nil
if observe {
fmt.Println(color.Yellow("Observe mode is enabled. Please read the following carefully:"))
fmt.Println(" - The node and watchtower will use the masquerade address instead of your real node address.")
fmt.Println(" - Your fee recipient will remain set to your real node wallet address")
fmt.Println(" - Run `rocketpool wallet end-masquerade` and restart the node/watchtower daemons when you have finished observing.")
fmt.Println()
if !yes && !prompt.Confirm("I understand the above. Enable observe mode for %s?", color.LightBlue(address.Hex())) {
fmt.Println("Cancelled.")
return nil
}
} else {
if !yes && !prompt.Confirm("Are you sure you want to masquerade as %s?", color.LightBlue(address.Hex())) {
fmt.Println("Cancelled.")
return nil
}
}

// Call API
_, err = rp.Masquerade(address)
_, err = rp.Masquerade(address, observe)
if err != nil {
return fmt.Errorf("error running masquerade: %w", err)
}

fmt.Printf("Your node is now masquerading as address %s.\n", color.LightBlue(address.Hex()))
if observe {
fmt.Println("Restart the node and watchtower daemons to observe as the masquerade address.")
}

return nil
}
14 changes: 12 additions & 2 deletions rocketpool-cli/wallet/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,23 @@ func getStatus() error {
if status.IsMasquerading {
if status.NodeAddress != emptyAddress {
fmt.Printf("The node wallet is initialized, but you are currently masquerading as %s\n", color.LightBlue(status.AccountAddress.Hex()))
fmt.Printf("Wallet Address: %s\n", status.NodeAddress)
fmt.Printf("Wallet Address: %s\n", color.LightBlue(status.NodeAddress.Hex()))
color.YellowPrintln("Due to this mismatch, the node cannot submit transactions. Use the command 'rocketpool wallet end-masquerade' to end masquerading and restore your wallet address.")
} else {
fmt.Printf("The node wallet has not been initialized, but you are currently masquerading as %s\n", color.LightBlue(status.AccountAddress.Hex()))
color.YellowPrintln("The node cannot submit transactions. Use the command 'rocketpool wallet end-masquerade' to end masquerading.")
}
if status.IsObserve {
fmt.Println()
fmt.Printf("The node is in %s, observing address %s.\n", color.Yellow("observe mode"), color.LightBlue(status.AccountAddress.Hex()))
if status.NodeAddress != emptyAddress {
fmt.Printf("Wallet Address (fee recipient): %s\n", color.LightBlue(status.NodeAddress.Hex()))
}
fmt.Println(" - The node and watchtower loops are using the masquerade address.")
fmt.Println(" - Transactions will not be submitted.")
fmt.Println(" - Your fee recipient remains set to your real node wallet address")
color.YellowPrintln("Run 'rocketpool wallet end-masquerade' and restart the node/watchtower daemons when you have finished observing.")
}
} else {
// Not Masquerading
if status.WalletInitialized {
Expand All @@ -56,7 +67,6 @@ func getStatus() error {
}
}

fmt.Println()
return nil

}
30 changes: 26 additions & 4 deletions rocketpool/api/wallet/masquerade.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,43 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v3"

"github.com/rocket-pool/smartnode/bindings/dao/trustednode"
"github.com/rocket-pool/smartnode/shared/services"
"github.com/rocket-pool/smartnode/shared/types/api"
)

func masquerade(c *cli.Command, address common.Address) (*api.MasqueradeResponse, error) {
func masquerade(c *cli.Command, address common.Address, observe bool) (*api.MasqueradeResponse, error) {

// Get services
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}

err = w.MasqueradeAsAddress(address)
if err != nil {
return nil, fmt.Errorf("Error masquerading as address %s", address.Hex())
if observe {
hdw, err := services.GetHdWallet(c)
if err != nil {
return nil, err
}
rp, err := services.GetRocketPool(c)
if err != nil {
return nil, err
}
nodeAccount, err := hdw.GetNodeAccount()
if err != nil {
return nil, err
}
isMember, err := trustednode.GetMemberExists(rp, nodeAccount.Address, nil)
if err != nil {
return nil, fmt.Errorf("error checking Oracle DAO membership: %w", err)
}
if isMember {
return nil, fmt.Errorf("Observe mode is not available for Oracle DAO nodes: oDAO duties would stop running while observing")
}
}

if err := w.MasqueradeAsAddress(address, observe); err != nil {
return nil, fmt.Errorf("error masquerading as address %s: %w", address.Hex(), err)
}

response := api.MasqueradeResponse{}
Expand Down
3 changes: 2 additions & 1 deletion rocketpool/api/wallet/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ func RegisterRoutes(mux *http.ServeMux, c *cli.Command) {

mux.HandleFunc("/api/wallet/masquerade", func(w http.ResponseWriter, r *http.Request) {
address := common.HexToAddress(r.FormValue("address"))
resp, err := masquerade(c, address)
observe := r.FormValue("observe") == "true"
resp, err := masquerade(c, address, observe)
apiutils.WriteResponse(w, resp, err)
})

Expand Down
6 changes: 6 additions & 0 deletions rocketpool/api/wallet/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import (
"github.com/urfave/cli/v3"

"github.com/rocket-pool/smartnode/shared/services"
"github.com/rocket-pool/smartnode/shared/services/wallet"
"github.com/rocket-pool/smartnode/shared/types/api"
)

func getStatus(c *cli.Command) (*api.WalletStatusResponse, error) {

// Get services
cfg, err := services.GetConfig(c)
if err != nil {
return nil, err
}
pm, err := services.GetPasswordManager(c)
if err != nil {
return nil, err
Expand All @@ -24,6 +29,7 @@ func getStatus(c *cli.Command) (*api.WalletStatusResponse, error) {

// Get wallet type
response.IsMasquerading = w.IsNodeMasquerading()
response.IsObserve = wallet.CheckObserveMode(cfg.Smartnode.GetNodeAddressPath())

// Get wallet status
if response.IsMasquerading {
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/defend-pdao-props.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func newDefendPdaoProps(c *cli.Command, logger log.ColorLogger) (*defendPdaoProp
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/distribute-minipools.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func newDistributeMinipools(c *cli.Command, logger log.ColorLogger) (*distribute
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/download-reward-trees.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func newDownloadRewardsTrees(c *cli.Command, logger log.ColorLogger) (*downloadR
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
35 changes: 26 additions & 9 deletions rocketpool/node/manage-fee-recipient.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import (

// Manage fee recipient task
type manageFeeRecipient struct {
c *cli.Command
log log.ColorLogger
cfg *config.RocketPoolConfig
w wallet.Wallet
rp *rocketpool.RocketPool
d *client.Client
bc beacon.Client
c *cli.Command
log log.ColorLogger
cfg *config.RocketPoolConfig
w wallet.Wallet
rp *rocketpool.RocketPool
d *client.Client
bc beacon.Client
stateManager *state.NetworkStateManager
}

// Create manage fee recipient task
Expand Down Expand Up @@ -58,15 +59,17 @@ func newManageFeeRecipient(c *cli.Command, logger log.ColorLogger) (*manageFeeRe
}

// Return task
return &manageFeeRecipient{
task := &manageFeeRecipient{
c: c,
log: logger,
cfg: cfg,
w: w,
rp: rp,
d: d,
bc: bc,
}, nil
}
task.stateManager = state.NewNetworkStateManager(rp, cfg.Smartnode.GetStateManagerContracts(), bc, &task.log)
return task, nil

}

Expand All @@ -87,6 +90,20 @@ func (m *manageFeeRecipient) run(state *state.NetworkState) error {
return err
}

// Fee recipient is always managed for the real node (HD wallet on disk), not the masquerade
// address. In observe mode, the global state is keyed for the masquerade address,
// so fetch a dedicated state for the real node.
am := wallet.NewAddressManager(m.cfg.Smartnode.GetNodeAddressPath())
masqAddress, masqErr := am.LoadAddress()
if masqErr == nil && am.IsObserve() {
m.log.Printlnf("Node is masquerading as %s; fee recipient management always targets the real node (%s) stored on disk.", masqAddress.Hex(), nodeAccount.Address.Hex())
var stateErr error
state, stateErr = m.stateManager.GetHeadStateForNode(nodeAccount.Address)
if stateErr != nil {
return fmt.Errorf("error getting network state for real node %s: %w", nodeAccount.Address.Hex(), stateErr)
}
}

// Get the fee recipient info for the node
feeRecipientInfo, err := rputils.GetFeeRecipientInfo(m.rp, m.bc, nodeAccount.Address, state)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/metrics-exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func runMetricsServer(ctx context.Context, c *cli.Command, logger log.ColorLogge
if err != nil {
return err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return err
}
Expand Down
16 changes: 15 additions & 1 deletion rocketpool/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/rocket-pool/smartnode/shared/services/alerting"
"github.com/rocket-pool/smartnode/shared/services/connectivity"
"github.com/rocket-pool/smartnode/shared/services/state"
"github.com/rocket-pool/smartnode/shared/services/wallet"
"github.com/rocket-pool/smartnode/shared/services/wallet/keystore/lighthouse"
"github.com/rocket-pool/smartnode/shared/services/wallet/keystore/nimbus"
"github.com/rocket-pool/smartnode/shared/services/wallet/keystore/prysm"
Expand Down Expand Up @@ -148,7 +149,13 @@ func run(c *cli.Command) error {
if err != nil {
return err
}
w, err := services.GetHdWallet(c)
isObserveMode := wallet.CheckObserveMode(cfg.Smartnode.GetNodeAddressPath())
var w wallet.Wallet
if isObserveMode {
w, err = services.GetWallet(c)
} else {
w, err = services.GetHdWallet(c)
}
if err != nil {
return err
}
Expand All @@ -169,6 +176,13 @@ func run(c *cli.Command) error {
return fmt.Errorf("error getting node account: %w", err)
}

if isObserveMode {
red := color.New(color.FgHiRed).SprintFunc()
fmt.Println(red("Node daemon is observing address " + nodeAccount.Address.Hex() + "."))
fmt.Println(red("Transactions will not be submitted. Fee recipient management targets your real node address."))
fmt.Println(red("Run `rocketpool wallet end-masquerade` and restart the node/watchtower daemons when you have finished observing."))
}

// Initialize loggers
errorLog := log.NewColorLogger(ErrorColor)
updateLog := log.NewColorLogger(UpdateColor)
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/provision-express-tickets.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func newProvisionExpressTickets(c *cli.Command, logger log.ColorLogger) (*provis
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/set-latest-delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func newSetUseLatestDelegate(c *cli.Command, logger log.ColorLogger) (*setUseLat
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/node/verify-pdao-props.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func newVerifyPdaoProps(c *cli.Command, logger log.ColorLogger) (*verifyPdaoProp
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/watchtower/check-solo-migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func newCheckSoloMigrations(c *cli.Command, logger log.ColorLogger, errorLogger
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/watchtower/dissolve-timed-out-minipools.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func newDissolveTimedOutMinipools(c *cli.Command, logger log.ColorLogger) (*diss
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/watchtower/finalize-pdao-proposals.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func newFinalizePdaoProposals(c *cli.Command, logger log.ColorLogger) (*finalize
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/watchtower/respond-challenges.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func newRespondChallenges(c *cli.Command, logger log.ColorLogger, m *state.Netwo
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion rocketpool/watchtower/submit-network-balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func newSubmitNetworkBalances(c *cli.Command, logger log.ColorLogger, errorLogge
if err != nil {
return nil, err
}
w, err := services.GetHdWallet(c)
w, err := services.GetWallet(c)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading