Skip to content

Commit 4bf7b88

Browse files
Add Validator for remote L1 without importing blockchain (#2607)
* add validator on remote l1 * fix error * remove print * fix error * get validator manager owner * check if poa * fix test * remove print * fmt * lint * revert change * fix lint * fixes * update wait time * lint * fix merge * address comments * lint * address comments * address comments * lint * use warp to get blockchain * lint --------- Signed-off-by: sukantoraymond <[email protected]>
1 parent 32b1612 commit 4bf7b88

File tree

14 files changed

+259
-49
lines changed

14 files changed

+259
-49
lines changed

cmd/blockchaincmd/add_validator.go

Lines changed: 74 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ var (
6464
aggregatorExtraEndpoints []string
6565
aggregatorAllowPrivatePeers bool
6666
clusterNameFlagValue string
67+
createLocalValidator bool
68+
)
6769

68-
createLocalValidator bool
70+
const (
71+
validatorWeightFlag = "weight"
6972
)
7073

7174
// avalanche blockchain addValidator
@@ -82,12 +85,11 @@ staking token. Both processes will issue a RegisterL1ValidatorTx on the P-Chain.
8285
This command currently only works on Blockchains deployed to either the Fuji
8386
Testnet or Mainnet.`,
8487
RunE: addValidator,
85-
Args: cobrautils.ExactArgs(1),
88+
Args: cobrautils.MaximumNArgs(1),
8689
}
8790
networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions)
8891

8992
cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet only]")
90-
cmd.Flags().Uint64Var(&weight, "weight", constants.NonBootstrapValidatorWeight, "set the staking weight of the validator to add")
9193
cmd.Flags().Float64Var(
9294
&balanceAVAX,
9395
"balance",
@@ -119,31 +121,42 @@ Testnet or Mainnet.`,
119121
cmd.Flags().StringVar(&outputTxPath, "output-tx-path", "", "(for Subnets, not L1s) file path of the add validator tx")
120122
cmd.Flags().BoolVar(&waitForTxAcceptance, "wait-for-tx-acceptance", true, "(for Subnets, not L1s) just issue the add validator tx, without waiting for its acceptance")
121123
cmd.Flags().Uint16Var(&delegationFee, "delegation-fee", 100, "(PoS only) delegation fee (in bips)")
124+
cmd.Flags().StringVar(&subnetIDstr, "subnet-id", "", "subnet ID (only if blockchain name is not provided)")
125+
cmd.Flags().StringVar(&validatorManagerOwnerAddress, "validator-manager-owner", "", "validator manager owner address (only if blockchain name is not provided)")
126+
cmd.Flags().Uint64Var(&weight, validatorWeightFlag, uint64(constants.DefaultStakeWeight), "set the weight of the validator")
122127

123128
return cmd
124129
}
125130

