Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate local machine into subnet deploy #2235

Closed
wants to merge 14 commits into from
128 changes: 79 additions & 49 deletions cmd/blockchaincmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"strings"
"time"

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

"github.com/ava-labs/avalanchego/api/info"
"github.com/ava-labs/avalanchego/vms/platformvm/warp/message"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -464,6 +466,18 @@
return PrintSubnetInfo(blockchainName, true)
}

ux.Logger.PrintToUser("You can use your local machine as a bootstrap validator on the blockchain")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also this to be guarded by a flag

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

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.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably we want to explain more here? like this is temporary bootstrap validator

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not temporary if user wants to leave it the node indefinitely as validator


useLocalMachine, err := app.Prompt.CaptureYesNo("Do you want to use your local machine as a bootstrap validator?")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flag to avoid question for this and just proceed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

if err != nil {
return err
}

if useLocalMachine {
bootstrapEndpoints = []string{"http://127.0.0.1:9650"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might be tricky to assume this endpoint as port can be not 9650 but rather dynamic
cc @felipemadero

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should ask user for the endpoint and not yes/no for local machine.
we can hint that it can be 127.0.0.1:9650 for the local machine

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now. After the previous question, a Start should be made and from that, the endpoint
can be obtained from the anr itself, not need to assume anything.
This is not related to the flag useLocalMachine. This relates to the local cluster that exists previous
to the deploy. The best way should be to check the network, which should be a local cluster,
in that case take the endpoint from anr.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably for another PR. Make an issue for this and keep current static assignment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

if len(bootstrapEndpoints) > 0 {
var changeAddr string
for _, endpoint := range bootstrapEndpoints {
Expand Down Expand Up @@ -663,7 +677,7 @@
}
deployer.CleanCacheWallet()
managerAddress := common.HexToAddress(validatormanager.ValidatorContractAddress)
isFullySigned, ConvertL1TxID, tx, remainingSubnetAuthKeys, err := deployer.ConvertL1(

Check warning on line 680 in cmd/blockchaincmd/deploy.go

View workflow job for this annotation

GitHub Actions / Lint

unexported-naming: the symbol ConvertL1TxID is local, its name should start with a lowercase letter (revive)
controlKeys,
subnetAuthKeys,
subnetID,
Expand Down Expand Up @@ -725,65 +739,81 @@
return err
}

if false {
chainSpec := contract.ChainSpec{
BlockchainName: blockchainName,
}
genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey(
app,
network,
chainSpec,
)
if err != nil {
clusterName, err := node.GetClusterNameFromList(app)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cluster name to be taken from the input network itself IMO

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

which should be a cluster

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

models.Networks has ClusterName

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to do it when integrating local node start

if err != nil {
return err
}

if !useLocalMachine {
if err = node.SyncSubnet(app, clusterName, blockchainName, true, nil); err != nil {
return err
}
privateKey, err := privateKeyFlags.GetPrivateKey(app, genesisPrivateKey)
if err != nil {
if err := node.WaitForHealthyCluster(app, clusterName, node.HealthCheckTimeout, node.HealthCheckPoolTime); err != nil {
return err
}
if privateKey == "" {
privateKey, err = prompts.PromptPrivateKey(
app.Prompt,
"Which key to you want to use to pay for initializing Validator Manager contract? (Uses Blockchain gas token)",
app.GetKeyDir(),
app.GetKey,
genesisAddress,
genesisPrivateKey,
)
if err != nil {
return err
}
}
rpcURL, _, err := contract.GetBlockchainEndpoints(
app,
network,
chainSpec,
true,
false,
)
if err != nil {
} else {
if err := node.TrackSubnetWithLocalMachine(app, clusterName, blockchainName); err != nil {
return err
}
aggregatorExtraPeerEndpoints, err := GetAggregatorExtraPeerEndpoints(network)
}

chainSpec := contract.ChainSpec{
BlockchainName: blockchainName,
}
genesisAddress, genesisPrivateKey, err := contract.GetEVMSubnetPrefundedKey(
app,
network,
chainSpec,
)
if err != nil {
return err
}
privateKey, err := privateKeyFlags.GetPrivateKey(app, genesisPrivateKey)
if err != nil {
return err
}
if privateKey == "" {
privateKey, err = prompts.PromptPrivateKey(
app.Prompt,
"Which key to you want to use to pay for initializing Validator Manager contract? (Uses Blockchain gas token)",
app.GetKeyDir(),
app.GetKey,
genesisAddress,
genesisPrivateKey,
)
if err != nil {
return err
}
if err := validatormanager.SetupPoA(
app,
network,
rpcURL,
contract.ChainSpec{
BlockchainName: blockchainName,
},
privateKey,
common.HexToAddress(sidecar.PoAValidatorManagerOwner),
avaGoBootstrapValidators,
aggregatorExtraPeerEndpoints,
); err != nil {
return err
}
ux.Logger.GreenCheckmarkToUser("Subnet is successfully converted into Subnet Only Validator")
}
rpcURL, _, err := contract.GetBlockchainEndpoints(
app,
network,
chainSpec,
true,
false,
)
if err != nil {
return err
}
aggregatorExtraPeerEndpoints, err := GetAggregatorExtraPeerEndpoints(network)
if err != nil {
return err
}
if err := validatormanager.SetupPoA(
app,
network,
rpcURL,
contract.ChainSpec{
BlockchainName: blockchainName,
},
privateKey,
common.HexToAddress(sidecar.PoAValidatorManagerOwner),
avaGoBootstrapValidators,
aggregatorExtraPeerEndpoints,
); err != nil {
return err
}
ux.Logger.GreenCheckmarkToUser("Subnet is successfully converted into Subnet Only Validator")
}

flags := make(map[string]string)
Expand Down
115 changes: 11 additions & 104 deletions cmd/nodecmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"os"
"path/filepath"

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

"github.com/ava-labs/avalanche-cli/pkg/binutils"
"github.com/ava-labs/avalanche-cli/pkg/cobrautils"
"github.com/ava-labs/avalanche-cli/pkg/constants"
Expand All @@ -17,10 +19,7 @@
"github.com/ava-labs/avalanche-cli/pkg/utils"
"github.com/ava-labs/avalanche-cli/pkg/ux"
"github.com/ava-labs/avalanche-network-runner/client"
anrutils "github.com/ava-labs/avalanche-network-runner/utils"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -351,7 +350,9 @@
spinner := spinSession.SpinToUser("Booting Network. Wait until healthy...")
if _, err := cli.Start(ctx, avalancheGoBinPath, anrOpts...); err != nil {
ux.SpinFailWithError(spinner, "", err)
localDestroyNode(nil, []string{clusterName})
if destroyErr := localDestroyNode(nil, []string{clusterName}); destroyErr != nil {
return fmt.Errorf("failed to start local avalanchego: %w, and failed to destroy the local node %s due to %w", err, clusterName, destroyErr)
}
return fmt.Errorf("failed to start local avalanchego: %w", err)
}
ux.SpinComplete(spinner)
Expand Down Expand Up @@ -415,14 +416,17 @@
func localDestroyNode(_ *cobra.Command, args []string) error {
clusterName := args[0]

localStopNode(nil, nil)
if err := localStopNode(nil, nil); err != nil {

Check warning on line 419 in cmd/nodecmd/local.go

View workflow job for this annotation

GitHub Actions / Lint

empty-lines: extra empty line at the end of a block (revive)
return fmt.Errorf("failed to destroy local node: %w", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node can be already stopped. for the moment on ignore the error or verify is the node is already stopped,
we want to continue removing all the directorioes that is the reason the error is ignored

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just need to make sure this passes lint. removed err

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed


Check failure on line 421 in cmd/nodecmd/local.go

View workflow job for this annotation

GitHub Actions / Lint

File is not `gofumpt`-ed (gofumpt)
}

Check failure on line 422 in cmd/nodecmd/local.go

View workflow job for this annotation

GitHub Actions / Lint

unnecessary trailing newline (whitespace)

rootDir := app.GetLocalDir(clusterName)
if err := os.RemoveAll(rootDir); err != nil {
return err
}

if ok, err := checkClusterIsLocal(clusterName); err != nil || !ok {
if ok, err := node.CheckClusterIsLocal(app, clusterName); err != nil || !ok {
return fmt.Errorf("local cluster %q not found", clusterName)
}

Expand Down Expand Up @@ -452,107 +456,10 @@
return app.WriteClustersConfigFile(&clustersConfig)
}

func checkClusterIsLocal(clusterName string) (bool, error) {
clustersConfig, err := app.GetClustersConfig()
if err != nil {
return false, err
}
clusterConf, ok := clustersConfig.Clusters[clusterName]
return ok && clusterConf.Local, nil
}

func localTrack(_ *cobra.Command, args []string) error {
clusterName := args[0]
blockchainName := args[1]
if ok, err := checkClusterIsLocal(clusterName); err != nil || !ok {
return fmt.Errorf("local node %q is not found", clusterName)
}
sc, err := app.LoadSidecar(blockchainName)
if err != nil {
return err
}
clustersConfig, err := app.LoadClustersConfig()
if err != nil {
return err
}
clusterConfig := clustersConfig.Clusters[clusterName]
network := clusterConfig.Network
if sc.Networks[network.Name()].BlockchainID == ids.Empty {
return fmt.Errorf("blockchain %s has not been deployed to %s", blockchainName, network.Name())
}
subnetID := sc.Networks[network.Name()].SubnetID
blockchainID := sc.Networks[network.Name()].BlockchainID
vmID, err := anrutils.VMID(blockchainName)
if err != nil {
return fmt.Errorf("failed to create VM ID from %s: %w", blockchainName, err)
}
var vmBin string
switch sc.VM {
case models.SubnetEvm:
_, vmBin, err = binutils.SetupSubnetEVM(app, sc.VMVersion)
if err != nil {
return fmt.Errorf("failed to install subnet-evm: %w", err)
}
case models.CustomVM:
vmBin = binutils.SetupCustomBin(app, blockchainName)
default:
return fmt.Errorf("unknown vm: %s", sc.VM)
}
rootDir := app.GetLocalDir(clusterName)
pluginPath := filepath.Join(rootDir, "node1", "plugins", vmID.String())
if err := utils.FileCopy(vmBin, pluginPath); err != nil {
return err
}
if err := os.Chmod(pluginPath, constants.DefaultPerms755); err != nil {
return err
}
if app.ChainConfigExists(blockchainName) {
inputChainConfigPath := app.GetChainConfigPath(blockchainName)
outputChainConfigPath := filepath.Join(rootDir, "node1", "configs", "chains", blockchainID.String(), "config.json")
if err := os.MkdirAll(filepath.Dir(outputChainConfigPath), 0o700); err != nil {
return fmt.Errorf("could not create chain conf directory %s: %w", filepath.Dir(outputChainConfigPath), err)
}
if err := utils.FileCopy(inputChainConfigPath, outputChainConfigPath); err != nil {
return err
}
}

cli, err := binutils.NewGRPCClientWithEndpoint(
binutils.LocalClusterGRPCServerEndpoint,
binutils.WithAvoidRPCVersionCheck(true),
binutils.WithDialTimeout(constants.FastGRPCDialTimeout),
)
if err != nil {
return err
}
ctx, cancel := utils.GetANRContext()
defer cancel()
status, err := cli.Status(ctx)
if err != nil {
return err
}
publicEndpoints := []string{}
for _, nodeInfo := range status.ClusterInfo.NodeInfos {
if _, err := cli.RestartNode(ctx, nodeInfo.Name, client.WithWhitelistedSubnets(subnetID.String())); err != nil {
return err
}
publicEndpoints = append(publicEndpoints, nodeInfo.Uri)
}
networkInfo := sc.Networks[network.Name()]
rpcEndpoints := set.Of(networkInfo.RPCEndpoints...)
wsEndpoints := set.Of(networkInfo.WSEndpoints...)
for _, publicEndpoint := range publicEndpoints {
rpcEndpoints.Add(getRPCEndpoint(publicEndpoint, networkInfo.BlockchainID.String()))
wsEndpoints.Add(getWSEndpoint(publicEndpoint, networkInfo.BlockchainID.String()))
}
networkInfo.RPCEndpoints = rpcEndpoints.List()
networkInfo.WSEndpoints = wsEndpoints.List()
sc.Networks[clusterConfig.Network.Name()] = networkInfo
if err := app.UpdateSidecar(&sc); err != nil {
return err
}
ux.Logger.GreenCheckmarkToUser("%s successfully tracking %s", clusterName, blockchainName)
return nil
return node.TrackSubnetWithLocalMachine(app, clusterName, blockchainName)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure it is the moment to move this to node pgk. we keep a part of logic here and a part in node.
also, maybe node is not the final dest package.

}

func notImplementedForLocal(what string) error {
Expand Down
Loading
Loading