Skip to content

Commit 3d19e1e

Browse files
authored
Merge pull request #596 from jshufro/jms/v2/cpd
Remove pseudomodal.go (unused), deduplicate other parts
2 parents c9d41e4 + 9ff6ec3 commit 3d19e1e

File tree

11 files changed

+206
-735
lines changed

11 files changed

+206
-735
lines changed

rocketpool-cli/client/client.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ import (
1616

1717
// Config
1818
const (
19-
InstallerName string = "install.sh"
20-
UpdateTrackerInstallerName string = "install-update-tracker.sh"
21-
InstallerURL string = "https://github.com/rocket-pool/smartnode/releases/download/%s/" + InstallerName
22-
UpdateTrackerURL string = "https://github.com/rocket-pool/smartnode/releases/download/%s/" + UpdateTrackerInstallerName
23-
2419
SettingsFile string = "user-settings.yml"
2520
BackupSettingsFile string = "user-settings-backup.yml"
2621

rocketpool-cli/client/service.go

Lines changed: 35 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -19,51 +19,57 @@ import (
1919
)
2020

2121
const (
22+
installerName string = "install.sh"
23+
updateTrackerInstallerName string = "install-update-tracker.sh"
24+
installerURL string = "https://github.com/rocket-pool/smartnode/releases/download/%s/" + installerName
25+
updateTrackerURL string = "https://github.com/rocket-pool/smartnode/releases/download/%s/" + updateTrackerInstallerName
26+
2227
debugColor color.Attribute = color.FgYellow
2328
nethermindAdminUrl string = "http://127.0.0.1:7434"
2429
)
2530

26-
// Install the Rocket Pool service
27-
func (c *Client) InstallService(verbose bool, noDeps bool, version string, path string, useLocalInstaller bool) error {
28-
// Get installation script flags
31+
func (c *Client) downloadAndRun(
32+
name string,
33+
url string,
34+
verbose bool,
35+
version string,
36+
useLocalInstaller bool,
37+
extraFlags []string,
38+
) error {
39+
var script []byte
40+
2941
flags := []string{
3042
"-v", shellescape.Quote(version),
3143
}
32-
if path != "" {
33-
flags = append(flags, fmt.Sprintf("-p %s", shellescape.Quote(path)))
34-
}
35-
if noDeps {
36-
flags = append(flags, "-d")
37-
}
44+
flags = append(flags, extraFlags...)
3845

39-
var script []byte
4046
if useLocalInstaller {
4147
// Make sure it exists
42-
_, err := os.Stat(InstallerName)
48+
_, err := os.Stat(name)
4349
if errors.Is(err, os.ErrNotExist) {
44-
return fmt.Errorf("local install script [%s] does not exist", InstallerName)
50+
return fmt.Errorf("local script [%s] does not exist", name)
4551
}
4652
if err != nil {
47-
return fmt.Errorf("error checking install script [%s]: %w", InstallerName, err)
53+
return fmt.Errorf("error checking script [%s]: %w", name, err)
4854
}
4955

5056
// Read it
51-
script, err = os.ReadFile(InstallerName)
57+
script, err = os.ReadFile(name)
5258
if err != nil {
53-
return fmt.Errorf("error reading local install script [%s]: %w", InstallerName, err)
59+
return fmt.Errorf("error reading local script [%s]: %w", name, err)
5460
}
5561

5662
// Set the "local mode" flag
5763
flags = append(flags, "-l")
5864
} else {
5965
// Download the installation script
60-
resp, err := http.Get(fmt.Sprintf(InstallerURL, version))
66+
resp, err := http.Get(fmt.Sprintf(url, version))
6167
if err != nil {
6268
return err
6369
}
6470
defer resp.Body.Close()
6571
if resp.StatusCode != http.StatusOK {
66-
return fmt.Errorf("unexpected http status downloading installation script: %d", resp.StatusCode)
72+
return fmt.Errorf("unexpected http status downloading %s script: %d", name, resp.StatusCode)
6773
}
6874

6975
// Sanity check that the script octet length matches content-length
@@ -128,103 +134,23 @@ func (c *Client) InstallService(verbose bool, noDeps bool, version string, path
128134
return nil
129135
}
130136

131-
// Install the update tracker
132-
func (c *Client) InstallUpdateTracker(verbose bool, version string, useLocalInstaller bool) error {
137+
// Install the Rocket Pool service
138+
func (c *Client) InstallService(verbose bool, noDeps bool, version string, path string, useLocalInstaller bool) error {
133139
// Get installation script flags
134-
flags := []string{
135-
"-v", shellescape.Quote(version),
136-
}
137-
138-
var script []byte
139-
if useLocalInstaller {
140-
// Make sure it exists
141-
_, err := os.Stat(UpdateTrackerInstallerName)
142-
if errors.Is(err, os.ErrNotExist) {
143-
return fmt.Errorf("local update tracker install script [%s] does not exist", UpdateTrackerInstallerName)
144-
}
145-
if err != nil {
146-
return fmt.Errorf("error checking update tracker install script [%s]: %w", UpdateTrackerInstallerName, err)
147-
}
148-
149-
// Read it
150-
script, err = os.ReadFile(UpdateTrackerInstallerName)
151-
if err != nil {
152-
return fmt.Errorf("error reading local update tracker install script [%s]: %w", UpdateTrackerInstallerName, err)
153-
}
154-
155-
// Set the "local mode" flag
156-
flags = append(flags, "-l")
157-
} else {
158-
// Download the update tracker script
159-
resp, err := http.Get(fmt.Sprintf(UpdateTrackerURL, version))
160-
if err != nil {
161-
return err
162-
}
163-
defer resp.Body.Close()
164-
if resp.StatusCode != http.StatusOK {
165-
return fmt.Errorf("unexpected http status downloading update tracker installer script: %d", resp.StatusCode)
166-
}
167-
168-
// Sanity check that the script octet length matches content-length
169-
script, err = io.ReadAll(resp.Body)
170-
if err != nil {
171-
return err
172-
}
173-
174-
if fmt.Sprint(len(script)) != resp.Header.Get("content-length") {
175-
return fmt.Errorf("downloaded script length %d did not match content-length header %s", len(script), resp.Header.Get("content-length"))
176-
}
177-
}
178-
179-
// Get the escalation command
180-
escalationCmd, err := c.getEscalationCommand()
181-
if err != nil {
182-
return fmt.Errorf("error getting escalation command: %w", err)
183-
}
184-
185-
// Initialize installation command
186-
cmd := c.newCommand(fmt.Sprintf("%s sh -s -- %s", escalationCmd, strings.Join(flags, " ")))
187-
188-
// Pass the script to sh via its stdin fd
189-
cmd.SetStdin(bytes.NewReader(script))
190-
191-
// Get command output pipes
192-
cmdOut, err := cmd.StdoutPipe()
193-
if err != nil {
194-
return err
140+
flags := []string{}
141+
if path != "" {
142+
flags = append(flags, fmt.Sprintf("-p %s", shellescape.Quote(path)))
195143
}
196-
cmdErr, err := cmd.StderrPipe()
197-
if err != nil {
198-
return err
144+
if noDeps {
145+
flags = append(flags, "-d")
199146
}
200147

201-
// Print progress from stdout
202-
go (func() {
203-
scanner := bufio.NewScanner(cmdOut)
204-
for scanner.Scan() {
205-
fmt.Println(scanner.Text())
206-
}
207-
})()
208-
209-
// Read command & error output from stderr; render in verbose mode
210-
var errMessage string
211-
go (func() {
212-
c := color.New(debugColor)
213-
scanner := bufio.NewScanner(cmdErr)
214-
for scanner.Scan() {
215-
errMessage = scanner.Text()
216-
if verbose {
217-
_, _ = c.Println(scanner.Text())
218-
}
219-
}
220-
})()
148+
return c.downloadAndRun(installerName, installerURL, verbose, version, useLocalInstaller, flags)
149+
}
221150

222-
// Run command and return error output
223-
err = cmd.Run()
224-
if err != nil {
225-
return fmt.Errorf("could not install Rocket Pool update tracker: %s", errMessage)
226-
}
227-
return nil
151+
// Install the update tracker
152+
func (c *Client) InstallUpdateTracker(verbose bool, version string, useLocalInstaller bool) error {
153+
return c.downloadAndRun(updateTrackerInstallerName, updateTrackerURL, verbose, version, useLocalInstaller, nil)
228154
}
229155

230156
// Start the Rocket Pool service

rocketpool-cli/commands/node/create-vacant-minipool.go

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

33
import (
4-
"crypto/rand"
54
"fmt"
6-
"math/big"
7-
"strconv"
85

96
"github.com/ethereum/go-ethereum/common"
107
"github.com/rocket-pool/node-manager-core/beacon"
@@ -29,126 +26,20 @@ func createVacantMinipool(c *cli.Context, pubkey beacon.ValidatorPubkey) error {
2926
return err
3027
}
3128

32-
// Make sure Beacon is on the correct chain
33-
depositContractInfo, err := rp.Api.Network.GetDepositContractInfo(true)
29+
d, err := newDepositPrompts(c, rp, &pubkey)
3430
if err != nil {
3531
return err
3632
}
37-
if depositContractInfo.Data.RPNetwork != depositContractInfo.Data.BeaconNetwork ||
38-
depositContractInfo.Data.RPDepositContract != depositContractInfo.Data.BeaconDepositContract {
39-
utils.PrintDepositMismatchError(
40-
depositContractInfo.Data.RPNetwork,
41-
depositContractInfo.Data.BeaconNetwork,
42-
depositContractInfo.Data.RPDepositContract,
43-
depositContractInfo.Data.BeaconDepositContract)
33+
if d == nil {
4434
return nil
4535
}
4636

47-
fmt.Println("Your Beacon Node is on the correct network.")
48-
fmt.Println()
49-
50-
// Check if the fee distributor has been initialized
51-
feeDistributorResponse, err := rp.Api.Node.InitializeFeeDistributor()
52-
if err != nil {
53-
return err
54-
}
55-
if !feeDistributorResponse.Data.IsInitialized {
56-
fmt.Println("Your fee distributor has not been initialized yet so you cannot create a new minipool.\nPlease run `rocketpool node initialize-fee-distributor` to initialize it first.")
57-
return nil
58-
}
59-
60-
// Post a warning about fee distribution
61-
if !(c.Bool("yes") || utils.Confirm(fmt.Sprintf("%sNOTE: by creating a new minipool, your node will automatically claim and distribute any balance you have in your fee distributor contract. If you don't want to claim your balance at this time, you should not create a new minipool.%s\nWould you like to continue?", terminal.ColorYellow, terminal.ColorReset))) {
62-
fmt.Println("Cancelled.")
63-
return nil
64-
}
65-
66-
// Print a notification about the pubkey
67-
fmt.Printf("You are about to convert the solo staker %s into a Rocket Pool minipool. This will convert your 32 ETH deposit into either an 8 ETH or 16 ETH deposit (your choice), and convert the remaining 24 or 16 ETH into a deposit from the Rocket Pool staking pool. The staking pool portion will be credited to your node's account, allowing you to create more validators without depositing additional ETH onto the Beacon Chain. Your excess balance (your existing Beacon rewards) will be preserved and not shared with the pool stakers.\n\nPlease thoroughly read our documentation at https://docs.rocketpool.net/guides/atlas/solo-staker-migration.html to learn about the process and its implications.\n\n1. First, we'll create the new minipool.\n2. Next, we'll ask whether you want to import the validator's private key into your Smartnode's Validator Client, or keep running your own externally-managed validator.\n3. Finally, we'll help you migrate your validator's withdrawal credentials to the minipool address.\n\n%sNOTE: If you intend to use the credit balance to create additional validators, you will need to have enough RPL staked to support them.%s\n\n", pubkey.Hex(), terminal.ColorYellow, terminal.ColorReset)
68-
69-
// Get deposit amount
70-
var amount float64
71-
if c.String(amountFlag) != "" {
72-
// Parse amount
73-
depositAmount, err := strconv.ParseFloat(c.String(amountFlag), 64)
74-
if err != nil {
75-
return fmt.Errorf("invalid deposit amount '%s': %w", c.String(amountFlag), err)
76-
}
77-
amount = depositAmount
78-
} else {
79-
// Get deposit amount options
80-
amountOptions := []string{
81-
"8 ETH",
82-
"16 ETH",
83-
}
84-
85-
// Prompt for amount
86-
selected, _ := utils.Select("Please choose an amount of ETH you want to use as your deposit for the new minipool (this will become your share of the balance, and the remainder will become the pool stakers' share):", amountOptions)
87-
switch selected {
88-
case 0:
89-
amount = 8
90-
case 1:
91-
amount = 16
92-
}
93-
}
94-
amountWei := eth.EthToWei(amount)
95-
96-
// Get network node fees
97-
nodeFeeResponse, err := rp.Api.Network.NodeFee()
98-
if err != nil {
99-
return err
100-
}
101-
102-
// Get minimum node fee
103-
var minNodeFee float64
104-
if c.String("max-slippage") == "auto" {
105-
// Use default max slippage
106-
minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.NodeFee) - DefaultMaxNodeFeeSlippage
107-
if minNodeFee < eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee) {
108-
minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee)
109-
}
110-
} else if c.String("max-slippage") != "" {
111-
// Parse max slippage
112-
maxNodeFeeSlippagePerc, err := strconv.ParseFloat(c.String("max-slippage"), 64)
113-
if err != nil {
114-
return fmt.Errorf("invalid maximum commission rate slippage '%s': %w", c.String("max-slippage"), err)
115-
}
116-
maxNodeFeeSlippage := maxNodeFeeSlippagePerc / 100
117-
118-
// Calculate min node fee
119-
minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.NodeFee) - maxNodeFeeSlippage
120-
if minNodeFee < eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee) {
121-
minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee)
122-
}
123-
} else {
124-
// Prompt for min node fee
125-
if nodeFeeResponse.Data.MinNodeFee == nodeFeeResponse.Data.MaxNodeFee {
126-
fmt.Printf("Your minipool will use the current fixed commission rate of %.2f%%.\n", eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee)*100)
127-
minNodeFee = eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee)
128-
} else {
129-
minNodeFee = promptMinNodeFee(eth.WeiToEth(nodeFeeResponse.Data.NodeFee), eth.WeiToEth(nodeFeeResponse.Data.MinNodeFee))
130-
}
131-
}
132-
133-
// Get minipool salt
134-
var salt *big.Int
135-
if c.String(saltFlag) != "" {
136-
var success bool
137-
salt, success = big.NewInt(0).SetString(c.String(saltFlag), 0)
138-
if !success {
139-
return fmt.Errorf("invalid minipool salt: %s", c.String(saltFlag))
140-
}
141-
} else {
142-
buffer := make([]byte, 32)
143-
_, err = rand.Read(buffer)
144-
if err != nil {
145-
return fmt.Errorf("error generating random salt: %w", err)
146-
}
147-
salt = big.NewInt(0).SetBytes(buffer)
148-
}
37+
minNodeFee := d.minNodeFee
38+
amountWei := d.amountWei
39+
amount := eth.WeiToEth(amountWei)
14940

15041
// Build the TX
151-
response, err := rp.Api.Node.CreateVacantMinipool(amountWei, minNodeFee, salt, pubkey)
42+
response, err := rp.Api.Node.CreateVacantMinipool(amountWei, minNodeFee, d.salt, pubkey)
15243
if err != nil {
15344
return err
15445
}
@@ -177,20 +68,25 @@ func createVacantMinipool(c *cli.Context, pubkey beacon.ValidatorPubkey) error {
17768
syncResponse, err := rp.Api.Service.ClientStatus()
17869
if err != nil {
17970
return fmt.Errorf("error checking if your clients are in sync: %w", err)
180-
} else {
181-
if syncResponse.Data.BcManagerStatus.PrimaryClientStatus.IsSynced {
182-
fmt.Printf("Your consensus client is synced, you may safely create a minipool.\n")
183-
} else if syncResponse.Data.BcManagerStatus.FallbackEnabled {
184-
if syncResponse.Data.BcManagerStatus.FallbackClientStatus.IsSynced {
185-
fmt.Printf("Your fallback consensus client is synced, you may safely create a minipool.\n")
186-
} else {
187-
fmt.Printf("%s**WARNING**: neither your primary nor fallback consensus clients are fully synced.\nYou cannot migrate until they've finished syncing.\n%s", terminal.ColorRed, terminal.ColorReset)
188-
return nil
189-
}
71+
}
72+
if syncResponse.Data.BcManagerStatus.PrimaryClientStatus.IsSynced {
73+
fmt.Println("Your consensus client is synced, you may safely create a minipool.")
74+
} else if syncResponse.Data.BcManagerStatus.FallbackEnabled {
75+
if syncResponse.Data.BcManagerStatus.FallbackClientStatus.IsSynced {
76+
fmt.Println("Your fallback consensus client is synced, you may safely create a minipool.")
19077
} else {
191-
fmt.Printf("%s**WARNING**: your primary consensus client is either not fully synced or offline and you do not have a fallback client configured.\nYou cannot migrate until you have a synced consensus client.\n%s", terminal.ColorRed, terminal.ColorReset)
78+
fmt.Print(terminal.ColorRed)
79+
fmt.Println("**WARNING**: neither your primary nor fallback consensus clients are fully synced.")
80+
fmt.Println("You cannot migrate until they've finished syncing.")
81+
fmt.Print(terminal.ColorReset)
19282
return nil
19383
}
84+
} else {
85+
fmt.Print(terminal.ColorRed)
86+
fmt.Println("**WARNING**: your primary consensus client is either not fully synced or offline and you do not have a fallback client configured.")
87+
fmt.Println("You cannot migrate until you have a synced consensus client.")
88+
fmt.Print(terminal.ColorReset)
89+
return nil
19490
}
19591

19692
// Run the TX

0 commit comments

Comments
 (0)