126-
func preAddChecks() error {
131+
func preAddChecks(args []string) error {
127132
if nodeEndpoint != "" && createLocalValidator {
128133
return fmt.Errorf("cannot set both --node-endpoint and --create-local-validator")
129134
}
130135
if createLocalValidator && (nodeIDStr != "" || publicKey != "" || pop != "") {
131136
return fmt.Errorf("cannot set --node-id, --bls-public-key or --bls-proof-of-possession if --create-local-validator used")
132137
}
138+
if len(args) == 0 && createLocalValidator {
139+
return fmt.Errorf("use avalanche addValidator <subnetName> command to use local machine as new validator")
140+
}
133141

134142
return nil
135143
}
136144

137-
func addValidator(_ *cobra.Command, args []string) error {
138-
blockchainName := args[0]
139-
_, err := ValidateSubnetNameAndGetChains([]string{blockchainName})
140-
if err != nil {
141-
return err
142-
}
143-
144-
sc, err := app.LoadSidecar(blockchainName)
145-
if err != nil {
146-
return fmt.Errorf("failed to load sidecar: %w", err)
145+
func addValidator(cmd *cobra.Command, args []string) error {
146+
var sc models.Sidecar
147+
blockchainName := ""
148+
networkOption := networkoptions.DefaultSupportedNetworkOptions
149+
if len(args) == 1 {
150+
blockchainName = args[0]
151+
_, err := ValidateSubnetNameAndGetChains([]string{blockchainName})
152+
if err != nil {
153+
return err
154+
}
155+
sc, err = app.LoadSidecar(blockchainName)
156+
if err != nil {
157+
return fmt.Errorf("failed to load sidecar: %w", err)
158+
}
159+
networkOption = networkoptions.GetNetworkFromSidecar(sc, networkoptions.DefaultSupportedNetworkOptions)
147160
}
148161

149162
network, err := networkoptions.GetNetworkFromCmdLineFlags(
@@ -152,7 +165,7 @@ func addValidator(_ *cobra.Command, args []string) error {
152165
globalNetworkFlags,
153166
true,
154167
false,
155-
networkoptions.GetNetworkFromSidecar(sc, networkoptions.DefaultSupportedNetworkOptions),
168+
networkOption,
156169
"",
157170
)
158171
if err != nil {
@@ -164,7 +177,20 @@ func addValidator(_ *cobra.Command, args []string) error {
164177
network = models.ConvertClusterToNetwork(network)
165178
}
166179

167-
if err := preAddChecks(); err != nil {
180+
if len(args) == 0 {
181+
if rpcURL == "" {
182+
rpcURL, err = app.Prompt.CaptureURL("What is the RPC endpoint?", false)
183+
if err != nil {
184+
return err
185+
}
186+
}
187+
sc, err = importL1(blockchainIDStr, rpcURL, network)
188+
if err != nil {
189+
return err
190+
}
191+
}
192+
193+
if err := preAddChecks(args); err != nil {
168194
return err
169195
}
170196

@@ -197,19 +223,35 @@ func addValidator(_ *cobra.Command, args []string) error {
197223
}
198224
}
199225

200-
// if we don't have a nodeID or ProofOfPossession by this point, prompt user if we want to add a aditional local node
201-
if (!sovereign && nodeIDStr == "") || (sovereign && !createLocalValidator && nodeIDStr == "" && publicKey == "" && pop == "") {
202-
for {
203-
local := "Use my local machine to spin up an additional validator"
204-
existing := "I have an existing Avalanche node (we will require its NodeID and BLS info)"
205-
if option, err := app.Prompt.CaptureList(
206-
"How would you like to set up the new validator",
207-
[]string{local, existing},
208-
); err != nil {
226+
if sovereign {
227+
if !cmd.Flags().Changed(validatorWeightFlag) {
228+
weight, err = app.Prompt.CaptureWeight(
229+
"What weight would you like to assign to the validator?",
230+
func(uint64) error { return nil },
231+
)
232+
if err != nil {
209233
return err
210-
} else {
211-
createLocalValidator = option == local
212-
break
234+
}
235+
}
236+
}
237+
238+
// if we don't have a nodeID or ProofOfPossession by this point, prompt user if we want to add additional local node
239+
if (!sovereign && nodeIDStr == "") || (sovereign && !createLocalValidator && nodeIDStr == "" && publicKey == "" && pop == "") {
240+
if len(args) == 0 {
241+
createLocalValidator = false
242+
} else {
243+
for {
244+
local := "Use my local machine to spin up an additional validator"
245+
existing := "I have an existing Avalanche node (we will require its NodeID and BLS info)"
246+
if option, err := app.Prompt.CaptureList(
247+
"How would you like to set up the new validator",
248+
[]string{local, existing},
249+
); err != nil {
250+
return err
251+
} else {
252+
createLocalValidator = option == local
253+
break
254+
}
213255
}
214256
}
215257
}
@@ -312,6 +354,7 @@ func addValidator(_ *cobra.Command, args []string) error {
312354
balanceAVAX,
313355
remainingBalanceOwnerAddr,
314356
disableOwnerAddr,
357+
sc,
315358
)
316359
}
317360

@@ -335,6 +378,7 @@ func CallAddValidator(
335378
balanceAVAX float64,
336379
remainingBalanceOwnerAddr string,
337380
disableOwnerAddr string,
381+
sc models.Sidecar,
338382
) error {
339383
nodeID, err := ids.NodeIDFromString(nodeIDStr)
340384
if err != nil {
@@ -350,21 +394,16 @@ func CallAddValidator(
350394
return fmt.Errorf("failed to get blockchain timestamp: %w", err)
351395
}
352396
expiry := uint64(blockchainTimestamp.Add(constants.DefaultValidationIDExpiryDuration).Unix())
353-
354397
chainSpec := contract.ChainSpec{
355398
BlockchainName: blockchainName,
356399
}
357-
358-
sc, err := app.LoadSidecar(chainSpec.BlockchainName)
359-
if err != nil {
360-
return fmt.Errorf("failed to load sidecar: %w", err)
400+
if sc.Networks[network.Name()].BlockchainID.String() != "" {
401+
chainSpec.BlockchainID = sc.Networks[network.Name()].BlockchainID.String()
361402
}
362-
363403
if sc.Networks[network.Name()].ValidatorManagerAddress == "" {
364404
return fmt.Errorf("unable to find Validator Manager address")
365405
}
366406
validatorManagerAddress = sc.Networks[network.Name()].ValidatorManagerAddress
367-
368407
ownerPrivateKeyFound, _, _, ownerPrivateKey, err := contract.SearchForManagedKey(
369408
app,
370409
network,

cmd/blockchaincmd/change_weight.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,5 +257,6 @@ func setWeight(_ *cobra.Command, args []string) error {
257257
float64(balance)/float64(units.Avax),
258258
remainingBalanceOwnerAddr,
259259
disableOwnerAddr,
260+
sc,
260261
)
261262
}

cmd/blockchaincmd/deploy.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ var (
9393
poSWeightToValueFactor uint64
9494
deployBalanceAVAX float64
9595
validatorManagerAddress string
96+
validatorManagerOwnerAddress string
9697
errMutuallyExlusiveControlKeys = errors.New("--control-keys and --same-control-key are mutually exclusive")
9798
ErrMutuallyExlusiveKeyLedger = errors.New("key source flags --key, --ledger/--ledger-addrs are mutually exclusive")
9899
ErrStoredKeyOnMainnet = errors.New("key --key is not available for mainnet operations")
@@ -574,7 +575,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
574575
}
575576

576577
deployBalance := uint64(deployBalanceAVAX * float64(units.Avax))
577-
578+
// whether user has created Avalanche Nodes when blockchain deploy command is called
578579
if sidecar.Sovereign {
579580
if changeOwnerAddress == "" {
580581
// use provided key as change owner unless already set
@@ -792,13 +793,13 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
792793
if savePartialTx {
793794
return nil
794795
}
795-
796796
if convertOnly || generateNodeID || (!useLocalMachine && clusterNameFlagValue == "") {
797797
ux.Logger.GreenCheckmarkToUser("Converted blockchain successfully generated")
798798
ux.Logger.PrintToUser("To finish conversion to sovereign L1, create the corresponding Avalanche node(s) with the provided Node ID and BLS Info")
799-
ux.Logger.PrintToUser("and setup them to track subnet ID %s with 'track-subnets' config setting", subnetID)
800-
ux.Logger.PrintToUser(logging.Green.Wrap("Double check the nodes expose the P2P port and have a correct setting for 'public-ip' config value"))
801799
ux.Logger.PrintToUser("Created Node ID and BLS Info can be found at %s", app.GetSidecarPath(blockchainName))
800+
ux.Logger.PrintToUser("==================================================")
801+
ux.Logger.PrintToUser("To enable the nodes to track the L1, set '%s' as the value for 'track-subnets' configuration in ~/.avalanchego/config.json", subnetID)
802+
ux.Logger.PrintToUser("Ensure that the P2P port is exposed and 'public-ip' config value is set")
802803
ux.Logger.PrintToUser("Once the Avalanche Node(s) are created and are tracking the blockchain, call `avalanche contract initValidatorManager %s` to finish conversion to sovereign L1", blockchainName)
803804
return nil
804805
}

cmd/blockchaincmd/import_public.go

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,33 @@
33
package blockchaincmd
44

55
import (
6+
"encoding/hex"
67
"encoding/json"
78
"fmt"
89

910
"github.com/ava-labs/avalanche-cli/pkg/application"
11+
"github.com/ava-labs/avalanche-cli/pkg/blockchain"
1012
"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
1113
"github.com/ava-labs/avalanche-cli/pkg/constants"
14+
"github.com/ava-labs/avalanche-cli/pkg/contract"
1215
"github.com/ava-labs/avalanche-cli/pkg/models"
1316
"github.com/ava-labs/avalanche-cli/pkg/networkoptions"
17+
"github.com/ava-labs/avalanche-cli/pkg/precompiles"
1418
"github.com/ava-labs/avalanche-cli/pkg/utils"
1519
"github.com/ava-labs/avalanche-cli/pkg/ux"
1620
"github.com/ava-labs/avalanche-cli/pkg/vm"
21+
validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager"
1722
"github.com/ava-labs/avalanchego/api/info"
1823
"github.com/ava-labs/avalanchego/ids"
1924
"github.com/ava-labs/avalanchego/utils/rpc"
2025
"github.com/ava-labs/coreth/core"
26+
"github.com/ethereum/go-ethereum/common"
2127
"github.com/spf13/cobra"
2228
)
2329

2430
var (
25-
blockchainIDstr string
31+
blockchainIDStr string
32+
subnetIDstr string
2633
nodeURL string
2734
useSubnetEvm bool
2835
useCustomVM bool
@@ -55,7 +62,7 @@ flag.`,
5562
"overwrite the existing configuration if one exists",
5663
)
5764
cmd.Flags().StringVar(
58-
&blockchainIDstr,
65+
&blockchainIDStr,
5966
"blockchain-id",
6067
"",
6168
"the blockchain ID",
@@ -102,13 +109,13 @@ func importPublic(*cobra.Command, []string) error {
102109
}
103110

104111
var blockchainID ids.ID
105-
if blockchainIDstr == "" {
112+
if blockchainIDStr == "" {
106113
blockchainID, err = app.Prompt.CaptureID("What is the ID of the blockchain?")
107114
if err != nil {
108115
return err
109116
}
110117
} else {
111-
blockchainID, err = ids.FromString(blockchainIDstr)
118+
blockchainID, err = ids.FromString(blockchainIDStr)
112119
if err != nil {
113120
return err
114121
}
@@ -211,3 +218,70 @@ func importPublic(*cobra.Command, []string) error {
211218

212219
return nil
213220
}
221+
222+
func importL1(blockchainIDStr string, rpcURL string, network models.Network) (models.Sidecar, error) {
223+
var sc models.Sidecar
224+
225+
blockchainID, err := precompiles.WarpPrecompileGetBlockchainID(rpcURL)
226+
if err != nil {
227+
if blockchainIDStr == "" {
228+
blockchainID, err = app.Prompt.CaptureID("What is the Blockchain ID?")
229+
if err != nil {
230+
return models.Sidecar{}, err
231+
}
232+
} else {
233+
blockchainID, err = ids.FromString(blockchainIDStr)
234+
if err != nil {
235+
return models.Sidecar{}, err
236+
}
237+
}
238+
}
239+
subnetID, err := blockchain.GetSubnetIDFromBlockchainID(blockchainID, network)
240+
if err != nil {
241+
return models.Sidecar{}, err
242+
}
243+
244+
subnetInfo, err := blockchain.GetSubnet(subnetID, network)
245+
if err != nil {
246+
return models.Sidecar{}, err
247+
}
248+
if subnetInfo.IsPermissioned {
249+
return models.Sidecar{}, fmt.Errorf("unable to import non sovereign Subnets")
250+
}
251+
validatorManagerAddress = "0x" + hex.EncodeToString(subnetInfo.ManagerAddress)
252+
fmt.Printf("obtained blockchainid %s \n", blockchainID.String())
253+
fmt.Printf("obtained subnetid %s \n", subnetID.String())
254+
255+
fmt.Printf("obtained validatorManagerAddress %s \n", validatorManagerAddress)
256+
257+
// add validator without blockchain arg is only for l1s
258+
sc = models.Sidecar{
259+
Sovereign: true,
260+
}
261+
262+
isPoA := validatorManagerSDK.ValidatorManagerIsPoA(rpcURL, common.HexToAddress(validatorManagerAddress))
263+
if err != nil {
264+
return models.Sidecar{}, err
265+
}
266+
267+
if isPoA {
268+
sc.ValidatorManagement = models.ProofOfAuthority
269+
owner, err := contract.GetContractOwner(rpcURL, common.HexToAddress(validatorManagerAddress))
270+
if err != nil {
271+
return models.Sidecar{}, err
272+
}
273+
sc.ValidatorManagerOwner = owner.String()
274+
} else {
275+
sc.ValidatorManagement = models.ProofOfStake
276+
}
277+
278+
sc.Networks = make(map[string]models.NetworkData)
279+
280+
sc.Networks[network.Name()] = models.NetworkData{
281+
SubnetID: subnetID,
282+
BlockchainID: blockchainID,
283+
ValidatorManagerAddress: validatorManagerAddress,
284+
RPCEndpoints: []string{rpcURL},
285+
}
286+
return sc, err
287+
}

cmd/keycmd/transfer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func transferF(*cobra.Command, []string) error {
213213
return err
214214
}
215215
if senderChainFlags.BlockchainName != "" || receiverChainFlags.BlockchainName != "" || senderChainFlags.XChain {
216-
return fmt.Errorf("tranfer from %s to %s is not supported", senderDesc, receiverDesc)
216+
return fmt.Errorf("transfer from %s to %s is not supported", senderDesc, receiverDesc)
217217
}
218218

219219
if keyName == "" && ledgerIndex == wrongLedgerIndexVal {

cmd/validatorcmd/list.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ func list(_ *cobra.Command, args []string) error {
9090
if err != nil {
9191
return err
9292
}
93-
9493
managerAddress := common.HexToAddress(validatorManagerAddress)
9594

9695
t := ux.DefaultTable(

0 commit comments

Comments
 (0)