Skip to content

Commit

Permalink
node local PoC (#2216)
Browse files Browse the repository at this point in the history
* node local init

* hardcode etna devnet config

* wip

* rm not needed utils

* ready for draft PR

* nits
rm unused struct

* refactor - wip

* make sure we can resume without prompts

* add custom network and local cluster

* devnet instead of custom network, rm custom

* go mod tidy

* upgrade.json for etna devnet

* more local cluster

* separate between local network and local cluster

* working

* nit

* fix plugin

* nit

* improve snapshot management

* fix bug

* nit

* proper etna devnet boostrappers

* fix bug with local rootdir

* remove global node config stuff

* destroy node data and processes if bad start

* nit

* always use fresh staking keys

* nit

* so less flags

* add back fast boot time

* add checks for local cluster. minor refactor (#2239)

* add checks for local cluster
minor refactoring

* fix test

* addressed Felipe feedback

---------

Signed-off-by: arturrez <[email protected]>

* bump anr

* fixes for convert flow

* add check for already initialized error on PoA init

* nit

* use anr main

* fix merge

* Local mkdir rootdir (#2245)

* make sure rootDir exists

* mv it to proper location

* it's done before the start

* update anr

* Integrate local devnet (#2254)

* integrate deploy

* integrate deploy

* Fix lint

* address comments

* address comments

* Integrate start (#2262)

* integrate start

* integrate start

* update etna network

* integrate start

* integrate start

* finish integrate start

* fix lint

* stop existing local avalanchego

* more robust

---------

Signed-off-by: arturrez <[email protected]>
Signed-off-by: sukantoraymond <[email protected]>
Co-authored-by: Felipe Madero <[email protected]>
Co-authored-by: sukantoraymond <[email protected]>
  • Loading branch information
3 people authored Oct 16, 2024
1 parent 7733ee6 commit 25f7fe9
Show file tree
Hide file tree
Showing 55 changed files with 1,704 additions and 366 deletions.
18 changes: 15 additions & 3 deletions cmd/backendcmd/spawn_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,35 @@ import (
"github.com/spf13/cobra"
)

var app *application.Avalanche
var (
app *application.Avalanche
serverPort string
gatewayPort string
snapshotsDir string
)

// backendCmd is the command to run the backend gRPC process
func NewCmd(injectedApp *application.Avalanche) *cobra.Command {
app = injectedApp
return &cobra.Command{
cmd := &cobra.Command{
Use: constants.BackendCmd,
Short: "Run the backend server",
Long: "This tool requires a backend process to run; this command starts it",
RunE: startBackend,
Args: cobrautils.ExactArgs(0),
Hidden: true,
}
cmd.Flags().StringVar(&serverPort, "server-port", binutils.LocalNetworkGRPCServerPort, "server port to use")
cmd.Flags().StringVar(&gatewayPort, "gateway-port", binutils.LocalNetworkGRPCGatewayPort, "gateway port to use")
cmd.Flags().StringVar(&snapshotsDir, "snapshots-dir", "", "snapshots dir to use")
return cmd
}

func startBackend(_ *cobra.Command, _ []string) error {
s, err := binutils.NewGRPCServer(app.GetSnapshotsDir())
if snapshotsDir == "" {
snapshotsDir = app.GetSnapshotsDir()
}
s, err := binutils.NewGRPCServer(serverPort, gatewayPort, snapshotsDir)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/blockchaincmd/add_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func CallAddValidator(
}

if changeAddr == "" {
changeAddr, err = getKeyForChangeOwner("", network)
changeAddr, err = getKeyForChangeOwner(nodeIDStrFormat, "", network)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/blockchaincmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ configuration, pass the -f flag.`,
cmd.Flags().BoolVar(&createFlags.proofOfStake, "proof-of-stake", false, "(coming soon) use proof of stake for validator management")
cmd.Flags().StringVar(&createFlags.poaValidatorManagerOwner, "poa-manager-owner", "", "EVM address that controls Validator Manager Owner (for Proof of Authority only)")
cmd.Flags().BoolVar(&sovereign, "sovereign", true, "set to false if creating non-sovereign blockchain")
cmd.Flags().BoolVar(&createFlags.enableDebugging, "debug", false, "enable blockchain debugging")
cmd.Flags().BoolVar(&createFlags.enableDebugging, "debug", true, "enable blockchain debugging")
return cmd
}

Expand Down
191 changes: 167 additions & 24 deletions cmd/blockchaincmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@
package blockchaincmd

import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/ava-labs/avalanchego/api/info"
"os"
"path/filepath"
"strings"
"time"

"github.com/ava-labs/avalanche-cli/pkg/node"
"github.com/ava-labs/avalanche-cli/pkg/evm"

"github.com/ava-labs/avalanche-cli/pkg/node"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/message"
"github.com/ethereum/go-ethereum/common"

Expand Down Expand Up @@ -49,6 +52,7 @@ import (
var deploySupportedNetworkOptions = []networkoptions.NetworkOption{
networkoptions.Local,
networkoptions.Devnet,
networkoptions.EtnaDevnet,
networkoptions.Fuji,
networkoptions.Mainnet,
}
Expand All @@ -62,6 +66,8 @@ var (
userProvidedAvagoVersion string
outputTxPath string
useLedger bool
useLocalMachine bool
localMachineCluster string
useEwoq bool
ledgerAddresses []string
sovereign bool
Expand All @@ -74,6 +80,7 @@ var (
generateNodeID bool
bootstrapValidatorsJSONFilePath string
privateKeyFlags contract.PrivateKeyFlags
bootstrapEndpoints []string

errMutuallyExlusiveControlKeys = errors.New("--control-keys and --same-control-key are mutually exclusive")
ErrMutuallyExlusiveKeyLedger = errors.New("key source flags --key, --ledger/--ledger-addrs are mutually exclusive")
Expand Down Expand Up @@ -128,6 +135,9 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`,
cmd.Flags().StringVar(&icmSpec.RegistryBydecodePath, "teleporter-registry-bytecode-path", "", "path to an interchain messenger registry bytecode file")
cmd.Flags().StringVar(&bootstrapValidatorsJSONFilePath, "bootstrap-filepath", "", "JSON file path that provides details about bootstrap validators, leave Node-ID and BLS values empty if using --generate-node-id=true")
cmd.Flags().BoolVar(&generateNodeID, "generate-node-id", false, "whether to create new node id for bootstrap validators (Node-ID and BLS values in bootstrap JSON file will be overridden if --bootstrap-filepath flag is used)")
cmd.Flags().StringSliceVar(&bootstrapEndpoints, "bootstrap-enu dpoints", nil, "take validator node info from the given endpoints")
cmd.Flags().BoolVar(&useLocalMachine, "use-local-machine", false, "use local machine as a blockchain validator")
cmd.Flags().StringVar(&localMachineCluster, "local-machine-cluster", "", "existing local machine to be used as a blockchain validator")
return cmd
}

Expand Down Expand Up @@ -394,13 +404,6 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
}
}

if sidecar.Sovereign && bootstrapValidatorsJSONFilePath == "" {
bootstrapValidators, err = promptBootstrapValidators(network)
if err != nil {
return err
}
}

ux.Logger.PrintToUser("Deploying %s to %s", chains, network.Name())

if network.Kind == models.Local {
Expand Down Expand Up @@ -433,10 +436,20 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
}

deployer := subnet.NewLocalDeployer(app, userProvidedAvagoVersion, avagoBinaryPath, vmBin)
deployInfo, err := deployer.DeployToLocalNetwork(chain, genesisPath, icmSpec, subnetIDStr)
deployInfo, err := deployer.DeployToLocalNetwork(
chain,
genesisPath,
icmSpec,
subnetIDStr,
constants.ServerRunFileLocalNetworkPrefix,
)
if err != nil {
if deployer.BackendStartedHere() {
if innerErr := binutils.KillgRPCServerProcess(app); innerErr != nil {
if innerErr := binutils.KillgRPCServerProcess(
app,
binutils.LocalNetworkGRPCServerEndpoint,
constants.ServerRunFileLocalNetworkPrefix,
); innerErr != nil {
app.Log.Warn("tried to kill the gRPC server process but it failed", zap.Error(innerErr))
}
}
Expand All @@ -452,13 +465,95 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
deployInfo.BlockchainID,
deployInfo.ICMMessengerAddress,
deployInfo.ICMRegistryAddress,
bootstrapValidators,
nil,
); err != nil {
return err
}
return PrintSubnetInfo(blockchainName, true)
}

if sidecar.Sovereign {
if !useLocalMachine {
ux.Logger.PrintToUser("You can use your local machine as a bootstrap validator on the blockchain")
ux.Logger.PrintToUser("This means that you don't have to to set up a remote server on a cloud service (e.g. AWS / GCP) to be a validator on the blockchain.")

useLocalMachine, err = app.Prompt.CaptureYesNo("Do you want to use your local machine as a bootstrap validator?")
if err != nil {
return err
}
}
if useLocalMachine {
// stop any local avalanche go process running before we start local node
_ = node.StopLocalNode(app)
clusterName := fmt.Sprintf("%s-local-node", blockchainName)
if localMachineCluster != "" {
// don't destroy cluster if local cluster name is provided
clusterName = localMachineCluster
} else {

Check failure on line 492 in cmd/blockchaincmd/deploy.go

View workflow job for this annotation

GitHub Actions / lint / Lint

elseif: can replace 'else {if cond {}}' with 'else if cond {}' (gocritic)

Check failure on line 492 in cmd/blockchaincmd/deploy.go

View workflow job for this annotation

GitHub Actions / Lint

elseif: can replace 'else {if cond {}}' with 'else if cond {}' (gocritic)
// destroy any cluster with same name before we start local node
// we don't want to reuse snapshots from previous sessions
if utils.DirectoryExists(app.GetLocalDir(clusterName)) {
_ = node.DestroyLocalNode(app, clusterName)
}
}
// TODO: replace bootstrapEndpoints with dynamic port number
bootstrapEndpoints = []string{"http://127.0.0.1:9650"}
anrSettings := node.ANRSettings{}
avagoVersionSettings := node.AvalancheGoVersionSettings{}
useEtnaDevnet := false
if network.Kind == models.EtnaDevnet {
useEtnaDevnet = true
}
if avagoBinaryPath == "" {
ux.Logger.PrintToUser("Local build of Avalanche Go is required to create an Avalanche node using local machine")
ux.Logger.PrintToUser("Please download Avalanche Go repo at https://github.com/ava-labs/avalanchego and build from source through ./scripts/build.sh")
ux.Logger.PrintToUser("Please provide the full path to Avalanche Go binary in the build directory (e.g, xxx/build/avalanchego)")
avagoBinaryPath, err = app.Prompt.CaptureString("Path to Avalanche Go build")
if err != nil {
return err
}
}
network = models.NewNetworkFromCluster(network, clusterName)
// anrSettings, avagoVersionSettings, globalNetworkFlags are empty
if err = node.StartLocalNode(app, clusterName, useEtnaDevnet, avagoBinaryPath, anrSettings, avagoVersionSettings, globalNetworkFlags, nil); err != nil {
return err
}
}

if len(bootstrapEndpoints) > 0 {
var changeAddr string
for _, endpoint := range bootstrapEndpoints {
infoClient := info.NewClient(endpoint)
ctx, cancel := utils.GetAPILargeContext()
defer cancel()
nodeID, proofOfPossession, err := infoClient.GetNodeID(ctx)
if err != nil {
return err
}
publicKey = "0x" + hex.EncodeToString(proofOfPossession.PublicKey[:])
pop = "0x" + hex.EncodeToString(proofOfPossession.ProofOfPossession[:])
changeAddr, err = getKeyForChangeOwner(nodeID.String(), changeAddr, network)
if err != nil {
return err
}
bootstrapValidators = append(bootstrapValidators, models.SubnetValidator{
NodeID: nodeID.String(),
Weight: constants.BootstrapValidatorWeight,
Balance: constants.BootstrapValidatorBalance,
BLSPublicKey: publicKey,
BLSProofOfPossession: pop,
ChangeOwnerAddr: changeAddr,
})
}
}
if len(bootstrapValidators) == 0 {
bootstrapValidators, err = promptBootstrapValidators(network)
if err != nil {
return err
}
}
}

// from here on we are assuming a public deploy
if subnetOnly && subnetIDStr != "" {
return errMutuallyExlusiveSubnetFlags
Expand Down Expand Up @@ -687,19 +782,27 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
}

if !generateNodeID {
clusterName, err := node.GetClusterNameFromList(app)
if err != nil {
return err
clusterName := network.ClusterName
if clusterName == "" {
clusterName, err = node.GetClusterNameFromList(app)
if err != nil {
return err
}
}

if err = node.SyncSubnet(app, clusterName, blockchainName, true, nil); err != nil {
return err
}
if !useLocalMachine {
if err = node.SyncSubnet(app, clusterName, blockchainName, true, nil); err != nil {
return err
}

if err := node.WaitForHealthyCluster(app, clusterName, node.HealthCheckTimeout, node.HealthCheckPoolTime); err != nil {
return err
if err := node.WaitForHealthyCluster(app, clusterName, node.HealthCheckTimeout, node.HealthCheckPoolTime); err != nil {
return err
}
} else {
if err := node.TrackSubnetWithLocalMachine(app, clusterName, blockchainName); err != nil {
return err
}
}

chainSpec := contract.ChainSpec{
BlockchainName: blockchainName,
}
Expand All @@ -721,20 +824,29 @@ func deployBlockchain(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
client, err := evm.GetClient(rpcURL)
if err != nil {
return err
}
evm.WaitForChainID(client)
privateAggregatorEndpoints, err := GetAggregatorExtraPeerEndpoints(network)
if err != nil {
return err
}
ux.Logger.PrintToUser("Initializing Proof of Authority Validator Manager contract on blockchain %s ...", blockchainName)
if err := validatormanager.SetupPoA(
app,
network,
rpcURL,
contract.ChainSpec{
BlockchainName: blockchainName,
},
chainSpec,
genesisPrivateKey,
common.HexToAddress(sidecar.PoAValidatorManagerOwner),
avaGoBootstrapValidators,
privateAggregatorEndpoints,
); err != nil {
return err
}
ux.Logger.GreenCheckmarkToUser("L1 is successfully converted to sovereign blockchain")
ux.Logger.GreenCheckmarkToUser("Proof of Authority Validator Manager contract successfully initialized on blockchain %s", blockchainName)
} else {
ux.Logger.GreenCheckmarkToUser("Generated Node ID and BLS info for bootstrap validator(s)")
ux.Logger.PrintToUser("To convert L1 to sovereign blockchain, create the corresponding Avalanche node(s) with the provided Node ID and BLS Info")
Expand Down Expand Up @@ -1003,3 +1115,34 @@ func LoadBootstrapValidator(filepath string) ([]models.SubnetValidator, error) {
}
return subnetValidators, nil
}

func GetAggregatorExtraPeerEndpoints(network models.Network) ([]string, error) {
aggregatorExtraPeerEndpoints := []string{}
if network.ClusterName != "" {
clustersConfig, err := app.LoadClustersConfig()
if err != nil {
return nil, err
}
clusterConfig := clustersConfig.Clusters[network.ClusterName]
if clusterConfig.Local {
cli, err := binutils.NewGRPCClientWithEndpoint(
binutils.LocalClusterGRPCServerEndpoint,
binutils.WithAvoidRPCVersionCheck(true),
binutils.WithDialTimeout(constants.FastGRPCDialTimeout),
)
if err != nil {
return nil, err
}
ctx, cancel := utils.GetANRContext()
defer cancel()
status, err := cli.Status(ctx)
if err != nil {
return nil, err
}
for _, nodeInfo := range status.ClusterInfo.NodeInfos {
aggregatorExtraPeerEndpoints = append(aggregatorExtraPeerEndpoints, nodeInfo.Uri)
}
}
}
return aggregatorExtraPeerEndpoints, nil
}
6 changes: 4 additions & 2 deletions cmd/blockchaincmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error {
for net, data := range sc.Networks {
network, err := networkoptions.GetNetworkFromSidecarNetworkName(app, net)
if err != nil {
return err
ux.Logger.RedXToUser("%s is supposed to be deployed to network %s: %s ", blockchainName, network.Name(), err)
ux.Logger.PrintToUser("")
continue
}
if network.Kind == models.Local && !locallyDeployed {
continue
Expand Down Expand Up @@ -191,7 +193,7 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error {
for net, data := range sc.Networks {
network, err := networkoptions.GetNetworkFromSidecarNetworkName(app, net)
if err != nil {
return err
continue
}
if network.Kind == models.Local && !locallyDeployed {
continue
Expand Down
2 changes: 1 addition & 1 deletion cmd/blockchaincmd/prompt_genesis_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func promptBootstrapValidators(network models.Network) ([]models.SubnetValidator
return nil, err
}
}
changeAddr, err := getKeyForChangeOwner(previousAddr, network)
changeAddr, err := getKeyForChangeOwner(nodeIDStr, previousAddr, network)
if err != nil {
return nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions cmd/blockchaincmd/prompt_owners.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,11 @@ func getThreshold(maxLen int) (uint32, error) {
return uint32(intTh), err
}

func getKeyForChangeOwner(previouslyUsedAddr string, network models.Network) (string, error) {
changeAddrPrompt := "Which key would you like to set as change owner for leftover AVAX if the node is removed from validator set?"
func getKeyForChangeOwner(nodeID string, previouslyUsedAddr string, network models.Network) (string, error) {
changeAddrPrompt := fmt.Sprintf(
"Which key would you like to set as change owner for leftover AVAX if the node %s is removed from validator set?",
nodeID,
)

const (
getFromStored = "Get address from an existing stored key (created from avalanche key create or avalanche key import)"
Expand Down
Loading

0 comments on commit 25f7fe9

Please sign in to comment.