diff --git a/.github/config/auto_assign.yml b/.github/config/auto_assign.yml new file mode 100644 index 000000000..05dbfc03a --- /dev/null +++ b/.github/config/auto_assign.yml @@ -0,0 +1,2 @@ +addAssignees: author +runOnDraft: true diff --git a/.github/scripts/cli_scraper.py b/.github/scripts/cli_scraper.py new file mode 100644 index 000000000..f0a61eb3b --- /dev/null +++ b/.github/scripts/cli_scraper.py @@ -0,0 +1,262 @@ +import subprocess +import json +import re + +def replace_angle_brackets(text): + """ + Replace any text within angle brackets with backticks to prevent Markdown rendering issues. + Example: "" becomes "`snapshotName`" + """ + return re.sub(r'<(.*?)>', r'`\1`', text) + +def generate_anchor_id(cli_tool, command_chain): + """ + Generate a unique anchor ID based on the entire command chain. + + Example: + cli_tool = "avalanche" + command_chain = ["blockchain", "create"] + -> anchor_id = "avalanche-blockchain-create" + """ + full_chain = [cli_tool] + command_chain + anchor_str = '-'.join(full_chain) + # Remove invalid characters for anchors, and lowercase + anchor_str = re.sub(r'[^\w\-]', '', anchor_str.lower()) + return anchor_str + +def get_command_structure(cli_tool, command_chain=None, max_depth=10, current_depth=0, processed_commands=None): + """ + Recursively get a dictionary of commands, subcommands, flags (with descriptions), + and descriptions for a given CLI tool by parsing its --help output. + """ + if command_chain is None: + command_chain = [] + if processed_commands is None: + processed_commands = {} + + current_command = [cli_tool] + command_chain + command_key = ' '.join(current_command) + + # Prevent re-processing of the same command + if command_key in processed_commands: + return processed_commands[command_key] + + # Prevent going too deep + if current_depth > max_depth: + return None + + command_structure = { + "description": "", + "flags": [], + "subcommands": {} + } + + print(f"Processing command: {' '.join(current_command)}") + + # Run ` --help` + try: + help_output = subprocess.run( + current_command + ["--help"], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + timeout=10, + stdin=subprocess.DEVNULL + ) + output = help_output.stdout + # Some CLIs return a non-zero exit code but still provide help text, so no strict check here + except subprocess.TimeoutExpired: + print(f"[ERROR] Timeout expired for command: {' '.join(current_command)}") + return None + except Exception as e: + print(f"[ERROR] Exception while running: {' '.join(current_command)} -> {e}") + return None + + if not output.strip(): + print(f"[WARNING] No output for command: {' '.join(current_command)}") + return None + + # --- Extract Description ------------------------------------------------------ + description_match = re.search(r"(?s)^\s*(.*?)\n\s*Usage:", output) + if description_match: + description = description_match.group(1).strip() + command_structure['description'] = replace_angle_brackets(description) + + # --- Extract Flags (including Global Flags) ----------------------------------- + flags = [] + # "Flags:" section + flags_match = re.search(r"(?sm)^Flags:\n(.*?)(?:\n\n|^\S|\Z)", output) + if flags_match: + flags_text = flags_match.group(1) + flags.extend(re.findall( + r"^\s+(-{1,2}[^\s,]+(?:,\s*-{1,2}[^\s,]+)*)\s+(.*)$", + flags_text, + re.MULTILINE + )) + + # "Global Flags:" section + global_flags_match = re.search(r"(?sm)^Global Flags:\n(.*?)(?:\n\n|^\S|\Z)", output) + if global_flags_match: + global_flags_text = global_flags_match.group(1) + flags.extend(re.findall( + r"^\s+(-{1,2}[^\s,]+(?:,\s*-{1,2}[^\s,]+)*)\s+(.*)$", + global_flags_text, + re.MULTILINE + )) + + if flags: + command_structure["flags"] = [ + { + "flag": f[0].strip(), + "description": replace_angle_brackets(f[1].strip()) + } + for f in flags + ] + + # --- Extract Subcommands ------------------------------------------------------ + subcommands_match = re.search( + r"(?sm)(?:^Available Commands?:\n|^Commands?:\n)(.*?)(?:\n\n|^\S|\Z)", + output + ) + if subcommands_match: + subcommands_text = subcommands_match.group(1) + # Lines like: " create Create a new something" + subcommand_lines = re.findall(r"^\s+([^\s]+)\s+(.*)$", subcommands_text, re.MULTILINE) + + for subcmd, sub_desc in sorted(set(subcommand_lines)): + sub_desc_clean = replace_angle_brackets(sub_desc.strip()) + sub_structure = get_command_structure( + cli_tool, + command_chain + [subcmd], + max_depth, + current_depth + 1, + processed_commands + ) + if sub_structure is not None: + if not sub_structure.get('description'): + sub_structure['description'] = sub_desc_clean + command_structure["subcommands"][subcmd] = sub_structure + else: + command_structure["subcommands"][subcmd] = { + "description": sub_desc_clean, + "flags": [], + "subcommands": {} + } + + processed_commands[command_key] = command_structure + return command_structure + +def generate_markdown(cli_structure, cli_tool, file_path): + """ + Generate a Markdown file from the CLI structure JSON object in a developer-friendly format. + No top-level subcommand bullet list. + """ + # Define a set of known type keywords. Adjust as needed. + known_types = { + "string", "bool", "int", "uint", "float", "duration", + "strings", "uint16", "uint32", "uint64", "int16", "int32", "int64", + "float32", "float64" + } + + def write_section(structure, file, command_chain=None): + if command_chain is None: + command_chain = [] + + # If at root level, do not print a heading or bullet list, just go straight + # to recursing through subcommands. + if command_chain: + # Determine heading level (but max out at H6) + heading_level = min(1 + len(command_chain), 6) + + # Build heading text: + if len(command_chain) == 1: + heading_text = f"{cli_tool} {command_chain[0]}" + else: + heading_text = ' '.join(command_chain[1:]) + + # Insert a single anchor before writing the heading + anchor = generate_anchor_id(cli_tool, command_chain) + file.write(f'\n') + file.write(f"{'#' * heading_level} {heading_text}\n\n") + + # Write description + if structure.get('description'): + file.write(f"{structure['description']}\n\n") + + # Write usage + full_command = f"{cli_tool} {' '.join(command_chain)}" + file.write("**Usage:**\n") + file.write(f"```bash\n{full_command} [subcommand] [flags]\n```\n\n") + + # Subcommands index + subcommands = structure.get('subcommands', {}) + if subcommands: + file.write("**Subcommands:**\n\n") + for subcmd in sorted(subcommands.keys()): + sub_desc = subcommands[subcmd].get('description', '') + sub_anchor = generate_anchor_id(cli_tool, command_chain + [subcmd]) + file.write(f"- [`{subcmd}`](#{sub_anchor}): {sub_desc}\n") + file.write("\n") + else: + subcommands = structure.get('subcommands', {}) + + # Flags (only if we have a command chain) + if command_chain and structure.get('flags'): + file.write("**Flags:**\n\n") + flag_lines = [] + for flag_dict in structure['flags']: + flag_names = flag_dict['flag'] + description = flag_dict['description'].strip() + + # Attempt to parse a recognized "type" from the first word. + desc_parts = description.split(None, 1) # Split once on whitespace + if len(desc_parts) == 2: + first_word, rest = desc_parts + # Check if the first word is in known_types + if first_word.lower() in known_types: + flag_type = first_word + flag_desc = rest + else: + flag_type = "" + flag_desc = description + else: + flag_type = "" + flag_desc = description + + if flag_type: + flag_line = f"{flag_names} {flag_type}" + else: + flag_line = flag_names + + flag_lines.append((flag_line, flag_desc)) + + # Determine formatting width + max_len = max(len(fl[0]) for fl in flag_lines) if flag_lines else 0 + file.write("```bash\n") + for fl, fd in flag_lines: + file.write(f"{fl.ljust(max_len)} {fd}\n") + file.write("```\n\n") + + # Recurse into subcommands + subcommands = structure.get('subcommands', {}) + for subcmd in sorted(subcommands.keys()): + write_section(subcommands[subcmd], file, command_chain + [subcmd]) + + with open(file_path, "w", encoding="utf-8") as f: + write_section(cli_structure, f) + +def main(): + cli_tool = "avalanche" # Adjust if needed + max_depth = 10 + + # Build the nested command structure + cli_structure = get_command_structure(cli_tool, max_depth=max_depth) + if cli_structure: + # Generate Markdown + generate_markdown(cli_structure, cli_tool, "cmd/commands.md") + print("Markdown documentation saved to cmd/commands.md") + else: + print("[ERROR] Failed to retrieve CLI structure") + +if __name__ == "__main__": + main() diff --git a/.github/scripts/sdk_doc.py b/.github/scripts/sdk_doc.py new file mode 100644 index 000000000..f16642d5f --- /dev/null +++ b/.github/scripts/sdk_doc.py @@ -0,0 +1,227 @@ +import os +import re +from typing import Dict, List, Optional, Set +from dataclasses import dataclass +import ast +import glob + +@dataclass +class GoParam: + name: str + type: str + description: str = "" + +@dataclass +class GoReturn: + type: str + description: str = "" + +class GoFunction: + def __init__(self, name: str, signature: str, doc: str): + self.name = name + self.signature = signature + self.description = "" + self.params: List[GoParam] = [] + self.returns: List[GoReturn] = [] + self.examples: List[str] = [] + self.notes: List[str] = [] + self.parse_doc(doc) + + def parse_doc(self, doc: str): + if not doc: + return + + sections = doc.split("\n") + current_section = "description" + current_example = [] + + for line in sections: + line = line.strip() + if not line: + continue + + # Parse section markers + if line.lower().startswith("@param"): + parts = line[6:].strip().split(" ", 2) + if len(parts) >= 2: + name, type_str = parts[0], parts[1] + desc = parts[2] if len(parts) > 2 else "" + self.params.append(GoParam(name, type_str, desc)) + continue + + if line.lower().startswith("@return"): + parts = line[7:].strip().split(" ", 1) + type_str = parts[0] + desc = parts[1] if len(parts) > 1 else "" + self.returns.append(GoReturn(type_str, desc)) + continue + + if line.lower().startswith("example:"): + current_section = "example" + continue + + if line.lower().startswith("note:"): + self.notes.append(line[5:].strip()) + continue + + # Handle content based on current section + if current_section == "example": + if line.startswith("```") and current_example: + self.examples.append("\n".join(current_example)) + current_example = [] + current_section = "description" + elif not line.startswith("```"): + current_example.append(line) + else: + if not self.description: + self.description = line + else: + self.description += " " + line + +class GoPackage: + def __init__(self, name: str, path: str): + self.name = name + self.path = path + self.functions: List[GoFunction] = [] + self.description = "" + self.examples: List[str] = [] + +def parse_go_file(file_path: str) -> List[GoFunction]: + """Parse a Go file and extract detailed function documentation.""" + functions = [] + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Regular expression for matching Go function declarations with docs + func_pattern = r'(?:/\*\*(.*?)\*/\s*)?func\s+(\w+)\s*\((.*?)\)(?:\s*\(?(.*?)\)?)?\s*{' + matches = re.finditer(func_pattern, content, re.DOTALL) + + for match in matches: + doc = match.group(1).strip() if match.group(1) else "" + name = match.group(2) + params = match.group(3) + returns = match.group(4) if match.group(4) else "" + + signature = f"func {name}({params})" + if returns: + signature += f" ({returns})" + + functions.append(GoFunction(name, signature, doc)) + + return functions + +def scan_sdk_packages(sdk_path: str) -> Dict[str, GoPackage]: + """Scan the SDK directory for Go packages.""" + packages = {} + + for root, _, files in os.walk(sdk_path): + go_files = [f for f in files if f.endswith('.go')] + if not go_files: + continue + + # Get package name from relative path + rel_path = os.path.relpath(root, sdk_path) + package_name = os.path.basename(rel_path) + + if package_name not in packages: + packages[package_name] = GoPackage(package_name, rel_path) + + # Parse package description from package comment in any go file + for go_file in go_files: + file_path = os.path.join(root, go_file) + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + pkg_doc_match = re.search(r'/\*\*(.*?)\*/\s*package', content, re.DOTALL) + if pkg_doc_match: + packages[package_name].description = pkg_doc_match.group(1).strip() + + # Parse functions from the file + functions = parse_go_file(file_path) + packages[package_name].functions.extend(functions) + + return packages + +def generate_single_markdown(packages: Dict[str, GoPackage], output_file: str): + """Generate a single markdown documentation file for all packages.""" + with open(output_file, 'w', encoding='utf-8') as f: + f.write('# SDK Documentation\n\n') + + # Generate table of contents + f.write('## Table of Contents\n\n') + for package_name in sorted(packages.keys()): + f.write(f'- [{package_name}](#{package_name.lower()})\n') + f.write('\n---\n\n') + + # Generate package documentation + for package_name, package in sorted(packages.items()): + f.write(f'## {package_name}\n\n') + + if package.description: + f.write(f'{package.description}\n\n') + + if package.examples: + f.write('### Package Examples\n\n') + for example in package.examples: + f.write('```go\n') + f.write(example) + f.write('\n```\n\n') + + f.write('### Functions\n\n') + for func in sorted(package.functions, key=lambda x: x.name): + f.write(f'#### {func.name}\n\n') + f.write('```go\n') + f.write(f'{func.signature}\n') + f.write('```\n\n') + + if func.description: + f.write(f'{func.description}\n\n') + + if func.params: + f.write('**Parameters:**\n\n') + for param in func.params: + f.write(f'- `{param.name}` ({param.type})') + if param.description: + f.write(f': {param.description}') + f.write('\n') + f.write('\n') + + if func.returns: + f.write('**Returns:**\n\n') + for ret in func.returns: + f.write(f'- ({ret.type})') + if ret.description: + f.write(f': {ret.description}') + f.write('\n') + f.write('\n') + + if func.examples: + f.write('**Examples:**\n\n') + for example in func.examples: + f.write('```go\n') + f.write(example) + f.write('\n```\n\n') + + if func.notes: + f.write('**Notes:**\n\n') + for note in func.notes: + f.write(f'- {note}\n') + f.write('\n') + + f.write('---\n\n') + +def main(): + # Get the absolute path to the SDK directory + script_dir = os.path.dirname(os.path.abspath(__file__)) + sdk_path = os.path.abspath(os.path.join(script_dir, '..', '..', 'sdk')) + output_file = os.path.join(sdk_path, 'SDK.md') + + print(f"Scanning SDK directory: {sdk_path}") + packages = scan_sdk_packages(sdk_path) + + print(f"Generating documentation in: {output_file}") + generate_single_markdown(packages, output_file) + + print("Documentation generation complete!") + +if __name__ == "__main__": + main() diff --git a/.github/workflows/assignee.yml b/.github/workflows/assignee.yml new file mode 100644 index 000000000..25357063e --- /dev/null +++ b/.github/workflows/assignee.yml @@ -0,0 +1,14 @@ +name: Auto Assign + +on: + pull_request: + types: [opened, ready_for_review] + +jobs: + assign: + runs-on: ubuntu-latest + steps: + - name: PR Auto Assignee + uses: kentaro-m/auto-assign-action@v2.0.0 + with: + configuration-path: ".github/config/auto_assign.yml" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8ae2c14e..da0cc87a1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,6 @@ on: push: tags: - "*" - branches: - - acp-77 jobs: # First confirm that the linting and unit tests pass at this commit prior to creating release artifacts. @@ -61,19 +59,8 @@ jobs: - name: Set up QEMU uses: docker/setup-qemu-action@v3 - - - name: Build Docker Image with acp77-latest tag - if: github.ref == 'refs/heads/acp-77' # special case for acp-77 branch - run: | - docker buildx build --pull --push --platform=linux/amd64,linux/arm64 \ - -t avaplatform/avalanche-cli:acp77-latest \ - -f ./Dockerfile . - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TELEMETRY_TOKEN: ${{ secrets.POSTHOG_PROD_TOKEN }} - name: Run GoReleaser - if: github.ref != 'refs/heads/acp-77' # skip for acp-77 branch uses: goreleaser/goreleaser-action@v2 with: distribution: goreleaser diff --git a/Makefile b/Makefile index 1f05eb4de..db1a63879 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SHELL = /usr/bin/env bash -o pipefail #.SHELLFLAGS = -ec ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -#Detect OS +#Detect OS params UNAME := $(shell uname -s | tr A-Z a-z) ARCH :=$(shell uname -m | tr A-Z a-z) DOCKER:= $(shell command -v docker 2> /dev/null) diff --git a/README.md b/README.md index 0e9b9f841..9f0b5f398 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ avalanche network start ## Notable Features -- Creation of Subnet-EVM, and custom virtual machine subnet configurations +- Creation of Subnet-EVM, and custom virtual machine blockchain configurations - Precompile integration and configuration - Local deployment of L1s for development and rapid prototyping - Fuji Testnet and Avalanche Mainnet deployment of L1s diff --git a/VERSION b/VERSION index fe4e75fb7..7b378be30 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.3 \ No newline at end of file +1.8.4 \ No newline at end of file diff --git a/cmd/blockchaincmd/add_validator.go b/cmd/blockchaincmd/add_validator.go index ad79174d5..871bf43ff 100644 --- a/cmd/blockchaincmd/add_validator.go +++ b/cmd/blockchaincmd/add_validator.go @@ -6,8 +6,11 @@ import ( "errors" "fmt" "math/big" + "strings" "time" + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/utils/units" @@ -26,26 +29,19 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/validatormanager" + "github.com/ava-labs/avalanche-cli/sdk/validator" "github.com/ava-labs/avalanchego/ids" avagoconstants "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/vms/platformvm" warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/spf13/cobra" ) var ( - addValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, - } - nodeIDStr string nodeEndpoint string - balance uint64 + balanceAVAX float64 weight uint64 startTimeStr string duration time.Duration @@ -60,6 +56,7 @@ var ( disableOwnerAddr string rpcURL string aggregatorLogLevel string + aggregatorLogToStdout bool delegationFee uint16 errNoSubnetID = errors.New("failed to find the subnet ID for this subnet, has it been deployed/created on this network?") @@ -90,11 +87,16 @@ Testnet or Mainnet.`, RunE: addValidator, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, addValidatorSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet only]") cmd.Flags().Uint64Var(&weight, "weight", constants.NonBootstrapValidatorWeight, "set the staking weight of the validator to add") - cmd.Flags().Uint64Var(&balance, "balance", 0, "set the AVAX balance of the validator that will be used for continuous fee on P-Chain") + cmd.Flags().Float64Var( + &balanceAVAX, + "balance", + 0, + "set the AVAX balance of the validator that will be used for continuous fee on P-Chain", + ) cmd.Flags().BoolVarP(&useEwoq, "ewoq", "e", false, "use ewoq key [fuji/devnet only]") cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet)") cmd.Flags().StringSliceVar(&ledgerAddresses, "ledger-addrs", []string{}, "use the given ledger addresses") @@ -110,7 +112,8 @@ Testnet or Mainnet.`, cmd.Flags().BoolVar(&aggregatorAllowPrivatePeers, "aggregator-allow-private-peers", true, "allow the signature aggregator to connect to peers with private IP") privateKeyFlags.AddToCmd(cmd, "to pay fees for completing the validator's registration (blockchain gas token)") cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint") - cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") + cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator") + cmd.Flags().BoolVar(&aggregatorLogToStdout, "aggregator-log-to-stdout", false, "use stdout for signature aggregator logs") cmd.Flags().DurationVar(&duration, "staking-period", 0, "how long this validator will be staking") cmd.Flags().BoolVar(&useDefaultStartTime, "default-start-time", false, "(for Subnets, not L1s) use default start time for subnet validator (5 minutes later for fuji & mainnet, 30 seconds later for devnet)") cmd.Flags().StringVar(&startTimeStr, "start-time", "", "(for Subnets, not L1s) UTC start time when this validator starts validating, in 'YYYY-MM-DD HH:MM:SS' format") @@ -148,14 +151,13 @@ func addValidator(_ *cobra.Command, args []string) error { return fmt.Errorf("failed to load sidecar: %w", err) } - networkOptionsList := networkoptions.GetNetworkFromSidecar(sc, addValidatorSupportedNetworkOptions) network, err := networkoptions.GetNetworkFromCmdLineFlags( app, "", globalNetworkFlags, true, false, - networkOptionsList, + networkoptions.GetNetworkFromSidecar(sc, networkoptions.DefaultSupportedNetworkOptions), "", ) if err != nil { @@ -216,6 +218,8 @@ func addValidator(_ *cobra.Command, args []string) error { } } + subnetID := sc.Networks[network.Name()].SubnetID + // if user chose to upsize a local node to add another local validator if createLocalValidator { anrSettings := node.ANRSettings{} @@ -237,7 +241,6 @@ func addValidator(_ *cobra.Command, args []string) error { nodeName := "" blockchainID := sc.Networks[network.Name()].BlockchainID - subnetID := sc.Networks[network.Name()].SubnetID if nodeName, err = node.UpsizeLocalNode( app, @@ -300,10 +303,23 @@ func addValidator(_ *cobra.Command, args []string) error { if !sovereign { return CallAddValidatorNonSOV(deployer, network, kc, useLedger, blockchainName, nodeIDStr, defaultValidatorParams, waitForTxAcceptance) } - return CallAddValidator(deployer, network, kc, blockchainName, nodeIDStr, publicKey, pop) + return CallAddValidator( + deployer, + network, + kc, + blockchainName, + subnetID, + nodeIDStr, + publicKey, + pop, + weight, + balanceAVAX, + remainingBalanceOwnerAddr, + disableOwnerAddr, + ) } -func promptValidatorBalance(availableBalance uint64) (uint64, error) { +func promptValidatorBalanceAVAX(availableBalance float64) (float64, error) { ux.Logger.PrintToUser("Validator's balance is used to pay for continuous fee to the P-Chain") ux.Logger.PrintToUser("When this Balance reaches 0, the validator will be considered inactive and will no longer participate in validating the L1") txt := "What balance would you like to assign to the validator (in AVAX)?" @@ -315,20 +331,25 @@ func CallAddValidator( network models.Network, kc *keychain.Keychain, blockchainName string, + subnetID ids.ID, nodeIDStr string, publicKey string, pop string, + weight uint64, + balanceAVAX float64, + remainingBalanceOwnerAddr string, + disableOwnerAddr string, ) error { nodeID, err := ids.NodeIDFromString(nodeIDStr) if err != nil { return err } - blsInfo, err := getBLSInfo(publicKey, pop) + blsInfo, err := blockchain.ConvertToBLSProofOfPossession(publicKey, pop) if err != nil { return fmt.Errorf("failure parsing BLS info: %w", err) } - blockchainTimestamp, err := getBlockchainTimestamp(network) + blockchainTimestamp, err := blockchain.GetBlockchainTimestamp(network) if err != nil { return fmt.Errorf("failed to get blockchain timestamp: %w", err) } @@ -398,22 +419,30 @@ func CallAddValidator( ux.Logger.PrintToUser(logging.Yellow.Wrap("RPC Endpoint: %s"), rpcURL) - if balance == 0 { + totalWeight, err := validator.GetTotalWeight(network.SDKNetwork(), subnetID) + if err != nil { + return err + } + allowedChange := float64(totalWeight) * constants.MaxL1TotalWeightChange + if float64(weight) > allowedChange { + return fmt.Errorf("can't make change: desired validator weight %d exceeds max allowed weight change of %d", newWeight, uint64(allowedChange)) + } + + if balanceAVAX == 0 { availableBalance, err := utils.GetNetworkBalance(kc.Addresses().List(), network.Endpoint) if err != nil { return err } - balance, err = promptValidatorBalance(availableBalance / units.Avax) + balanceAVAX, err = promptValidatorBalanceAVAX(float64(availableBalance) / float64(units.Avax)) if err != nil { return err } - } else { - // convert to nanoAVAX - balance *= units.Avax } + // convert to nanoAVAX + balance := uint64(balanceAVAX * float64(units.Avax)) if remainingBalanceOwnerAddr == "" { - remainingBalanceOwnerAddr, err = getKeyForChangeOwner(network) + remainingBalanceOwnerAddr, err = blockchain.GetKeyForChangeOwner(app, network) if err != nil { return err } @@ -451,7 +480,18 @@ func CallAddValidator( Addresses: disableOwnerAddrID, } - extraAggregatorPeers, err := GetAggregatorExtraPeers(clusterNameFlagValue, aggregatorExtraEndpoints) + extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterNameFlagValue, aggregatorExtraEndpoints) + if err != nil { + return err + } + aggregatorLogger, err := utils.NewLogger( + constants.SignatureAggregatorLogName, + aggregatorLogLevel, + constants.DefaultAggregatorLogLevel, + app.GetAggregatorLogDir(clusterNameFlagValue), + aggregatorLogToStdout, + ux.Logger.PrintToUser, + ) if err != nil { return err } @@ -469,7 +509,7 @@ func CallAddValidator( weight, extraAggregatorPeers, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, pos, delegationFee, duration, @@ -482,14 +522,17 @@ func CallAddValidator( txID, _, err := deployer.RegisterL1Validator(balance, blsInfo, signedMessage) if err != nil { - return err - } - ux.Logger.PrintToUser("RegisterL1ValidatorTx ID: %s", txID) - - if err := UpdatePChainHeight( - "Waiting for P-Chain to update validator information ...", - ); err != nil { - return err + if !strings.Contains(err.Error(), "warp message already issued for validationID") { + return err + } + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The Validation ID was already registered on the P-Chain. Proceeding to the next step")) + } else { + ux.Logger.PrintToUser("RegisterL1ValidatorTx ID: %s", txID) + if err := blockchain.UpdatePChainHeight( + "Waiting for P-Chain to update validator information ...", + ); err != nil { + return err + } } if err := validatormanager.FinishValidatorRegistration( @@ -501,7 +544,7 @@ func CallAddValidator( validationID, extraAggregatorPeers, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, ); err != nil { return err } @@ -512,7 +555,7 @@ func CallAddValidator( if !pos { ux.Logger.PrintToUser(" Weight: %d", weight) } - ux.Logger.PrintToUser(" Balance: %d", balance/units.Avax) + ux.Logger.PrintToUser(" Balance: %.2f", balanceAVAX) ux.Logger.GreenCheckmarkToUser("Validator successfully added to the L1") return nil @@ -598,7 +641,7 @@ func CallAddValidatorNonSOV( return err } } - ux.Logger.PrintToUser("Your subnet auth keys for add validator tx creation: %s", subnetAuthKeys) + ux.Logger.PrintToUser("Your auth keys for add validator tx creation: %s", subnetAuthKeys) selectedWeight, err := getWeight() if err != nil { @@ -680,13 +723,6 @@ func PromptDuration(start time.Time, network models.Network, isPos bool) (time.D } } -func getBlockchainTimestamp(network models.Network) (time.Time, error) { - ctx, cancel := utils.GetAPIContext() - defer cancel() - platformCli := platformvm.NewClient(network.Endpoint) - return platformCli.GetTimestamp(ctx) -} - func getTimeParameters(network models.Network, nodeID ids.NodeID, isValidator bool) (time.Time, time.Duration, error) { defaultStakingStartLeadTime := constants.StakingStartLeadTime if network.Kind == models.Devnet { @@ -801,7 +837,7 @@ func getWeight() (uint64, error) { case defaultWeight: useDefaultWeight = true default: - weight, err = app.Prompt.CaptureWeight(txt) + weight, err = app.Prompt.CaptureWeight(txt, func(uint64) error { return nil }) if err != nil { return 0, err } diff --git a/cmd/blockchaincmd/blockchain.go b/cmd/blockchaincmd/blockchain.go index 54989cd6c..6e4026ac0 100644 --- a/cmd/blockchaincmd/blockchain.go +++ b/cmd/blockchaincmd/blockchain.go @@ -56,11 +56,11 @@ manage your Blockchain configurations and live deployments.`, cmd.AddCommand(vmidCmd()) // blockchain removeValidator cmd.AddCommand(newRemoveValidatorCmd()) - // subnet validators + // blockchain validators cmd.AddCommand(newValidatorsCmd()) - // subnet changeOwner + // blockchain changeOwner cmd.AddCommand(newChangeOwnerCmd()) - // subnet changeWeight + // blockchain changeWeight cmd.AddCommand(newChangeWeightCmd()) return cmd } diff --git a/cmd/blockchaincmd/change_owner.go b/cmd/blockchaincmd/change_owner.go index 737e0d8af..4bcab5f73 100644 --- a/cmd/blockchaincmd/change_owner.go +++ b/cmd/blockchaincmd/change_owner.go @@ -18,32 +18,25 @@ import ( "github.com/spf13/cobra" ) -var changeOwnerSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - // avalanche blockchain changeOwner func newChangeOwnerCmd() *cobra.Command { cmd := &cobra.Command{ Use: "changeOwner [blockchainName]", - Short: "Change owner of the blockchain's subnet", - Long: `The blockchain changeOwner changes the owner of the subnet of the deployed Blockchain.`, + Short: "Change owner of the blockchain", + Long: `The blockchain changeOwner changes the owner of the deployed Blockchain.`, RunE: changeOwner, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, changeOwnerSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet)") cmd.Flags().StringSliceVar(&ledgerAddresses, "ledger-addrs", []string{}, "use the given ledger addresses") cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet]") cmd.Flags().BoolVarP(&useEwoq, "ewoq", "e", false, "use ewoq key [fuji/devnet]") - cmd.Flags().StringSliceVar(&subnetAuthKeys, "subnet-auth-keys", nil, "control keys that will be used to authenticate transfer subnet ownership tx") + cmd.Flags().StringSliceVar(&subnetAuthKeys, "auth-keys", nil, "control keys that will be used to authenticate transfer blockchain ownership tx") cmd.Flags().BoolVarP(&sameControlKey, "same-control-key", "s", false, "use the fee-paying key as control key") - cmd.Flags().StringSliceVar(&controlKeys, "control-keys", nil, "addresses that may make subnet changes") - cmd.Flags().Uint32Var(&threshold, "threshold", 0, "required number of control key signatures to make subnet changes") - cmd.Flags().StringVar(&outputTxPath, "output-tx-path", "", "file path of the transfer subnet ownership tx") + cmd.Flags().StringSliceVar(&controlKeys, "control-keys", nil, "addresses that may make blockchain changes") + cmd.Flags().Uint32Var(&threshold, "threshold", 0, "required number of control key signatures to make blockchain changes") + cmd.Flags().StringVar(&outputTxPath, "output-tx-path", "", "file path of the transfer blockchain ownership tx") return cmd } @@ -56,7 +49,7 @@ func changeOwner(_ *cobra.Command, args []string) error { globalNetworkFlags, true, false, - changeOwnerSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -134,7 +127,7 @@ func changeOwner(_ *cobra.Command, args []string) error { return err } } - ux.Logger.PrintToUser("Your subnet auth keys for add validator tx creation: %s", subnetAuthKeys) + ux.Logger.PrintToUser("Your auth keys for add validator tx creation: %s", subnetAuthKeys) controlKeys, threshold, err = promptOwners( kc, @@ -161,7 +154,7 @@ func changeOwner(_ *cobra.Command, args []string) error { } if !isFullySigned { if err := SaveNotFullySignedTx( - "Transfer Subnet Ownership", + "Transfer Blockchain Ownership", tx, blockchainName, subnetAuthKeys, diff --git a/cmd/blockchaincmd/change_weight.go b/cmd/blockchaincmd/change_weight.go index 18b496c67..33e54e143 100644 --- a/cmd/blockchaincmd/change_weight.go +++ b/cmd/blockchaincmd/change_weight.go @@ -3,39 +3,48 @@ package blockchaincmd import ( - "errors" "fmt" - "os" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" "github.com/ava-labs/avalanche-cli/pkg/constants" + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/key" "github.com/ava-labs/avalanche-cli/pkg/keychain" - "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" + "github.com/ava-labs/avalanche-cli/pkg/node" "github.com/ava-labs/avalanche-cli/pkg/prompts" "github.com/ava-labs/avalanche-cli/pkg/subnet" + "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/sdk/validator" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/formatting" + "github.com/ava-labs/avalanchego/utils/formatting/address" + "github.com/ava-labs/avalanchego/utils/units" "github.com/spf13/cobra" ) +var newWeight uint64 + // avalanche blockchain addValidator func newChangeWeightCmd() *cobra.Command { cmd := &cobra.Command{ Use: "changeWeight [blockchainName]", - Short: "Changes the weight of a Subnet validator", - Long: `The blockchain changeWeight command changes the weight of a Subnet Validator. + Short: "Changes the weight of a L1 validator", + Long: `The blockchain changeWeight command changes the weight of a L1 Validator. -The Subnet has to be a Proof of Authority Subnet-Only Validator Subnet.`, +The L1 has to be a Proof of Authority L1.`, RunE: setWeight, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, addValidatorSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet only]") - cmd.Flags().Uint64Var(&weight, "weight", constants.NonBootstrapValidatorWeight, "set the new staking weight of the validator") + cmd.Flags().Uint64Var(&newWeight, "weight", 0, "set the new staking weight of the validator") cmd.Flags().BoolVarP(&useEwoq, "ewoq", "e", false, "use ewoq key [fuji/devnet only]") cmd.Flags().StringVar(&nodeIDStr, "node-id", "", "node-id of the validator") + cmd.Flags().StringVar(&nodeEndpoint, "node-endpoint", "", "gather node id/bls from publicly available avalanchego apis on the given endpoint") cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet)") cmd.Flags().StringSliceVar(&ledgerAddresses, "ledger-addrs", []string{}, "use the given ledger addresses") return cmd @@ -43,17 +52,13 @@ The Subnet has to be a Proof of Authority Subnet-Only Validator Subnet.`, func setWeight(_ *cobra.Command, args []string) error { blockchainName := args[0] - err := prompts.ValidateNodeID(nodeIDStr) - if err != nil { - return err - } sc, err := app.LoadSidecar(blockchainName) if err != nil { return fmt.Errorf("failed to load sidecar: %w", err) } - networkOptionsList := networkoptions.GetNetworkFromSidecar(sc, removeValidatorSupportedNetworkOptions) + networkOptionsList := networkoptions.GetNetworkFromSidecar(sc, networkoptions.DefaultSupportedNetworkOptions) network, err := networkoptions.GetNetworkFromCmdLineFlags( app, "", @@ -67,47 +72,17 @@ func setWeight(_ *cobra.Command, args []string) error { return err } - if outputTxPath != "" { - if _, err := os.Stat(outputTxPath); err == nil { - return fmt.Errorf("outputTxPath %q already exists", outputTxPath) - } - } - - if len(ledgerAddresses) > 0 { - useLedger = true - } - - if useLedger && keyName != "" { - return ErrMutuallyExlusiveKeyLedger - } - - switch network.Kind { - case models.Devnet: - if !useLedger && keyName == "" { - useLedger, keyName, err = prompts.GetKeyOrLedger(app.Prompt, constants.PayTxsFeesMsg, app.GetKeyDir(), false) - if err != nil { - return err - } - } - case models.Fuji: - if !useLedger && keyName == "" { - useLedger, keyName, err = prompts.GetKeyOrLedger(app.Prompt, constants.PayTxsFeesMsg, app.GetKeyDir(), false) - if err != nil { - return err - } - } - case models.Mainnet: - useLedger = true - if keyName != "" { - return ErrStoredKeyOnMainnet - } - default: - return errors.New("unsupported network") - } - - // get keychain accesor fee := network.GenesisParams().TxFeeConfig.StaticFeeConfig.TxFee - kc, err := keychain.GetKeychain(app, false, useLedger, ledgerAddresses, keyName, network, fee) + kc, err := keychain.GetKeychainFromCmdLineFlags( + app, + "to pay for transaction fees on P-Chain", + network, + keyName, + useEwoq, + useLedger, + ledgerAddresses, + fee, + ) if err != nil { return err } @@ -119,81 +94,164 @@ func setWeight(_ *cobra.Command, args []string) error { return errNoSubnetID } + if nodeEndpoint != "" { + nodeIDStr, publicKey, pop, err = node.GetNodeData(nodeEndpoint) + if err != nil { + return err + } + } + var nodeID ids.NodeID if nodeIDStr == "" { - nodeID, err = PromptNodeID("add as a blockchain validator") + nodeID, err = PromptNodeID("change weight") if err != nil { return err } } else { + if err := prompts.ValidateNodeID(nodeIDStr); err != nil { + return err + } nodeID, err = ids.NodeIDFromString(nodeIDStr) if err != nil { return err } } - isValidator, err := subnet.IsSubnetValidator(subnetID, nodeID, network) + isValidator, err := validator.IsValidator(network.SDKNetwork(), subnetID, nodeID) if err != nil { // just warn the user, don't fail - ux.Logger.PrintToUser("failed to check if node is a validator on the subnet: %s", err) + ux.Logger.PrintToUser("failed to check if node is a validator: %s", err) } else if !isValidator { // this is actually an error - return fmt.Errorf("node %s is not a validator on subnet %s", nodeID, subnetID) + return fmt.Errorf("node %s is not a validator for blockchain %s", nodeID, subnetID) } - deployer := subnet.NewPublicDeployer(app, kc, network) + chainSpec := contract.ChainSpec{ + BlockchainName: blockchainName, + } - // first remove the validator from subnet - err = removeValidatorSOV(deployer, - network, - blockchainName, - nodeID, - 0, // automatic uptime - isBootstrapValidatorForNetwork(nodeID, sc.Networks[network.Name()]), - false, // don't force - ) + if rpcURL == "" { + rpcURL, _, err = contract.GetBlockchainEndpoints( + app, + network, + chainSpec, + true, + false, + ) + if err != nil { + return err + } + } + + validationID, err := validator.GetValidationID(rpcURL, nodeID) if err != nil { return err } - // TODO: we need to wait for the balance from the removed validator to arrive in changeAddr - // set arbitrary time.sleep here? - - weight, err = app.Prompt.CaptureWeight("What weight would you like to assign to the validator?") + validatorInfo, err := validator.GetValidatorInfo(network.SDKNetwork(), validationID) if err != nil { return err } - balance, err = getValidatorBalanceFromPChain() + totalWeight, err := validator.GetTotalWeight(network.SDKNetwork(), subnetID) if err != nil { return err } - publicKey, pop, err = getBLSInfoFromPChain() + allowedChange := float64(totalWeight) * constants.MaxL1TotalWeightChange + + if float64(validatorInfo.Weight) > allowedChange { + return fmt.Errorf("can't make change: current validator weight %d exceeds max allowed weight change of %d", validatorInfo.Weight, uint64(allowedChange)) + } + + allowedChange = float64(totalWeight-validatorInfo.Weight) * constants.MaxL1TotalWeightChange + + if newWeight == 0 { + ux.Logger.PrintToUser("Current validator weight is %d", validatorInfo.Weight) + newWeight, err = app.Prompt.CaptureWeight( + "What weight would you like to assign to the validator?", + func(v uint64) error { + if v > uint64(allowedChange) { + return fmt.Errorf("weight exceeds max allowed weight change of %d", uint64(allowedChange)) + } + return nil + }, + ) + if err != nil { + return err + } + } + + if float64(newWeight) > allowedChange { + return fmt.Errorf("can't make change: desired validator weight %d exceeds max allowed weight change of %d", newWeight, uint64(allowedChange)) + } + + publicKey, err = formatting.Encode(formatting.HexNC, bls.PublicKeyToCompressedBytes(validatorInfo.PublicKey)) if err != nil { return err } - remainingBalanceOwnerAddr, err = getChangeAddrFromPChain() - if err != nil { - return fmt.Errorf("failure parsing change owner address: %w", err) + if pop == "" { + _, pop, err = promptProofOfPossession(false, true) + if err != nil { + return err + } } - // add back validator to subnet with updated weight - return CallAddValidator(deployer, network, kc, blockchainName, nodeID.String(), publicKey, pop) -} + deployer := subnet.NewPublicDeployer(app, kc, network) -// getValidatorBalanceFromPChain gets remaining balance of validator from p chain -func getValidatorBalanceFromPChain() (uint64, error) { - return 0, nil -} + var remainingBalanceOwnerAddr, disableOwnerAddr string + hrp := key.GetHRP(network.ID) + if validatorInfo.RemainingBalanceOwner != nil && len(validatorInfo.RemainingBalanceOwner.Addrs) > 0 { + remainingBalanceOwnerAddr, err = address.Format("P", hrp, validatorInfo.RemainingBalanceOwner.Addrs[0][:]) + if err != nil { + return err + } + } + if validatorInfo.DeactivationOwner != nil && len(validatorInfo.DeactivationOwner.Addrs) > 0 { + disableOwnerAddr, err = address.Format("P", hrp, validatorInfo.DeactivationOwner.Addrs[0][:]) + if err != nil { + return err + } + } -// getBLSInfoFromPChain gets BLS public key and pop from info api -func getBLSInfoFromPChain() (string, string, error) { - return "", "", nil -} + // first remove the validator from subnet + err = removeValidatorSOV( + deployer, + network, + blockchainName, + nodeID, + 0, // automatic uptime + isBootstrapValidatorForNetwork(nodeID, sc.Networks[network.Name()]), + false, // don't force + ) + if err != nil { + return err + } -// getChangeAddrFromPChain gets validator change addr from info api -func getChangeAddrFromPChain() (string, error) { - return "", nil + balance := validatorInfo.Balance + if validatorInfo.RemainingBalanceOwner != nil && len(validatorInfo.RemainingBalanceOwner.Addrs) > 0 { + availableBalance, err := utils.GetNetworkBalance([]ids.ShortID{validatorInfo.RemainingBalanceOwner.Addrs[0]}, network.Endpoint) + if err != nil { + ux.Logger.RedXToUser("failure checking remaining balance of validator: %s. continuing with default value", err) + } else if availableBalance < balance { + balance = availableBalance + } + } + + // add back validator to subnet with updated weight + return CallAddValidator( + deployer, + network, + kc, + blockchainName, + subnetID, + nodeID.String(), + publicKey, + pop, + newWeight, + float64(balance)/float64(units.Avax), + remainingBalanceOwnerAddr, + disableOwnerAddr, + ) } diff --git a/cmd/blockchaincmd/configure.go b/cmd/blockchaincmd/configure.go index dfc8328ba..af3ae7421 100644 --- a/cmd/blockchaincmd/configure.go +++ b/cmd/blockchaincmd/configure.go @@ -27,8 +27,7 @@ func newConfigureCmd() *cobra.Command { cmd := &cobra.Command{ Use: "configure [blockchainName]", Short: "Adds additional config files for the avalanchego nodes", - Long: `AvalancheGo nodes support several different configuration files. Subnets have their own -Subnet config which applies to all chains/VMs in the Subnet. Each chain within the Subnet + Long: `AvalancheGo nodes support several different configuration files. Each network (a Subnet or an L1) has their own config which applies to all blockchains/VMs in the network. Each blockchain within the network can have its own chain config. A chain can also have special requirements for the AvalancheGo node configuration itself. This command allows you to set all those files.`, RunE: configure, diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index 9edd0720b..69da4c362 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -172,7 +172,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } if err := checkInvalidSubnetNames(blockchainName); err != nil { - return fmt.Errorf("subnet name %q is invalid: %w", blockchainName, err) + return fmt.Errorf("blockchain name %q is invalid: %w", blockchainName, err) } // version flags exclusiveness @@ -260,29 +260,8 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { if vmType == models.SubnetEvm { if sovereign { - // if validatorManagerOwner flag is used, we get the C Chain address of the key used - if createFlags.validatorManagerOwner != "" { - if err = validateValidatorManagerOwnerFlag(createFlags.validatorManagerOwner); err != nil { - return err - } - } - if createFlags.validatorManagerOwner == "" { - createFlags.validatorManagerOwner, err = getValidatorContractManagerAddr() - if err != nil { - return err - } - } - sc.ValidatorManagerOwner = createFlags.validatorManagerOwner - ux.Logger.GreenCheckmarkToUser("Validator Manager Contract owner address %s", createFlags.validatorManagerOwner) - - // use the validator manager owner as the transparent proxy contract owner unless specified via cmd flag - if createFlags.proxyContractOwner != "" { - if err = validateValidatorManagerOwnerFlag(createFlags.proxyContractOwner); err != nil { - return err - } - sc.ProxyContractOwner = createFlags.proxyContractOwner - } else { - sc.ProxyContractOwner = sc.ValidatorManagerOwner + if err := setSidecarValidatorManageOwner(sc, createFlags); err != nil { + return err } } @@ -296,7 +275,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { // get vm version vmVersion := createFlags.vmVersion - if createFlags.useLatestReleasedVMVersion || defaultsKind != vm.NoDefaults { + if vmVersion == "" && (createFlags.useLatestReleasedVMVersion || defaultsKind != vm.NoDefaults) { vmVersion = latest } if createFlags.useLatestPreReleasedVMVersion { @@ -385,6 +364,11 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } var tokenSymbol string if evmCompatibleGenesis := utils.ByteSliceIsSubnetEvmGenesis(genesisBytes); evmCompatibleGenesis { + if sovereign { + if err := setSidecarValidatorManageOwner(sc, createFlags); err != nil { + return err + } + } tokenSymbol, err = vm.PromptTokenSymbol(app, createFlags.tokenSymbol) if err != nil { return err @@ -558,3 +542,28 @@ func checkInvalidSubnetNames(name string) error { } return nil } + +func setSidecarValidatorManageOwner(sc *models.Sidecar, createFlags CreateFlags) error { + var err error + if createFlags.validatorManagerOwner == "" { + createFlags.validatorManagerOwner, err = getValidatorContractManagerAddr() + if err != nil { + return err + } + } + if err := validateValidatorManagerOwnerFlag(createFlags.validatorManagerOwner); err != nil { + return err + } + sc.ValidatorManagerOwner = createFlags.validatorManagerOwner + ux.Logger.GreenCheckmarkToUser("Validator Manager Contract owner address %s", createFlags.validatorManagerOwner) + // use the validator manager owner as the transparent proxy contract owner unless specified via cmd flag + if createFlags.proxyContractOwner != "" { + if err = validateValidatorManagerOwnerFlag(createFlags.proxyContractOwner); err != nil { + return err + } + sc.ProxyContractOwner = createFlags.proxyContractOwner + } else { + sc.ProxyContractOwner = sc.ValidatorManagerOwner + } + return nil +} diff --git a/cmd/blockchaincmd/deploy.go b/cmd/blockchaincmd/deploy.go index 69e92b6ec..dc19a3070 100644 --- a/cmd/blockchaincmd/deploy.go +++ b/cmd/blockchaincmd/deploy.go @@ -13,6 +13,8 @@ import ( "strings" "time" + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + "github.com/ava-labs/avalanche-cli/cmd/interchaincmd/messengercmd" "github.com/ava-labs/avalanche-cli/cmd/interchaincmd/relayercmd" "github.com/ava-labs/avalanche-cli/cmd/networkcmd" @@ -39,7 +41,6 @@ import ( "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/network/peer" avagoutils "github.com/ava-labs/avalanchego/utils" "github.com/ava-labs/avalanchego/utils/formatting/address" "github.com/ava-labs/avalanchego/utils/logging" @@ -51,19 +52,12 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/ethereum/go-ethereum/common" - "github.com/olekukonko/tablewriter" + "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" ) const skipRelayerFlagName = "skip-relayer" -var deploySupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - var ( sameControlKey bool keyName string @@ -128,12 +122,12 @@ attempts to deploy the same Blockchain to the same network (local, Fuji, Mainnet allowed. If you'd like to redeploy a Blockchain locally for testing, you must first call avalanche network clean to reset all deployed chain state. Subsequent local deploys redeploy the chain with fresh state. You can deploy the same Blockchain to multiple networks, -so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, +so you can take your locally tested Blockchain and deploy it on Fuji or Mainnet.`, RunE: deployBlockchain, PersistentPostRun: handlePostRun, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, deploySupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) privateKeyFlags.SetFlagNames("blockchain-private-key", "blockchain-key", "blockchain-genesis-key") privateKeyFlags.AddToCmd(cmd, "to fund validator manager initialization") cmd.Flags().StringVar( @@ -144,9 +138,9 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, ) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet deploy only]") cmd.Flags().BoolVarP(&sameControlKey, "same-control-key", "s", false, "use the fee-paying key as control key") - cmd.Flags().Uint32Var(&threshold, "threshold", 0, "required number of control key signatures to make subnet changes") - cmd.Flags().StringSliceVar(&controlKeys, "control-keys", nil, "addresses that may make subnet changes") - cmd.Flags().StringSliceVar(&subnetAuthKeys, "subnet-auth-keys", nil, "control keys that will be used to authenticate chain creation") + cmd.Flags().Uint32Var(&threshold, "threshold", 0, "required number of control key signatures to make blockchain changes") + cmd.Flags().StringSliceVar(&controlKeys, "control-keys", nil, "addresses that may make blockchain changes") + cmd.Flags().StringSliceVar(&subnetAuthKeys, "auth-keys", nil, "control keys that will be used to authenticate chain creation") cmd.Flags().StringVar(&outputTxPath, "output-tx-path", "", "file path of the blockchain creation tx") cmd.Flags().BoolVarP(&useEwoq, "ewoq", "e", false, "use ewoq key [fuji/devnet deploy only]") cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet)") @@ -158,6 +152,7 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, cmd.Flags().BoolVar(&icmSpec.SkipICMDeploy, "skip-local-teleporter", false, "skip automatic ICM deploy on local networks [to be deprecated]") cmd.Flags().BoolVar(&icmSpec.SkipICMDeploy, "skip-teleporter-deploy", false, "skip automatic ICM deploy") cmd.Flags().BoolVar(&icmSpec.SkipICMDeploy, "skip-icm-deploy", false, "skip automatic ICM deploy") + cmd.Flags().BoolVar(&icmSpec.SkipICMDeploy, "noicm", false, "skip automatic ICM deploy") cmd.Flags().BoolVar(&icmSpec.SkipRelayerDeploy, skipRelayerFlagName, false, "skip relayer deploy") cmd.Flags().StringVar( &icmSpec.ICMVersion, @@ -194,7 +189,8 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, 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-endpoints", nil, "take validator node info from the given endpoints") cmd.Flags().BoolVar(&convertOnly, "convert-only", false, "avoid node track, restart and poa manager setup") - cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") + cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator") + cmd.Flags().BoolVar(&aggregatorLogToStdout, "aggregator-log-to-stdout", false, "use stdout for signature aggregator logs") cmd.Flags().StringSliceVar(&aggregatorExtraEndpoints, "aggregator-extra-endpoints", nil, "endpoints for extra nodes that are needed in signature aggregation") cmd.Flags().BoolVar(&aggregatorAllowPrivatePeers, "aggregator-allow-private-peers", true, "allow the signature aggregator to connect to peers with private IP") cmd.Flags().BoolVar(&useLocalMachine, "use-local-machine", false, "use local machine as a blockchain validator") @@ -210,7 +206,7 @@ so you can take your locally tested Subnet and deploy it on Fuji or Mainnet.`, cmd.Flags().Uint64Var(&poSMinimumStakeAmount, "pos-minimum-stake-amount", 1, "minimum stake amount") cmd.Flags().Uint64Var(&poSMaximumStakeAmount, "pos-maximum-stake-amount", 1000, "maximum stake amount") - cmd.Flags().Uint64Var(&poSMinimumStakeDuration, "pos-minimum-stake-duration", 100, "minimum stake duration") + cmd.Flags().Uint64Var(&poSMinimumStakeDuration, "pos-minimum-stake-duration", constants.PoSL1MinimumStakeDurationSeconds, "minimum stake duration (in seconds)") cmd.Flags().Uint16Var(&poSMinimumDelegationFee, "pos-minimum-delegation-fee", 1, "minimum delegation fee") cmd.Flags().Uint8Var(&poSMaximumStakeMultiplier, "pos-maximum-stake-multiplier", 1, "maximum stake multiplier") cmd.Flags().Uint64Var(&poSWeightToValueFactor, "pos-weight-to-value-factor", 1, "weight to value factor") @@ -309,9 +305,8 @@ func checkSubnetEVMDefaultAddressNotInAlloc(network models.Network, chain string return nil } -func runDeploy(cmd *cobra.Command, args []string, supportedNetworkOptions []networkoptions.NetworkOption) error { +func runDeploy(cmd *cobra.Command, args []string) error { skipCreatePrompt = true - deploySupportedNetworkOptions = supportedNetworkOptions return deployBlockchain(cmd, args) } @@ -368,7 +363,7 @@ func getSubnetEVMMainnetChainID(sc *models.Sidecar, blockchainName string) error if decision == useSameChainID { sc.SubnetEVMMainnetChainID = uint(originalChainID) } else { - ux.Logger.PrintToUser("Enter your subnet's ChainID. It can be any positive integer != %d.", originalChainID) + ux.Logger.PrintToUser("Enter your blockchain's ChainID. It can be any positive integer != %d.", originalChainID) newChainID, err := app.Prompt.CapturePositiveInt( "ChainID", []prompts.Comparator{ @@ -428,7 +423,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { } if sidecar.ImportedFromAPM { - return errors.New("unable to deploy subnets imported from a repo") + return errors.New("unable to deploy blockchains imported from a repo") } if outputTxPath != "" { @@ -447,7 +442,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { globalNetworkFlags, true, false, - deploySupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -621,7 +616,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { bootstrapEndpoints, err = getLocalBootstrapEndpoints() if err != nil { return fmt.Errorf("error getting local host bootstrap endpoints: %w, "+ - "please create your local node again and call subnet deploy command again", err) + "please create your local node again and call blockchain deploy command again", err) } } network = models.ConvertClusterToNetwork(network) @@ -647,6 +642,26 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { } // if no cluster provided - we create one with fmt.Sprintf("%s-local-node-%s", blockchainName, networkNameComponent) name if useLocalMachine && clusterNameFlagValue == "" { + if clusterExists, err := node.CheckClusterIsLocal(app, clusterName); err != nil { + return err + } else if clusterExists { + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser( + logging.Red.Wrap("A local machine L1 deploy already exists for %s L1 and network %s"), + blockchainName, + network.Name(), + ) + yes, err := app.Prompt.CaptureNoYes( + fmt.Sprintf("Do you want to overwrite the current local L1 deploy for %s?", blockchainName), + ) + if err != nil { + return err + } + if !yes { + return nil + } + _ = node.DestroyLocalNode(app, clusterName) + } requiredBalance := deployBalance * uint64(numLocalNodes) if availableBalance < requiredBalance { return fmt.Errorf( @@ -720,7 +735,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { bootstrapEndpoints, err = getLocalBootstrapEndpoints() if err != nil { return fmt.Errorf("error getting local host bootstrap endpoints: %w, "+ - "please create your local node again and call subnet deploy command again", err) + "please create your local node again and call blockchain deploy command again", err) } } } @@ -728,7 +743,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { switch { case len(bootstrapEndpoints) > 0: if changeOwnerAddress == "" { - changeOwnerAddress, err = getKeyForChangeOwner(network) + changeOwnerAddress, err = blockchain.GetKeyForChangeOwner(app, network) if err != nil { return err } @@ -845,7 +860,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { return err } } - ux.Logger.PrintToUser("Your subnet auth keys for chain creation: %s", subnetAuthKeys) + ux.Logger.PrintToUser("Your blockchain auth keys for chain creation: %s", subnetAuthKeys) // deploy to public network deployer := subnet.NewPublicDeployer(app, kc, network) @@ -924,7 +939,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { avaGoBootstrapValidators, ) if err != nil { - ux.Logger.RedXToUser("error converting subnet: %s. fix the issue and try again with a new convert cmd", err) + ux.Logger.RedXToUser("error converting blockchain: %s. fix the issue and try again with a new convert cmd", err) return err } @@ -947,7 +962,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { _, err = ux.TimedProgressBar( 30*time.Second, - "Waiting for L1 to be converted into sovereign blockchain ...", + "Waiting for the Subnet to be converted into a sovereign L1 ...", 0, ) if err != nil { @@ -1024,7 +1039,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { return err } evm.WaitForChainID(client) - extraAggregatorPeers, err := GetAggregatorExtraPeers(clusterName, aggregatorExtraEndpoints) + extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterName, aggregatorExtraEndpoints) if err != nil { return err } @@ -1052,9 +1067,16 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { RPC: rpcURL, BootstrapValidators: avaGoBootstrapValidators, } - logLvl, err := logging.ToLevel(aggregatorLogLevel) + aggregatorLogger, err := utils.NewLogger( + constants.SignatureAggregatorLogName, + aggregatorLogLevel, + constants.DefaultAggregatorLogLevel, + app.GetAggregatorLogDir(clusterName), + aggregatorLogToStdout, + ux.Logger.PrintToUser, + ) if err != nil { - logLvl = logging.Off + return err } if sidecar.ValidatorManagement == models.ProofOfStake { ux.Logger.PrintToUser("Initializing Native Token Proof of Stake Validator Manager contract on blockchain %s ...", blockchainName) @@ -1063,7 +1085,7 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { genesisPrivateKey, extraAggregatorPeers, aggregatorAllowPrivatePeers, - logLvl, + aggregatorLogger, validatorManagerSDK.PoSParams{ MinimumStakeAmount: big.NewInt(int64(poSMinimumStakeAmount)), MaximumStakeAmount: big.NewInt(int64(poSMaximumStakeAmount)), @@ -1084,14 +1106,14 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { genesisPrivateKey, extraAggregatorPeers, aggregatorAllowPrivatePeers, - logLvl, + aggregatorLogger, ); err != nil { return err } ux.Logger.GreenCheckmarkToUser("Proof of Authority Validator Manager contract successfully initialized on blockchain %s", blockchainName) } } else { - ux.Logger.GreenCheckmarkToUser("Converted subnet successfully generated") + ux.Logger.GreenCheckmarkToUser("Converted blockchain successfully generated") ux.Logger.PrintToUser("To finish conversion to sovereign L1, create the corresponding Avalanche node(s) with the provided Node ID and BLS Info") ux.Logger.PrintToUser("Created Node ID and BLS Info can be found at %s", app.GetSidecarPath(blockchainName)) 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) @@ -1122,6 +1144,12 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { } } + if sidecar.Sovereign { + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser(logging.Green.Wrap("Your L1 is ready for on-chain interactions.")) + } + + var icmErr, relayerErr error if sidecar.TeleporterReady && tracked && !icmSpec.SkipICMDeploy { chainSpec := contract.ChainSpec{ BlockchainName: blockchainName, @@ -1144,58 +1172,78 @@ func deployBlockchain(cmd *cobra.Command, args []string) error { } ux.Logger.PrintToUser("") if err := messengercmd.CallDeploy([]string{}, deployICMFlags, network); err != nil { - return err - } - if network.Kind != models.Local && !useLocalMachine { - if flag := cmd.Flags().Lookup(skipRelayerFlagName); flag != nil && !flag.Changed { - ux.Logger.PrintToUser("") - yes, err := app.Prompt.CaptureYesNo("Do you want to use set up a local interchain relayer?") - if err != nil { - return err + icmErr = err + ux.Logger.RedXToUser("Interchain Messaging is not deployed due to: %v", icmErr) + } else { + ux.Logger.GreenCheckmarkToUser("ICM is successfully deployed") + if network.Kind != models.Local && !useLocalMachine { + if flag := cmd.Flags().Lookup(skipRelayerFlagName); flag != nil && !flag.Changed { + ux.Logger.PrintToUser("") + yes, err := app.Prompt.CaptureYesNo("Do you want to setup local relayer for the messages to be interchanged, as Interchain Messaging was deployed to your blockchain?") + if err != nil { + return err + } + icmSpec.SkipRelayerDeploy = !yes } - icmSpec.SkipRelayerDeploy = !yes - } - } - if !icmSpec.SkipRelayerDeploy && network.Kind != models.Mainnet { - deployRelayerFlags := relayercmd.DeployFlags{ - Version: icmSpec.RelayerVersion, - BinPath: icmSpec.RelayerBinPath, - LogLevel: icmSpec.RelayerLogLevel, - RelayCChain: relayCChain, - CChainFundingKey: cChainFundingKey, - BlockchainsToRelay: []string{blockchainName}, - Key: relayerKeyName, - Amount: relayerAmount, - AllowPrivateIPs: relayerAllowPrivateIPs, } - if network.Kind == models.Local || useLocalMachine { - deployRelayerFlags.Key = constants.ICMRelayerKeyName - deployRelayerFlags.Amount = constants.DefaultRelayerAmount - deployRelayerFlags.BlockchainFundingKey = constants.ICMKeyName - } - if network.Kind == models.Local { - deployRelayerFlags.CChainFundingKey = "ewoq" - } - if err := relayercmd.CallDeploy(nil, deployRelayerFlags, network); err != nil { - ux.Logger.PrintToUser("Relayer is not deployed due to %v", err) - ux.Logger.PrintToUser("To deploy relayer, call `avalanche interchain relayer deploy`") - } else { - ux.Logger.GreenCheckmarkToUser("Relayer is successfully deployed") + if !icmSpec.SkipRelayerDeploy && network.Kind != models.Mainnet { + deployRelayerFlags := relayercmd.DeployFlags{ + Version: icmSpec.RelayerVersion, + BinPath: icmSpec.RelayerBinPath, + LogLevel: icmSpec.RelayerLogLevel, + RelayCChain: relayCChain, + CChainFundingKey: cChainFundingKey, + BlockchainsToRelay: []string{blockchainName}, + Key: relayerKeyName, + Amount: relayerAmount, + AllowPrivateIPs: relayerAllowPrivateIPs, + } + if network.Kind == models.Local || useLocalMachine { + deployRelayerFlags.Key = constants.ICMRelayerKeyName + deployRelayerFlags.Amount = constants.DefaultRelayerAmount + deployRelayerFlags.BlockchainFundingKey = constants.ICMKeyName + } + if network.Kind == models.Local { + deployRelayerFlags.CChainFundingKey = "ewoq" + deployRelayerFlags.CChainAmount = constants.DefaultRelayerAmount + } + if err := relayercmd.CallDeploy(nil, deployRelayerFlags, network); err != nil { + relayerErr = err + ux.Logger.RedXToUser("Relayer is not deployed due to: %v", relayerErr) + } else { + ux.Logger.GreenCheckmarkToUser("Relayer is successfully deployed") + } } } } - if sidecar.Sovereign { - ux.Logger.GreenCheckmarkToUser("L1 is successfully deployed on %s", network.Name()) - } else { - ux.Logger.GreenCheckmarkToUser("Subnet is successfully deployed %s", network.Name()) - } + flags := make(map[string]string) flags[constants.MetricsNetwork] = network.Name() metrics.HandleTracking(cmd, constants.MetricsSubnetDeployCommand, app, flags) if network.Kind == models.Local && !simulatedPublicNetwork() { ux.Logger.PrintToUser("") - return PrintSubnetInfo(blockchainName, true) + _ = PrintSubnetInfo(blockchainName, true) + } + if icmErr != nil { + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("Interchain Messaging is not deployed due to: %v", icmErr) + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("To deploy ICM later on, call `avalanche icm deploy`") + ux.Logger.PrintToUser("This does not affect L1 operations besides Interchain Messaging") + } + if relayerErr != nil { + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("Relayer is not deployed due to: %v", relayerErr) + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("To deploy a local relayer later on, call `avalanche interchain relayer deploy`") + ux.Logger.PrintToUser("This does not affect L1 operations besides Interchain Messaging") + } + + if sidecar.Sovereign { + ux.Logger.GreenCheckmarkToUser("L1 is successfully deployed on %s", network.Name()) + } else { + ux.Logger.GreenCheckmarkToUser("Subnet is successfully deployed on %s", network.Name()) } return nil @@ -1230,7 +1278,7 @@ func getClusterBootstrapValidators( if err != nil { return nil, fmt.Errorf("failed to parse nodeID: %w", err) } - changeAddr, err = getKeyForChangeOwner(network) + changeAddr, err = blockchain.GetKeyForChangeOwner(app, network) if err != nil { return nil, err } @@ -1250,27 +1298,6 @@ func getClusterBootstrapValidators( return subnetValidators, nil } -func getBLSInfo(publicKey, proofOfPossesion string) (signer.ProofOfPossession, error) { - type jsonProofOfPossession struct { - PublicKey string - ProofOfPossession string - } - jsonPop := jsonProofOfPossession{ - PublicKey: publicKey, - ProofOfPossession: proofOfPossesion, - } - popBytes, err := json.Marshal(jsonPop) - if err != nil { - return signer.ProofOfPossession{}, err - } - pop := &signer.ProofOfPossession{} - err = pop.UnmarshalJSON(popBytes) - if err != nil { - return signer.ProofOfPossession{}, err - } - return *pop, nil -} - // TODO: add deactivation owner? func ConvertToAvalancheGoSubnetValidator(subnetValidators []models.SubnetValidator) ([]*txs.ConvertSubnetToL1Validator, error) { bootstrapValidators := []*txs.ConvertSubnetToL1Validator{} @@ -1279,7 +1306,7 @@ func ConvertToAvalancheGoSubnetValidator(subnetValidators []models.SubnetValidat if err != nil { return nil, err } - blsInfo, err := getBLSInfo(validator.BLSPublicKey, validator.BLSProofOfPossession) + blsInfo, err := blockchain.ConvertToBLSProofOfPossession(validator.BLSPublicKey, validator.BLSProofOfPossession) if err != nil { return nil, fmt.Errorf("failure parsing BLS info: %w", err) } @@ -1307,7 +1334,7 @@ func ValidateSubnetNameAndGetChains(args []string) ([]string, error) { // this should not be necessary but some bright guy might just be creating // the genesis by hand or something... if err := checkInvalidSubnetNames(args[0]); err != nil { - return nil, fmt.Errorf("subnet name %s is invalid: %w", args[0], err) + return nil, fmt.Errorf("blockchain name %s is invalid: %w", args[0], err) } // Check subnet exists // TODO create a file that lists chains by subnet for fast querying @@ -1317,7 +1344,7 @@ func ValidateSubnetNameAndGetChains(args []string) ([]string, error) { } if len(chains) == 0 { - return nil, errors.New("Invalid subnet " + args[0]) + return nil, errors.New("Invalid blockchain " + args[0]) } return chains, nil @@ -1326,7 +1353,7 @@ func ValidateSubnetNameAndGetChains(args []string) ([]string, error) { func SaveNotFullySignedTx( txName string, tx *txs.Tx, - chain string, + blockchainName string, subnetAuthKeys []string, remainingSubnetAuthKeys []string, outputTxPath string, @@ -1361,26 +1388,30 @@ func SaveNotFullySignedTx( return err } if signedCount == len(subnetAuthKeys) { - PrintReadyToSignMsg(chain, outputTxPath) + PrintReadyToSignMsg(blockchainName, outputTxPath) } else { - PrintRemainingToSignMsg(chain, remainingSubnetAuthKeys, outputTxPath) + PrintRemainingToSignMsg(blockchainName, remainingSubnetAuthKeys, outputTxPath) } return nil } func PrintReadyToSignMsg( - chain string, + blockchainName string, outputTxPath string, ) { ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Tx is fully signed, and ready to be committed") ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Commit command:") - ux.Logger.PrintToUser(" avalanche transaction commit %s --input-tx-filepath %s", chain, outputTxPath) + cmdLine := fmt.Sprintf(" avalanche transaction commit %s --input-tx-filepath %s", blockchainName, outputTxPath) + if blockchainName == "" { + cmdLine = fmt.Sprintf(" avalanche transaction commit --input-tx-filepath %s", outputTxPath) + } + ux.Logger.PrintToUser(cmdLine) } func PrintRemainingToSignMsg( - chain string, + blockchainName string, remainingSubnetAuthKeys []string, outputTxPath string, ) { @@ -1394,28 +1425,35 @@ func PrintRemainingToSignMsg( "and run the signing command, or send %q to another user for signing.", outputTxPath) ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Signing command:") - ux.Logger.PrintToUser(" avalanche transaction sign %s --input-tx-filepath %s", chain, outputTxPath) + cmdline := fmt.Sprintf(" avalanche transaction sign %s --input-tx-filepath %s", blockchainName, outputTxPath) + if blockchainName == "" { + cmdline = fmt.Sprintf(" avalanche transaction sign --input-tx-filepath %s", outputTxPath) + } + ux.Logger.PrintToUser(cmdline) ux.Logger.PrintToUser("") } -func PrintDeployResults(chain string, subnetID ids.ID, blockchainID ids.ID) error { - vmID, err := anrutils.VMID(chain) - if err != nil { - return fmt.Errorf("failed to create VM ID from %s: %w", chain, err) - } - header := []string{"Deployment results", ""} - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader(header) - table.SetRowLine(true) - table.SetAutoMergeCells(true) - table.Append([]string{"Chain Name", chain}) - table.Append([]string{"Subnet ID", subnetID.String()}) - table.Append([]string{"VM ID", vmID.String()}) +func PrintDeployResults(blockchainName string, subnetID ids.ID, blockchainID ids.ID) error { + t := ux.DefaultTable("Deployment results", nil) + t.SetColumnConfigs([]table.ColumnConfig{ + {Number: 2, AutoMerge: true}, + }) + if blockchainName != "" { + t.AppendRow(table.Row{"Chain Name", blockchainName}) + } + t.AppendRow(table.Row{"Subnet ID", subnetID.String()}) + if blockchainName != "" { + vmID, err := anrutils.VMID(blockchainName) + if err != nil { + return fmt.Errorf("failed to create VM ID from %s: %w", blockchainName, err) + } + t.AppendRow(table.Row{"VM ID", vmID.String()}) + } if blockchainID != ids.Empty { - table.Append([]string{"Blockchain ID", blockchainID.String()}) - table.Append([]string{"P-Chain TXID", blockchainID.String()}) + t.AppendRow(table.Row{"Blockchain ID", blockchainID.String()}) + t.AppendRow(table.Row{"P-Chain TXID", blockchainID.String()}) } - table.Render() + ux.Logger.PrintToUser(t.Render()) return nil } @@ -1445,32 +1483,8 @@ func LoadBootstrapValidator(filepath string) ([]models.SubnetValidator, error) { return subnetValidators, nil } -func UrisToPeers(uris []string) ([]info.Peer, error) { - peers := []info.Peer{} - ctx, cancel := utils.GetANRContext() - defer cancel() - for _, uri := range uris { - client := info.NewClient(uri) - nodeID, _, err := client.GetNodeID(ctx) - if err != nil { - return nil, err - } - ip, err := client.GetNodeIP(ctx) - if err != nil { - return nil, err - } - peers = append(peers, info.Peer{ - Info: peer.Info{ - ID: nodeID, - PublicIP: ip, - }, - }) - } - return peers, nil -} - func ConvertURIToPeers(uris []string) ([]info.Peer, error) { - aggregatorPeers, err := UrisToPeers(uris) + aggregatorPeers, err := blockchain.UrisToPeers(uris) if err != nil { return nil, err } @@ -1496,60 +1510,6 @@ func ConvertURIToPeers(uris []string) ([]info.Peer, error) { return aggregatorPeers, nil } -func GetAggregatorExtraPeers( - clusterName string, - extraURIs []string, -) ([]info.Peer, error) { - uris, err := GetAggregatorNetworkUris(clusterName) - if err != nil { - return nil, err - } - uris = append(uris, extraURIs...) - urisSet := set.Of(uris...) - uris = urisSet.List() - return UrisToPeers(uris) -} - -func GetAggregatorNetworkUris(clusterName string) ([]string, error) { - aggregatorExtraPeerEndpointsUris := []string{} - if clusterName != "" { - clustersConfig, err := app.LoadClustersConfig() - if err != nil { - return nil, err - } - clusterConfig := clustersConfig.Clusters[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 { - aggregatorExtraPeerEndpointsUris = append(aggregatorExtraPeerEndpointsUris, nodeInfo.Uri) - } - } else { // remote cluster case - hostIDs := utils.Filter(clusterConfig.GetCloudIDs(), clusterConfig.IsAvalancheGoHost) - for _, hostID := range hostIDs { - if nodeConfig, err := app.LoadClusterNodeConfig(hostID); err != nil { - return nil, err - } else { - aggregatorExtraPeerEndpointsUris = append(aggregatorExtraPeerEndpointsUris, fmt.Sprintf("http://%s:%d", nodeConfig.ElasticIP, constants.AvalancheGoAPIPort)) - } - } - } - } - return aggregatorExtraPeerEndpointsUris, nil -} - func simulatedPublicNetwork() bool { return os.Getenv(constants.SimulatePublicNetwork) != "" } diff --git a/cmd/blockchaincmd/describe.go b/cmd/blockchaincmd/describe.go index 9d9dba4f4..37f535479 100644 --- a/cmd/blockchaincmd/describe.go +++ b/cmd/blockchaincmd/describe.go @@ -86,15 +86,11 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { } // VM/Deploys - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true + t := ux.DefaultTable(sc.Name, nil) t.SetColumnConfigs([]table.ColumnConfig{ {Number: 1, AutoMerge: true}, }) rowConfig := table.RowConfig{AutoMerge: true, AutoMergeAlign: text.AlignLeft} - t.SetTitle(sc.Name) t.AppendRow(table.Row{"Name", sc.Name, sc.Name}, rowConfig) vmIDstr := sc.ImportedVMID if vmIDstr == "" { @@ -109,7 +105,7 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { t.AppendRow(table.Row{"VM Version", sc.VMVersion, sc.VMVersion}, rowConfig) t.AppendRow(table.Row{"Validation", sc.ValidatorManagement, sc.ValidatorManagement}, rowConfig) - locallyDeployed := true + locallyDeployed := false localEndpoint := "" localChainID := "" for net, data := range sc.Networks { @@ -130,12 +126,16 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { }, ) if err != nil { - if network.Kind == models.Local { - locallyDeployed = false - continue - } else { + if network.Kind != models.Local { return err } + // ignore local network errors for cases + // where local network is down but sidecar contains + // local network metadata + // (eg host restarts) + continue + } else if network.Kind == models.Local { + locallyDeployed = true } if utils.ByteSliceIsSubnetEvmGenesis(genesisBytes) { genesis, err := utils.ByteSliceToSubnetEvmGenesis(genesisBytes) @@ -182,14 +182,10 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { ux.Logger.PrintToUser(t.Render()) // ICM - t = table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true + t = ux.DefaultTable("ICM", nil) t.SetColumnConfigs([]table.ColumnConfig{ {Number: 1, AutoMerge: true}, }) - t.SetTitle("ICM") hasICMInfo := false for net, data := range sc.Networks { network, err := app.GetNetworkFromSidecarNetworkName(net) @@ -218,11 +214,7 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { // Token ux.Logger.PrintToUser("") - t = table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true - t.SetTitle("Token") + t = ux.DefaultTable("Token", nil) t.AppendRow(table.Row{"Token Name", sc.TokenName}) t.AppendRow(table.Row{"Token Symbol", sc.TokenSymbol}) ux.Logger.PrintToUser(t.Render()) @@ -260,11 +252,7 @@ func PrintSubnetInfo(blockchainName string, onlyLocalnetInfo bool) error { } // Wallet - t = table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true - t.SetTitle("Wallet Connection") + t = ux.DefaultTable("Wallet Connection", nil) t.AppendRow(table.Row{"Network RPC URL", localEndpoint}) t.AppendRow(table.Row{"Network Name", sc.Name}) t.AppendRow(table.Row{"Chain ID", localChainID}) @@ -292,17 +280,15 @@ func printAllocations(sc models.Sidecar, genesis core.Genesis) error { } if len(genesis.Alloc) > 0 { ux.Logger.PrintToUser("") - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true - t.SetTitle("Initial Token Allocation") - t.AppendHeader(table.Row{ - "Description", - "Address and Private Key", - fmt.Sprintf("Amount (%s)", sc.TokenSymbol), - "Amount (wei)", - }) + t := ux.DefaultTable( + "Initial Token Allocation", + table.Row{ + "Description", + "Address and Private Key", + fmt.Sprintf("Amount (%s)", sc.TokenSymbol), + "Amount (wei)", + }, + ) for address, allocation := range genesis.Alloc { amount := allocation.Balance // we are only interested in supply distribution here @@ -347,12 +333,10 @@ func printSmartContracts(sc models.Sidecar, genesis core.Genesis) { return } ux.Logger.PrintToUser("") - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true - t.SetTitle("Smart Contracts") - t.AppendHeader(table.Row{"Description", "Address", "Deployer"}) + t := ux.DefaultTable( + "Smart Contracts", + table.Row{"Description", "Address", "Deployer"}, + ) for address, allocation := range genesis.Alloc { if len(allocation.Code) == 0 { continue @@ -383,14 +367,14 @@ func printSmartContracts(sc models.Sidecar, genesis core.Genesis) { func printPrecompiles(genesis core.Genesis) { ux.Logger.PrintToUser("") - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper + t := ux.DefaultTable( + "Initial Precompile Configs", + table.Row{"Precompile", "Admin Addresses", "Manager Addresses", "Enabled Addresses"}, + ) + t.Style().Options.SeparateRows = false t.SetColumnConfigs([]table.ColumnConfig{ {Number: 1, AutoMerge: true}, }) - t.SetTitle("Initial Precompile Configs") - t.AppendHeader(table.Row{"Precompile", "Admin Addresses", "Manager Addresses", "Enabled Addresses"}) warpSet := false allowListSet := false @@ -468,7 +452,7 @@ func addPrecompileAllowListToTable( func describe(_ *cobra.Command, args []string) error { blockchainName := args[0] if !app.GenesisExists(blockchainName) { - ux.Logger.PrintToUser("The provided subnet name %q does not exist", blockchainName) + ux.Logger.PrintToUser("The provided blockchain name %q does not exist", blockchainName) return nil } if printGenesisOnly { diff --git a/cmd/blockchaincmd/export.go b/cmd/blockchaincmd/export.go index aa5d789f4..24cdba9f7 100644 --- a/cmd/blockchaincmd/export.go +++ b/cmd/blockchaincmd/export.go @@ -66,7 +66,7 @@ func exportSubnet(_ *cobra.Command, args []string) error { blockchainName := args[0] if !app.SidecarExists(blockchainName) { - return fmt.Errorf("invalid subnet %q", blockchainName) + return fmt.Errorf("invalid blockchain %q", blockchainName) } sc, err := app.LoadSidecar(blockchainName) diff --git a/cmd/blockchaincmd/export_test.go b/cmd/blockchaincmd/export_test.go index 474f928ec..7d9637b42 100644 --- a/cmd/blockchaincmd/export_test.go +++ b/cmd/blockchaincmd/export_test.go @@ -89,7 +89,7 @@ func TestExportImportSubnet(t *testing.T) { err = importBlockchain(nil, []string{"this-does-also-not-exist-import-should-fail"}) require.ErrorIs(err, os.ErrNotExist) err = importBlockchain(nil, []string{exportOutput}) - require.ErrorContains(err, "subnet already exists") + require.ErrorContains(err, "blockchain already exists") genFile := filepath.Join(app.GetBaseDir(), constants.SubnetDir, testSubnet, constants.GenesisFileName) err = os.Remove(genFile) require.NoError(err) diff --git a/cmd/blockchaincmd/helpers.go b/cmd/blockchaincmd/helpers.go index 7d218d7ca..44f54834c 100644 --- a/cmd/blockchaincmd/helpers.go +++ b/cmd/blockchaincmd/helpers.go @@ -4,7 +4,6 @@ package blockchaincmd import ( "fmt" - "time" "github.com/ava-labs/avalanche-cli/pkg/binutils" "github.com/ava-labs/avalanche-cli/pkg/utils" @@ -13,7 +12,6 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/txutils" - "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanchego/ids" "github.com/spf13/cobra" ) @@ -36,7 +34,7 @@ func CreateBlockchainFirst(cmd *cobra.Command, blockchainName string, skipPrompt return nil } -func DeployBlockchainFirst(cmd *cobra.Command, blockchainName string, skipPrompt bool, supportedNetworkOptions []networkoptions.NetworkOption) error { +func DeployBlockchainFirst(cmd *cobra.Command, blockchainName string, skipPrompt bool) error { var ( doDeploy bool msg string @@ -47,7 +45,7 @@ func DeployBlockchainFirst(cmd *cobra.Command, blockchainName string, skipPrompt msg = fmt.Sprintf("Blockchain %s is not created yet. Do you want to create it first?", blockchainName) errIfNoChoosen = fmt.Errorf("blockchain not available and not being created first") } else { - filteredSupportedNetworkOptions, _, _, err := networkoptions.GetSupportedNetworkOptionsForSubnet(app, blockchainName, supportedNetworkOptions) + filteredSupportedNetworkOptions, _, _, err := networkoptions.GetSupportedNetworkOptionsForSubnet(app, blockchainName, networkoptions.DefaultSupportedNetworkOptions) if err != nil { return err } @@ -67,7 +65,7 @@ func DeployBlockchainFirst(cmd *cobra.Command, blockchainName string, skipPrompt return errIfNoChoosen } } - return runDeploy(cmd, []string{blockchainName}, supportedNetworkOptions) + return runDeploy(cmd, []string{blockchainName}) } return nil } @@ -96,21 +94,6 @@ func UpdateKeychainWithSubnetControlKeys( return nil } -func UpdatePChainHeight( - title string, -) error { - _, err := ux.TimedProgressBar( - 40*time.Second, - title, - 0, - ) - if err != nil { - return err - } - fmt.Println() - return nil -} - func getLocalBootstrapEndpoints() ([]string, error) { ctx, cancel := utils.GetANRContext() defer cancel() diff --git a/cmd/blockchaincmd/import_file.go b/cmd/blockchaincmd/import_file.go index 1afc3fefa..b2816705a 100644 --- a/cmd/blockchaincmd/import_file.go +++ b/cmd/blockchaincmd/import_file.go @@ -63,9 +63,9 @@ flag.`, ) cmd.Flags().StringVar( &subnetAlias, - "subnet", + "blockchain", "", - "the subnet configuration to import from the provided repo", + "the blockchain configuration to import from the provided repo", ) return cmd } @@ -80,7 +80,7 @@ func importBlockchain(_ *cobra.Command, args []string) error { fileOption := "File" apmOption := "Repository" typeOptions := []string{fileOption, apmOption} - promptStr := "Would you like to import your subnet from a file or a repository?" + promptStr := "Would you like to import your blockchain from a file or a repository?" result, err := app.Prompt.CaptureList(promptStr, typeOptions) if err != nil { return err @@ -98,7 +98,7 @@ func importBlockchain(_ *cobra.Command, args []string) error { func importFromFile(importPath string) error { var err error if importPath == "" { - promptStr := "Select the file to import your subnet from" + promptStr := "Select the file to import your blockchain from" importPath, err = app.Prompt.CaptureExistingFilepath(promptStr) if err != nil { return err @@ -118,11 +118,11 @@ func importFromFile(importPath string) error { blockchainName := importable.Sidecar.Name if blockchainName == "" { - return errors.New("export data is malformed: missing subnet name") + return errors.New("export data is malformed: missing blockchain name") } if app.GenesisExists(blockchainName) && !overwriteImport { - return errors.New("subnet already exists. Use --" + forceFlag + " parameter to overwrite") + return errors.New("blockchain already exists. Use --" + forceFlag + " parameter to overwrite") } if importable.Sidecar.VM == models.CustomVM { @@ -190,7 +190,7 @@ func importFromFile(importPath string) error { return err } - ux.Logger.PrintToUser("Subnet imported successfully") + ux.Logger.PrintToUser("Blockchain imported successfully") return nil } @@ -287,10 +287,10 @@ func importFromAPM() error { } } if subnet == "" { - return fmt.Errorf("unable to find subnet %s", subnetAlias) + return fmt.Errorf("unable to find blockchain %s", subnetAlias) } } else { - promptStr = "Select a subnet to import" + promptStr = "Select a blockchain to import" subnet, err = app.Prompt.CaptureList(promptStr, subnets) if err != nil { return err @@ -308,9 +308,9 @@ func importFromAPM() error { var vmType models.VMType = models.CustomVM if len(subnetDescr.VMs) == 0 { - return errors.New("no vms found in the given subnet") + return errors.New("no vms found in the given blockchain") } else if len(subnetDescr.VMs) == 0 { - return errors.New("multiple vm subnets not supported") + return errors.New("multiple vm blockchains are not supported") } vmDescr, err := apmintegration.LoadVMFile(app, repoAlias, subnetDescr.VMs[0]) @@ -333,7 +333,7 @@ func importFromAPM() error { ImportedVMID: vmDescr.ID, } - ux.Logger.PrintToUser("Selected subnet, installing " + subnetKey) + ux.Logger.PrintToUser("Selected blockchain, installing " + subnetKey) if err = apmintegration.InstallVM(app, subnetKey); err != nil { return err diff --git a/cmd/blockchaincmd/import_public.go b/cmd/blockchaincmd/import_public.go index 8e75d240d..d1386bb6f 100644 --- a/cmd/blockchaincmd/import_public.go +++ b/cmd/blockchaincmd/import_public.go @@ -22,12 +22,6 @@ import ( ) var ( - importPublicSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Fuji, - networkoptions.Mainnet, - networkoptions.Devnet, - networkoptions.Local, - } blockchainIDstr string nodeURL string useSubnetEvm bool @@ -48,9 +42,9 @@ doesn't overwrite an existing Blockchain with the same name. To allow overwrites flag.`, } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, importPublicSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) - cmd.Flags().StringVar(&nodeURL, "node-url", "", "[optional] URL of an already running subnet validator") + cmd.Flags().StringVar(&nodeURL, "node-url", "", "[optional] URL of an already running validator") cmd.Flags().BoolVar(&useSubnetEvm, "evm", false, "import a subnet-evm") cmd.Flags().BoolVar(&useCustomVM, "custom", false, "use a custom VM template") @@ -76,7 +70,7 @@ func importPublic(*cobra.Command, []string) error { globalNetworkFlags, true, false, - importPublicSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -86,7 +80,7 @@ func importPublic(*cobra.Command, []string) error { var reply *info.GetNodeVersionReply if nodeURL == "" { - yes, err := app.Prompt.CaptureNoYes("Have validator nodes already been deployed to this subnet?") + yes, err := app.Prompt.CaptureNoYes("Have validator nodes already been deployed to this blockchain?") if err != nil { return err } @@ -213,7 +207,7 @@ func importPublic(*cobra.Command, []string) error { return err } - ux.Logger.PrintToUser("Subnet %q imported successfully", sc.Name) + ux.Logger.PrintToUser("Blockchain %q imported successfully", sc.Name) return nil } diff --git a/cmd/blockchaincmd/join.go b/cmd/blockchaincmd/join.go index 37ccb93f8..a80d2cc05 100644 --- a/cmd/blockchaincmd/join.go +++ b/cmd/blockchaincmd/join.go @@ -23,12 +23,6 @@ import ( ) var ( - joinSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, - } // path to avalanchego config file avagoConfigPath string // path to avalanchego plugin dir @@ -39,7 +33,7 @@ var ( printManual bool // if true, doesn't ask for overwriting the config file forceWrite bool - // for permissionless subnet only: how much subnet native token will be staked in the validator + // for permissionless subnet only: how much native token will be staked in the validator stakeAmount uint64 ) @@ -48,13 +42,13 @@ func newJoinCmd() *cobra.Command { cmd := &cobra.Command{ Use: "join [blockchainName]", Short: "Configure your validator node to begin validating a new blockchain", - Long: `The subnet join command configures your validator node to begin validating a new Blockchain. + Long: `The blockchain join command configures your validator node to begin validating a new Blockchain. To complete this process, you must have access to the machine running your validator. If the CLI is running on the same machine as your validator, it can generate or update your node's config file automatically. Alternatively, the command can print the necessary instructions -to update your node manually. To complete the validation process, the Subnet's admins must add -the NodeID of your validator to the Subnet's allow list by calling addValidator with your +to update your node manually. To complete the validation process, the Blockchain's admins must add +the NodeID of your validator to the Blockchain's allow list by calling addValidator with your NodeID. After you update your validator's config, you need to restart your validator manually. If @@ -65,7 +59,7 @@ This command currently only supports Blockchains deployed on the Fuji Testnet an RunE: joinCmd, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, joinSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVar(&avagoConfigPath, "avalanchego-config", "", "file path of the avalanchego config file") cmd.Flags().StringVar(&pluginDir, "plugin-dir", "", "file path of avalanchego's plugin directory") cmd.Flags().StringVar(&dataDir, "data-dir", "", "path of avalanchego's data dir directory") @@ -108,7 +102,7 @@ func joinCmd(_ *cobra.Command, args []string) error { globalNetworkFlags, true, false, - joinSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/blockchaincmd/prompt_genesis_input.go b/cmd/blockchaincmd/prompt_genesis_input.go index 5605a3329..d80cfd5e3 100644 --- a/cmd/blockchaincmd/prompt_genesis_input.go +++ b/cmd/blockchaincmd/prompt_genesis_input.go @@ -5,6 +5,8 @@ package blockchaincmd import ( "fmt" + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + "github.com/ava-labs/avalanche-cli/pkg/application" "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/models" @@ -162,7 +164,7 @@ func promptBootstrapValidators( generateNodeID = !setUpNodes } if changeOwnerAddress == "" { - changeOwnerAddress, err = getKeyForChangeOwner(network) + changeOwnerAddress, err = blockchain.GetKeyForChangeOwner(app, network) if err != nil { return nil, err } diff --git a/cmd/blockchaincmd/prompt_owners.go b/cmd/blockchaincmd/prompt_owners.go index 1c7f59a4e..2de9d9cd6 100644 --- a/cmd/blockchaincmd/prompt_owners.go +++ b/cmd/blockchaincmd/prompt_owners.go @@ -71,9 +71,9 @@ func promptOwners( } func getControlKeys(kc *keychain.Keychain, creatingBlockchain bool) ([]string, bool, error) { - controlKeysInitialPrompt := "Configure which addresses may make changes to the subnet.\n" + + controlKeysInitialPrompt := "Configure which addresses may make changes to the blockchain.\n" + "These addresses are known as your control keys. You will also\n" + - "set how many control keys are required to make a subnet change (the threshold)." + "set how many control keys are required to make a blockchain change (the threshold)." ux.Logger.PrintToUser(controlKeysInitialPrompt) if creatingBlockchain { @@ -140,7 +140,7 @@ func getControlKeysForDeploy(kc *keychain.Keychain) ([]string, bool, error) { } func getControlKeysForChangeOwner(network models.Network) ([]string, bool, error) { - moreKeysPrompt := "Which control keys would you like to set as the new subnet owners?" + moreKeysPrompt := "Which control keys would you like to set as the new blockchain owners?" const ( getFromStored = "Get address from an existing stored key (created from avalanche key create or avalanche key import)" @@ -163,7 +163,7 @@ func getControlKeysForChangeOwner(network models.Network) ([]string, bool, error case getFromStored: key, err := prompts.CaptureKeyAddress( app.Prompt, - "be set as a subnet control key", + "be set as a control key", app.GetKeyDir(), app.GetKey, network, @@ -246,7 +246,7 @@ func controlKeysLoop(controlKeysPrompt string, network models.Network) ([]string func(_ string) (string, error) { return prompts.PromptAddress( app.Prompt, - "be set as a subnet control key", + "be set as a control key", app.GetKeyDir(), app.GetKey, "", @@ -275,7 +275,7 @@ func getThreshold(maxLen int) (uint32, error) { for i := 0; i < maxLen; i++ { indexList[i] = strconv.Itoa(i + 1) } - threshold, err := app.Prompt.CaptureList("Select required number of control key signatures to make a subnet change", indexList) + threshold, err := app.Prompt.CaptureList("Select required number of control key signatures to make a blockchain change", indexList) if err != nil { return 0, err } @@ -289,46 +289,3 @@ func getThreshold(maxLen int) (uint32, error) { } return uint32(intTh), err } - -func getKeyForChangeOwner(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?" - - const ( - getFromStored = "Get address from an existing stored key (created from avalanche key create or avalanche key import)" - custom = "Custom" - ) - - listOptions := []string{getFromStored, custom} - listDecision, err := app.Prompt.CaptureList(changeAddrPrompt, listOptions) - if err != nil { - return "", err - } - - var key string - - switch listDecision { - case getFromStored: - key, err = prompts.CaptureKeyAddress( - app.Prompt, - "be set as a change owner for leftover AVAX", - app.GetKeyDir(), - app.GetKey, - network, - prompts.PChainFormat, - ) - if err != nil { - return "", err - } - case custom: - addrPrompt := "Enter change address (P-chain format)" - changeAddr, err := app.Prompt.CaptureAddress(addrPrompt) - if err != nil { - return "", err - } - key = changeAddr.String() - } - if err != nil { - return "", err - } - return key, nil -} diff --git a/cmd/blockchaincmd/publish.go b/cmd/blockchaincmd/publish.go index 649fc7534..559e5e8d4 100644 --- a/cmd/blockchaincmd/publish.go +++ b/cmd/blockchaincmd/publish.go @@ -35,7 +35,7 @@ var ( noRepoPath string errSubnetNotDeployed = errors.New( - "only subnets which have already been deployed to either testnet (fuji) or mainnet can be published") + "only blockchains which have already been deployed to either testnet (fuji) or mainnet can be published") ) type newPublisherFunc func(string, string, string) subnet.Publisher @@ -55,11 +55,11 @@ func newPublishCmd() *cobra.Command { cmd.Flags().StringVar(&vmDescPath, "vm-file-path", "", "Path to the VM description file. If not given, a prompting sequence will be initiated.") cmd.Flags().StringVar(&subnetDescPath, "subnet-file-path", "", - "Path to the Subnet description file. If not given, a prompting sequence will be initiated.") + "Path to the Blockchain description file. If not given, a prompting sequence will be initiated.") cmd.Flags().StringVar(&noRepoPath, "no-repo-path", "", "Do not let the tool manage file publishing, but have it only generate the files and put them in the location given by this flag.") cmd.Flags().BoolVar(&forceWrite, forceFlag, false, - "If true, ignores if the subnet has been published in the past, and attempts a forced publish.") + "If true, ignores if the blockchain has been published in the past, and attempts a forced publish.") return cmd } @@ -117,7 +117,7 @@ func doPublish(sc *models.Sidecar, blockchainName string, publisherCreateFunc ne } if published { ux.Logger.PrintToUser( - "It appears this subnet has already been published, while no force flag has been detected.") + "It appears this blockchain has already been published, while no force flag has been detected.") return errors.New("aborted") } } @@ -132,7 +132,7 @@ func doPublish(sc *models.Sidecar, blockchainName string, publisherCreateFunc ne return err } - ux.Logger.PrintToUser("Nice! We got the subnet info. Let's now get the VM details") + ux.Logger.PrintToUser("Nice! We got the blockchain info. Let's now get the VM details") if vmDescPath == "" { vm, err = getVMInfo(sc) @@ -182,10 +182,10 @@ func doPublish(sc *models.Sidecar, blockchainName string, publisherCreateFunc ne } } if err := os.WriteFile(subnetFile, subnetYAML, constants.DefaultPerms755); err != nil { - return fmt.Errorf("failed creating the subnet description YAML file: %w", err) + return fmt.Errorf("failed creating the blockchain description YAML file: %w", err) } if err := os.WriteFile(vmFile, vmYAML, constants.DefaultPerms755); err != nil { - return fmt.Errorf("failed creating the subnet description YAML file: %w", err) + return fmt.Errorf("failed creating the blockchain description YAML file: %w", err) } ux.Logger.PrintToUser("YAML files written successfully to %s", noRepoPath) return nil @@ -263,7 +263,7 @@ func getAlias(reposDir string) error { // double-check: actually this path exists... if _, err := os.Stat(filepath.Join(reposDir, alias)); err == nil { ux.Logger.PrintToUser( - "The repository with the given alias already exists locally. You may have already published this subnet there (the other explanation is that a different subnet has been published there).") + "The repository with the given alias already exists locally. You may have already published this blockchain there (the other explanation is that a different blockchain has been published there).") yes, err := app.Prompt.CaptureYesNo("Do you wish to continue?") if err != nil { return err @@ -338,19 +338,19 @@ func loadYAMLFile[T types.Definition](path string, defType T) error { } func getSubnetInfo(sc *models.Sidecar) (*types.Subnet, error) { - homepage, err := app.Prompt.CaptureStringAllowEmpty("What is the homepage of the Subnet project?") + homepage, err := app.Prompt.CaptureStringAllowEmpty("What is the homepage of the Blockchain project?") if err != nil { return nil, err } - desc, err := app.Prompt.CaptureStringAllowEmpty("Provide a free-text description of the Subnet") + desc, err := app.Prompt.CaptureStringAllowEmpty("Provide a free-text description of the Blockchain") if err != nil { return nil, err } maintrs, canceled, err := prompts.CaptureListDecision( app.Prompt, - "Who are the maintainers of the Subnet?", + "Who are the maintainers of the Blockchain?", app.Prompt.CaptureEmail, "Provide a maintainer", "Maintainer", diff --git a/cmd/blockchaincmd/remove_validator.go b/cmd/blockchaincmd/remove_validator.go index f43903b0a..9a74212d9 100644 --- a/cmd/blockchaincmd/remove_validator.go +++ b/cmd/blockchaincmd/remove_validator.go @@ -6,12 +6,16 @@ import ( "errors" "fmt" "os" + "strings" + + "github.com/ava-labs/avalanche-cli/pkg/blockchain" "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/utils/logging" "github.com/ethereum/go-ethereum/common" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/contract" "github.com/ava-labs/avalanche-cli/pkg/keychain" "github.com/ava-labs/avalanche-cli/pkg/models" @@ -30,13 +34,6 @@ import ( "github.com/spf13/cobra" ) -var removeValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - var ( uptimeSec uint64 force bool @@ -46,8 +43,8 @@ var ( func newRemoveValidatorCmd() *cobra.Command { cmd := &cobra.Command{ Use: "removeValidator [blockchainName]", - Short: "Remove a permissioned validator from your blockchain's subnet", - Long: `The blockchain removeValidator command stops a whitelisted, subnet network validator from + Short: "Remove a permissioned validator from your blockchain", + Long: `The blockchain removeValidator command stops a whitelisted blockchain network validator from validating your deployed Blockchain. To remove the validator from the Subnet's allow list, provide the validator's unique NodeID. You can bypass @@ -55,9 +52,9 @@ these prompts by providing the values with flags.`, RunE: removeValidator, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, removeValidatorSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji deploy only]") - cmd.Flags().StringSliceVar(&subnetAuthKeys, "subnet-auth-keys", nil, "(for non-SOV blockchain only) control keys that will be used to authenticate the removeValidator tx") + cmd.Flags().StringSliceVar(&subnetAuthKeys, "auth-keys", nil, "(for non-SOV blockchain only) control keys that will be used to authenticate the removeValidator tx") cmd.Flags().StringVar(&outputTxPath, "output-tx-path", "", "(for non-SOV blockchain only) file path of the removeValidator tx") cmd.Flags().BoolVarP(&useLedger, "ledger", "g", false, "use ledger instead of key (always true on mainnet, defaults to false on fuji)") cmd.Flags().StringSliceVar(&ledgerAddresses, "ledger-addrs", []string{}, "use the given ledger addresses") @@ -67,7 +64,8 @@ these prompts by providing the values with flags.`, cmd.Flags().BoolVar(&aggregatorAllowPrivatePeers, "aggregator-allow-private-peers", true, "allow the signature aggregator to connect to peers with private IP") privateKeyFlags.AddToCmd(cmd, "to pay fees for completing the validator's removal (blockchain gas token)") cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint") - cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") + cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator") + cmd.Flags().BoolVar(&aggregatorLogToStdout, "aggregator-log-to-stdout", false, "use stdout for signature aggregator logs") cmd.Flags().Uint64Var(&uptimeSec, "uptime", 0, "validator's uptime in seconds. If not provided, it will be automatically calculated") cmd.Flags().BoolVar(&force, "force", false, "force validator removal even if it's not getting rewarded") return cmd @@ -85,14 +83,13 @@ func removeValidator(_ *cobra.Command, args []string) error { return err } - networkOptionsList := networkoptions.GetNetworkFromSidecar(sc, removeValidatorSupportedNetworkOptions) network, err := networkoptions.GetNetworkFromCmdLineFlags( app, "", globalNetworkFlags, true, false, - networkOptionsList, + networkoptions.GetNetworkFromSidecar(sc, networkoptions.DefaultSupportedNetworkOptions), "", ) if err != nil { @@ -262,7 +259,18 @@ func removeValidatorSOV( } ux.Logger.PrintToUser(logging.Yellow.Wrap("RPC Endpoint: %s"), rpcURL) clusterName := sc.Networks[network.Name()].ClusterName - extraAggregatorPeers, err := GetAggregatorExtraPeers(clusterName, aggregatorExtraEndpoints) + extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterName, aggregatorExtraEndpoints) + if err != nil { + return err + } + aggregatorLogger, err := utils.NewLogger( + constants.SignatureAggregatorLogName, + aggregatorLogLevel, + constants.DefaultAggregatorLogLevel, + app.GetAggregatorLogDir(clusterNameFlagValue), + aggregatorLogToStdout, + ux.Logger.PrintToUser, + ) if err != nil { return err } @@ -284,7 +292,7 @@ func removeValidatorSOV( nodeID, extraAggregatorPeers, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, sc.PoS(), uptimeSec, isBootstrapValidator || force, @@ -307,7 +315,7 @@ func removeValidatorSOV( nodeID, extraAggregatorPeers, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, sc.PoS(), uptimeSec, true, // force @@ -322,14 +330,17 @@ func removeValidatorSOV( ux.Logger.PrintToUser("ValidationID: %s", validationID) txID, _, err := deployer.SetL1ValidatorWeight(signedMessage) if err != nil { - return err - } - ux.Logger.PrintToUser("SetL1ValidatorWeightTx ID: %s", txID) - - if err := UpdatePChainHeight( - "Waiting for P-Chain to update validator information ...", - ); err != nil { - return err + if !strings.Contains(err.Error(), "could not load L1 validator: not found") { + return err + } + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The Validation ID was already removed on the P-Chain. Proceeding to the next step")) + } else { + ux.Logger.PrintToUser("SetL1ValidatorWeightTx ID: %s", txID) + if err := blockchain.UpdatePChainHeight( + "Waiting for P-Chain to update validator information ...", + ); err != nil { + return err + } } if err := validatormanager.FinishValidatorRemoval( @@ -341,7 +352,7 @@ func removeValidatorSOV( validationID, extraAggregatorPeers, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, ); err != nil { return err } @@ -377,7 +388,7 @@ func removeValidatorNonSOV(deployer *subnet.PublicDeployer, network models.Netwo return err } } - ux.Logger.PrintToUser("Your subnet auth keys for remove validator tx creation: %s", subnetAuthKeys) + ux.Logger.PrintToUser("Your auth keys for remove validator tx creation: %s", subnetAuthKeys) ux.Logger.PrintToUser("NodeID: %s", nodeID.String()) ux.Logger.PrintToUser("Network: %s", network.Name()) diff --git a/cmd/blockchaincmd/stats.go b/cmd/blockchaincmd/stats.go index 61012744d..f24bba7a5 100644 --- a/cmd/blockchaincmd/stats.go +++ b/cmd/blockchaincmd/stats.go @@ -22,13 +22,6 @@ import ( "github.com/spf13/cobra" ) -var statsSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - // avalanche blockchain stats func newStatsCmd() *cobra.Command { cmd := &cobra.Command{ @@ -38,7 +31,7 @@ func newStatsCmd() *cobra.Command { Args: cobrautils.ExactArgs(1), RunE: stats, } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, statsSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) return cmd } @@ -49,7 +42,7 @@ func stats(_ *cobra.Command, args []string) error { globalNetworkFlags, true, false, - statsSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -69,7 +62,7 @@ func stats(_ *cobra.Command, args []string) error { subnetID := sc.Networks[network.Name()].SubnetID if subnetID == ids.Empty { - return errors.New("no subnetID found for the provided subnet name; has this subnet actually been deployed to this network?") + return errors.New("no subnetID found for the provided blockchain name; has this blockchain actually been deployed to this network?") } pClient, infoClient := findAPIEndpoint(network) diff --git a/cmd/blockchaincmd/upgradecmd/apply.go b/cmd/blockchaincmd/upgradecmd/apply.go index ed7095857..3d0284428 100644 --- a/cmd/blockchaincmd/upgradecmd/apply.go +++ b/cmd/blockchaincmd/upgradecmd/apply.go @@ -37,9 +37,9 @@ const ( var ( ErrNetworkNotStartedOutput = "No local network running. Please start the network first." - ErrSubnetNotDeployedOutput = "Looks like this subnet has not been deployed to this network yet." + ErrSubnetNotDeployedOutput = "Looks like this blockchain has not been deployed to this network yet." - errSubnetNotYetDeployed = errors.New("subnet not yet deployed") + errSubnetNotYetDeployed = errors.New("blockchain not yet deployed") errInvalidPrecompiles = errors.New("invalid precompiles") errNoBlockTimestamp = errors.New("no blockTimestamp value set") errBlockTimestampInvalid = errors.New("blockTimestamp is invalid") @@ -330,8 +330,8 @@ func validateUpgrade(blockchainName, networkKey string, sc *models.Sidecar, skip netUpgradeBytes, err := app.ReadUpgradeFile(blockchainName) if err != nil { if err == os.ErrNotExist { - ux.Logger.PrintToUser("No file with upgrade specs for the given subnet has been found") - ux.Logger.PrintToUser("You may need to first create it with the `avalanche subnet upgrade generate` command or import it") + ux.Logger.PrintToUser("No file with upgrade specs for the given blockchain has been found") + ux.Logger.PrintToUser("You may need to first create it with the `avalanche blockchain upgrade generate` command or import it") ux.Logger.PrintToUser("Aborting this command. No changes applied") } return nil, "", err diff --git a/cmd/blockchaincmd/upgradecmd/export.go b/cmd/blockchaincmd/upgradecmd/export.go index 623dcac5a..df6bd748e 100644 --- a/cmd/blockchaincmd/upgradecmd/export.go +++ b/cmd/blockchaincmd/upgradecmd/export.go @@ -32,7 +32,7 @@ func newUpgradeExportCmd() *cobra.Command { func upgradeExportCmd(_ *cobra.Command, args []string) error { blockchainName := args[0] if !app.GenesisExists(blockchainName) { - ux.Logger.PrintToUser("The provided subnet name %q does not exist", blockchainName) + ux.Logger.PrintToUser("The provided blockchain name %q does not exist", blockchainName) return nil } diff --git a/cmd/blockchaincmd/upgradecmd/generate.go b/cmd/blockchaincmd/upgradecmd/generate.go index da8052416..2cd62b990 100644 --- a/cmd/blockchaincmd/upgradecmd/generate.go +++ b/cmd/blockchaincmd/upgradecmd/generate.go @@ -65,7 +65,7 @@ guides the user through the process using an interactive wizard.`, func upgradeGenerateCmd(_ *cobra.Command, args []string) error { blockchainName = args[0] if !app.GenesisExists(blockchainName) { - ux.Logger.PrintToUser("The provided subnet name %q does not exist", blockchainName) + ux.Logger.PrintToUser("The provided blockchain name %q does not exist", blockchainName) return nil } // print some warning/info message @@ -80,7 +80,7 @@ func upgradeGenerateCmd(_ *cobra.Command, args []string) error { "may cause the network to halt and recovering may be difficult."))) ux.Logger.PrintToUser(logging.Reset.Wrap( "Please consult " + logging.Cyan.Wrap( - "https://docs.avax.network/subnets/customize-a-subnet#network-upgrades-enabledisable-precompiles ") + + "https://docs.avax.network/avalanche-l1s/upgrade/customize-avalanche-l1#network-upgrades-enabledisable-precompiles ") + logging.Reset.Wrap("for more information"))) txt := "Press [Enter] to continue, or abort by choosing 'no'" diff --git a/cmd/blockchaincmd/upgradecmd/import.go b/cmd/blockchaincmd/upgradecmd/import.go index 9bcf66d6f..702e8599f 100644 --- a/cmd/blockchaincmd/upgradecmd/import.go +++ b/cmd/blockchaincmd/upgradecmd/import.go @@ -33,7 +33,7 @@ func newUpgradeImportCmd() *cobra.Command { func upgradeImportCmd(_ *cobra.Command, args []string) error { blockchainName := args[0] if !app.GenesisExists(blockchainName) { - ux.Logger.PrintToUser("The provided subnet name %q does not exist", blockchainName) + ux.Logger.PrintToUser("The provided blockchain name %q does not exist", blockchainName) return nil } diff --git a/cmd/blockchaincmd/upgradecmd/print.go b/cmd/blockchaincmd/upgradecmd/print.go index 4f8bc5dd4..59607a9e5 100644 --- a/cmd/blockchaincmd/upgradecmd/print.go +++ b/cmd/blockchaincmd/upgradecmd/print.go @@ -27,7 +27,7 @@ func newUpgradePrintCmd() *cobra.Command { func upgradePrintCmd(_ *cobra.Command, args []string) error { blockchainName := args[0] if !app.GenesisExists(blockchainName) { - ux.Logger.PrintToUser("The provided subnet name %q does not exist", blockchainName) + ux.Logger.PrintToUser("The provided blockchain name %q does not exist", blockchainName) return nil } diff --git a/cmd/blockchaincmd/upgradecmd/upgrade.go b/cmd/blockchaincmd/upgradecmd/upgrade.go index 05ea7ae4f..fbeff22cb 100644 --- a/cmd/blockchaincmd/upgradecmd/upgrade.go +++ b/cmd/blockchaincmd/upgradecmd/upgrade.go @@ -20,17 +20,17 @@ updating your developmental and deployed Blockchains.`, RunE: cobrautils.CommandSuiteUsage, } app = injectedApp - // subnet upgrade vm + // blockchain upgrade vm cmd.AddCommand(newUpgradeVMCmd()) - // subnet upgrade generate + // blockchain upgrade generate cmd.AddCommand(newUpgradeGenerateCmd()) - // subnet upgrade import + // blockchain upgrade import cmd.AddCommand(newUpgradeImportCmd()) - // subnet upgrade export + // blockchain upgrade export cmd.AddCommand(newUpgradeExportCmd()) - // subnet upgrade print + // blockchain upgrade print cmd.AddCommand(newUpgradePrintCmd()) - // subnet upgrade apply + // blockchain upgrade apply cmd.AddCommand(newUpgradeApplyCmd()) return cmd } diff --git a/cmd/blockchaincmd/validators.go b/cmd/blockchaincmd/validators.go index 8d18458b5..e7929b33e 100644 --- a/cmd/blockchaincmd/validators.go +++ b/cmd/blockchaincmd/validators.go @@ -19,24 +19,17 @@ import ( "github.com/spf13/cobra" ) -var validatorsSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - // avalanche blockchain validators func newValidatorsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "validators [blockchainName]", Short: "List subnets validators of a blockchain", - Long: `The blockchain validators command lists the validators of a blockchain's subnet and provides + Long: `The blockchain validators command lists the validators of a blockchain and provides several statistics about them.`, RunE: printValidators, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, validatorsSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) return cmd } @@ -49,7 +42,7 @@ func printValidators(_ *cobra.Command, args []string) error { globalNetworkFlags, true, false, - validatorsSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, blockchainName, ) if err != nil { diff --git a/cmd/commands.md b/cmd/commands.md new file mode 100644 index 000000000..8dca1bac5 --- /dev/null +++ b/cmd/commands.md @@ -0,0 +1,3649 @@ + +## avalanche blockchain + +The blockchain command suite provides a collection of tools for developing +and deploying Blockchains. + +To get started, use the blockchain create command wizard to walk through the +configuration of your very first Blockchain. Then, go ahead and deploy it +with the blockchain deploy command. You can use the rest of the commands to +manage your Blockchain configurations and live deployments. + +**Usage:** +```bash +avalanche blockchain [subcommand] [flags] +``` + +**Subcommands:** + +- [`addValidator`](#avalanche-blockchain-addvalidator): The blockchain addValidator command adds a node as a validator to +an L1 of the user provided deployed network. If the network is proof of +authority, the owner of the validator manager contract must sign the +transaction. If the network is proof of stake, the node must stake the L1's +staking token. Both processes will issue a RegisterL1ValidatorTx on the P-Chain. + +This command currently only works on Blockchains deployed to either the Fuji +Testnet or Mainnet. +- [`changeOwner`](#avalanche-blockchain-changeowner): The blockchain changeOwner changes the owner of the deployed Blockchain. +- [`changeWeight`](#avalanche-blockchain-changeweight): The blockchain changeWeight command changes the weight of a L1 Validator. + +The L1 has to be a Proof of Authority L1. +- [`configure`](#avalanche-blockchain-configure): AvalancheGo nodes support several different configuration files. Each network (a Subnet or an L1) has their own config which applies to all blockchains/VMs in the network. Each blockchain within the network +can have its own chain config. A chain can also have special requirements for the AvalancheGo node +configuration itself. This command allows you to set all those files. +- [`create`](#avalanche-blockchain-create): The blockchain create command builds a new genesis file to configure your Blockchain. +By default, the command runs an interactive wizard. It walks you through +all the steps you need to create your first Blockchain. + +The tool supports deploying Subnet-EVM, and custom VMs. You +can create a custom, user-generated genesis with a custom VM by providing +the path to your genesis and VM binaries with the --genesis and --vm flags. + +By default, running the command with a blockchainName that already exists +causes the command to fail. If you'd like to overwrite an existing +configuration, pass the -f flag. +- [`delete`](#avalanche-blockchain-delete): The blockchain delete command deletes an existing blockchain configuration. +- [`deploy`](#avalanche-blockchain-deploy): The blockchain deploy command deploys your Blockchain configuration locally, to Fuji Testnet, or to Mainnet. + +At the end of the call, the command prints the RPC URL you can use to interact with the Subnet. + +Avalanche-CLI only supports deploying an individual Blockchain once per network. Subsequent +attempts to deploy the same Blockchain to the same network (local, Fuji, Mainnet) aren't +allowed. If you'd like to redeploy a Blockchain locally for testing, you must first call +avalanche network clean to reset all deployed chain state. Subsequent local deploys +redeploy the chain with fresh state. You can deploy the same Blockchain to multiple networks, +so you can take your locally tested Blockchain and deploy it on Fuji or Mainnet. +- [`describe`](#avalanche-blockchain-describe): The blockchain describe command prints the details of a Blockchain configuration to the console. +By default, the command prints a summary of the configuration. By providing the --genesis +flag, the command instead prints out the raw genesis file. +- [`export`](#avalanche-blockchain-export): The blockchain export command write the details of an existing Blockchain deploy to a file. + +The command prompts for an output path. You can also provide one with +the --output flag. +- [`import`](#avalanche-blockchain-import): Import blockchain configurations into avalanche-cli. + +This command suite supports importing from a file created on another computer, +or importing from blockchains running public networks +(e.g. created manually or with the deprecated subnet-cli) +- [`join`](#avalanche-blockchain-join): The blockchain join command configures your validator node to begin validating a new Blockchain. + +To complete this process, you must have access to the machine running your validator. If the +CLI is running on the same machine as your validator, it can generate or update your node's +config file automatically. Alternatively, the command can print the necessary instructions +to update your node manually. To complete the validation process, the Blockchain's admins must add +the NodeID of your validator to the Blockchain's allow list by calling addValidator with your +NodeID. + +After you update your validator's config, you need to restart your validator manually. If +you provide the --avalanchego-config flag, this command attempts to edit the config file +at that path. + +This command currently only supports Blockchains deployed on the Fuji Testnet and Mainnet. +- [`list`](#avalanche-blockchain-list): The blockchain list command prints the names of all created Blockchain configurations. Without any flags, +it prints some general, static information about the Blockchain. With the --deployed flag, the command +shows additional information including the VMID, BlockchainID and SubnetID. +- [`publish`](#avalanche-blockchain-publish): The blockchain publish command publishes the Blockchain's VM to a repository. +- [`removeValidator`](#avalanche-blockchain-removevalidator): The blockchain removeValidator command stops a whitelisted blockchain network validator from +validating your deployed Blockchain. + +To remove the validator from the Subnet's allow list, provide the validator's unique NodeID. You can bypass +these prompts by providing the values with flags. +- [`stats`](#avalanche-blockchain-stats): The blockchain stats command prints validator statistics for the given Blockchain. +- [`upgrade`](#avalanche-blockchain-upgrade): The blockchain upgrade command suite provides a collection of tools for +updating your developmental and deployed Blockchains. +- [`validators`](#avalanche-blockchain-validators): The blockchain validators command lists the validators of a blockchain and provides +several statistics about them. +- [`vmid`](#avalanche-blockchain-vmid): The blockchain vmid command prints the virtual machine ID (VMID) for the given Blockchain. + +**Flags:** + +```bash +-h, --help help for blockchain +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### addValidator + +The blockchain addValidator command adds a node as a validator to +an L1 of the user provided deployed network. If the network is proof of +authority, the owner of the validator manager contract must sign the +transaction. If the network is proof of stake, the node must stake the L1's +staking token. Both processes will issue a RegisterL1ValidatorTx on the P-Chain. + +This command currently only works on Blockchains deployed to either the Fuji +Testnet or Mainnet. + +**Usage:** +```bash +avalanche blockchain addValidator [subcommand] [flags] +``` + +**Flags:** + +```bash +--aggregator-allow-private-peers allow the signature aggregator to connect to peers with private IP (default true) +--aggregator-extra-endpoints strings endpoints for extra nodes that are needed in signature aggregation +--aggregator-log-level string log level to use with signature aggregator (default "Debug") +--aggregator-log-to-stdout use stdout for signature aggregator logs +--balance float set the AVAX balance of the validator that will be used for continuous fee on P-Chain +--blockchain-genesis-key use genesis allocated key to pay fees for completing the validator's registration (blockchain gas token) +--blockchain-key string CLI stored key to use to pay fees for completing the validator's registration (blockchain gas token) +--blockchain-private-key string private key to use to pay fees for completing the validator's registration (blockchain gas token) +--bls-proof-of-possession string set the BLS proof of possession of the validator to add +--bls-public-key string set the BLS public key of the validator to add +--cluster string operate on the given cluster +--create-local-validator create additional local validator and add it to existing running local node +--default-duration (for Subnets, not L1s) set duration so as to validate until primary validator ends its period +--default-start-time (for Subnets, not L1s) use default start time for subnet validator (5 minutes later for fuji & mainnet, 30 seconds later for devnet) +--default-validator-params (for Subnets, not L1s) use default weight/start/duration params for subnet validator +--delegation-fee uint16 (PoS only) delegation fee (in bips) (default 100) +--devnet operate on a devnet network +--disable-owner string P-Chain address that will able to disable the validator with a P-Chain transaction +--endpoint string use the given endpoint for network operations +-e, --ewoq use ewoq key [fuji/devnet only] +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for addValidator +-k, --key string select the key to use [fuji/devnet only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-endpoint string gather node id/bls from publicly available avalanchego apis on the given endpoint +--node-id string node-id of the validator to add +--output-tx-path string (for Subnets, not L1s) file path of the add validator tx +--partial-sync set primary network partial sync for new validators (default true) +--remaining-balance-owner string P-Chain address that will receive any leftover AVAX from the validator when it is removed from Subnet +--rpc string connect to validator manager at the given rpc endpoint +--stake-amount uint (PoS only) amount of tokens to stake +--staking-period duration how long this validator will be staking +--start-time string (for Subnets, not L1s) UTC start time when this validator starts validating, in 'YYYY-MM-DD HH:MM:SS' format +--subnet-auth-keys strings (for Subnets, not L1s) control keys that will be used to authenticate add validator tx +-t, --testnet fuji operate on testnet (alias to fuji) +--wait-for-tx-acceptance (for Subnets, not L1s) just issue the add validator tx, without waiting for its acceptance (default true) +--weight uint set the staking weight of the validator to add (default 20) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### changeOwner + +The blockchain changeOwner changes the owner of the deployed Blockchain. + +**Usage:** +```bash +avalanche blockchain changeOwner [subcommand] [flags] +``` + +**Flags:** + +```bash +--auth-keys strings control keys that will be used to authenticate transfer blockchain ownership tx +--cluster string operate on the given cluster +--control-keys strings addresses that may make blockchain changes +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-e, --ewoq use ewoq key [fuji/devnet] +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for changeOwner +-k, --key string select the key to use [fuji/devnet] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--output-tx-path string file path of the transfer blockchain ownership tx +-s, --same-control-key use the fee-paying key as control key +-t, --testnet fuji operate on testnet (alias to fuji) +--threshold uint32 required number of control key signatures to make blockchain changes +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### changeWeight + +The blockchain changeWeight command changes the weight of a L1 Validator. + +The L1 has to be a Proof of Authority L1. + +**Usage:** +```bash +avalanche blockchain changeWeight [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-e, --ewoq use ewoq key [fuji/devnet only] +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for changeWeight +-k, --key string select the key to use [fuji/devnet only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-endpoint string gather node id/bls from publicly available avalanchego apis on the given endpoint +--node-id string node-id of the validator +-t, --testnet fuji operate on testnet (alias to fuji) +--weight uint set the new staking weight of the validator +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### configure + +AvalancheGo nodes support several different configuration files. Each network (a Subnet or an L1) has their own config which applies to all blockchains/VMs in the network. Each blockchain within the network +can have its own chain config. A chain can also have special requirements for the AvalancheGo node +configuration itself. This command allows you to set all those files. + +**Usage:** +```bash +avalanche blockchain configure [subcommand] [flags] +``` + +**Flags:** + +```bash +--chain-config string path to the chain configuration +-h, --help help for configure +--node-config string path to avalanchego node configuration +--per-node-chain-config string path to per node chain configuration for local network +--subnet-config string path to the subnet configuration +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### create + +The blockchain create command builds a new genesis file to configure your Blockchain. +By default, the command runs an interactive wizard. It walks you through +all the steps you need to create your first Blockchain. + +The tool supports deploying Subnet-EVM, and custom VMs. You +can create a custom, user-generated genesis with a custom VM by providing +the path to your genesis and VM binaries with the --genesis and --vm flags. + +By default, running the command with a blockchainName that already exists +causes the command to fail. If you'd like to overwrite an existing +configuration, pass the -f flag. + +**Usage:** +```bash +avalanche blockchain create [subcommand] [flags] +``` + +**Flags:** + +```bash +--custom use a custom VM template +--custom-vm-branch string custom vm branch or commit +--custom-vm-build-script string custom vm build-script +--custom-vm-path string file path of custom vm to use +--custom-vm-repo-url string custom vm repository url +--debug enable blockchain debugging (default true) +--evm use the Subnet-EVM as the base template +--evm-chain-id uint chain ID to use with Subnet-EVM +--evm-defaults deprecation notice: use '--production-defaults' +--evm-token string token symbol to use with Subnet-EVM +--external-gas-token use a gas token from another blockchain +-f, --force overwrite the existing configuration if one exists +--from-github-repo generate custom VM binary from github repository +--genesis string file path of genesis to use +-h, --help help for create +--icm interoperate with other blockchains using ICM +--icm-registry-at-genesis setup ICM registry smart contract on genesis [experimental] +--latest use latest Subnet-EVM released version, takes precedence over --vm-version +--pre-release use latest Subnet-EVM pre-released version, takes precedence over --vm-version +--production-defaults use default production settings for your blockchain +--proof-of-authority use proof of authority(PoA) for validator management +--proof-of-stake use proof of stake(PoS) for validator management +--proxy-contract-owner string EVM address that controls ProxyAdmin for TransparentProxy of ValidatorManager contract +--reward-basis-points uint (PoS only) reward basis points for PoS Reward Calculator (default 100) +--sovereign set to false if creating non-sovereign blockchain (default true) +--teleporter interoperate with other blockchains using ICM +--test-defaults use default test settings for your blockchain +--validator-manager-owner string EVM address that controls Validator Manager Owner +--vm string file path of custom vm to use. alias to custom-vm-path +--vm-version string version of Subnet-EVM template to use +--warp generate a vm with warp support (needed for ICM) (default true) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### delete + +The blockchain delete command deletes an existing blockchain configuration. + +**Usage:** +```bash +avalanche blockchain delete [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for delete +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### deploy + +The blockchain deploy command deploys your Blockchain configuration locally, to Fuji Testnet, or to Mainnet. + +At the end of the call, the command prints the RPC URL you can use to interact with the Subnet. + +Avalanche-CLI only supports deploying an individual Blockchain once per network. Subsequent +attempts to deploy the same Blockchain to the same network (local, Fuji, Mainnet) aren't +allowed. If you'd like to redeploy a Blockchain locally for testing, you must first call +avalanche network clean to reset all deployed chain state. Subsequent local deploys +redeploy the chain with fresh state. You can deploy the same Blockchain to multiple networks, +so you can take your locally tested Blockchain and deploy it on Fuji or Mainnet. + +**Usage:** +```bash +avalanche blockchain deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--aggregator-allow-private-peers allow the signature aggregator to connect to peers with private IP (default true) +--aggregator-extra-endpoints strings endpoints for extra nodes that are needed in signature aggregation +--aggregator-log-level string log level to use with signature aggregator (default "Debug") +--aggregator-log-to-stdout use stdout for signature aggregator logs +--auth-keys strings control keys that will be used to authenticate chain creation +--avalanchego-path string use this avalanchego binary path +--avalanchego-version string use this version of avalanchego (ex: v1.17.12) (default "latest-prerelease") +--balance float set the AVAX balance of each bootstrap validator that will be used for continuous fee on P-Chain (default 0.1) +--blockchain-genesis-key use genesis allocated key to fund validator manager initialization +--blockchain-key string CLI stored key to use to fund validator manager initialization +--blockchain-private-key string private key to use to fund validator manager initialization +--bootstrap-endpoints strings take validator node info from the given endpoints +--bootstrap-filepath string JSON file path that provides details about bootstrap validators, leave Node-ID and BLS values empty if using --generate-node-id=true +--cchain-funding-key string key to be used to fund relayer account on cchain +--cchain-icm-key string key to be used to pay for ICM deploys on C-Chain +--change-owner-address string address that will receive change if node is no longer L1 validator +--cluster string operate on the given cluster +--control-keys strings addresses that may make blockchain changes +--convert-only avoid node track, restart and poa manager setup +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-e, --ewoq use ewoq key [fuji/devnet deploy only] +-f, --fuji testnet operate on fuji (alias to testnet +--generate-node-id 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) +-h, --help help for deploy +--icm-key string key to be used to pay for ICM deploys (default "cli-teleporter-deployer") +--icm-version string ICM version to deploy (default "latest") +-k, --key string select the key to use [fuji/devnet deploy only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--mainnet-chain-id uint32 use different ChainID for mainnet deployment +--noicm skip automatic ICM deploy +--num-bootstrap-validators int (only if --generate-node-id is true) number of bootstrap validators to set up in sovereign L1 validator) +--num-local-nodes int number of nodes to be created on local machine +--num-nodes uint32 number of nodes to be created on local network deploy (default 2) +--output-tx-path string file path of the blockchain creation tx +--partial-sync set primary network partial sync for new validators (default true) +--pos-maximum-stake-amount uint maximum stake amount (default 1000) +--pos-maximum-stake-multiplier uint8 maximum stake multiplier (default 1) +--pos-minimum-delegation-fee uint16 minimum delegation fee (default 1) +--pos-minimum-stake-amount uint minimum stake amount (default 1) +--pos-minimum-stake-duration uint minimum stake duration (in seconds) (default 100) +--pos-weight-to-value-factor uint weight to value factor (default 1) +--relay-cchain relay C-Chain as source and destination (default true) +--relayer-allow-private-ips allow relayer to connec to private ips (default true) +--relayer-amount float automatically fund relayer fee payments with the given amount +--relayer-key string key to be used by default both for rewards and to pay fees +--relayer-log-level string log level to be used for relayer logs (default "info") +--relayer-path string relayer binary to use +--relayer-version string relayer version to deploy (default "latest-prerelease") +-s, --same-control-key use the fee-paying key as control key +--skip-icm-deploy skip automatic ICM deploy +--skip-local-teleporter skip automatic ICM deploy on local networks [to be deprecated] +--skip-relayer skip relayer deploy +--skip-teleporter-deploy skip automatic ICM deploy +-u, --subnet-id string do not create a subnet, deploy the blockchain into the given subnet id +--subnet-only only create a subnet +--teleporter-messenger-contract-address-path string path to an ICM Messenger contract address file +--teleporter-messenger-deployer-address-path string path to an ICM Messenger deployer address file +--teleporter-messenger-deployer-tx-path string path to an ICM Messenger deployer tx file +--teleporter-registry-bytecode-path string path to an ICM Registry bytecode file +--teleporter-version string ICM version to deploy (default "latest") +-t, --testnet fuji operate on testnet (alias to fuji) +--threshold uint32 required number of control key signatures to make blockchain changes +--use-local-machine use local machine as a blockchain validator +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### describe + +The blockchain describe command prints the details of a Blockchain configuration to the console. +By default, the command prints a summary of the configuration. By providing the --genesis +flag, the command instead prints out the raw genesis file. + +**Usage:** +```bash +avalanche blockchain describe [subcommand] [flags] +``` + +**Flags:** + +```bash +-g, --genesis Print the genesis to the console directly instead of the summary +-h, --help help for describe +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### export + +The blockchain export command write the details of an existing Blockchain deploy to a file. + +The command prompts for an output path. You can also provide one with +the --output flag. + +**Usage:** +```bash +avalanche blockchain export [subcommand] [flags] +``` + +**Flags:** + +```bash +--custom-vm-branch string custom vm branch +--custom-vm-build-script string custom vm build-script +--custom-vm-repo-url string custom vm repository url +-h, --help help for export +-o, --output string write the export data to the provided file path +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### import + +Import blockchain configurations into avalanche-cli. + +This command suite supports importing from a file created on another computer, +or importing from blockchains running public networks +(e.g. created manually or with the deprecated subnet-cli) + +**Usage:** +```bash +avalanche blockchain import [subcommand] [flags] +``` + +**Subcommands:** + +- [`file`](#avalanche-blockchain-import-file): The blockchain import command will import a blockchain configuration from a file or a git repository. + +To import from a file, you can optionally provide the path as a command-line argument. +Alternatively, running the command without any arguments triggers an interactive wizard. +To import from a repository, go through the wizard. By default, an imported Blockchain doesn't +overwrite an existing Blockchain with the same name. To allow overwrites, provide the --force +flag. +- [`public`](#avalanche-blockchain-import-public): The blockchain import public command imports a Blockchain configuration from a running network. + +By default, an imported Blockchain +doesn't overwrite an existing Blockchain with the same name. To allow overwrites, provide the --force +flag. + +**Flags:** + +```bash +-h, --help help for import +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### import file + +The blockchain import command will import a blockchain configuration from a file or a git repository. + +To import from a file, you can optionally provide the path as a command-line argument. +Alternatively, running the command without any arguments triggers an interactive wizard. +To import from a repository, go through the wizard. By default, an imported Blockchain doesn't +overwrite an existing Blockchain with the same name. To allow overwrites, provide the --force +flag. + +**Usage:** +```bash +avalanche blockchain import file [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string the blockchain configuration to import from the provided repo +--branch string the repo branch to use if downloading a new repo +-f, --force overwrite the existing configuration if one exists +-h, --help help for file +--repo string the repo to import (ex: ava-labs/avalanche-plugins-core) or url to download the repo from +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### import public + +The blockchain import public command imports a Blockchain configuration from a running network. + +By default, an imported Blockchain +doesn't overwrite an existing Blockchain with the same name. To allow overwrites, provide the --force +flag. + +**Usage:** +```bash +avalanche blockchain import public [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain-id string the blockchain ID +--cluster string operate on the given cluster +--custom use a custom VM template +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--evm import a subnet-evm +--force overwrite the existing configuration if one exists +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for public +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-url string [optional] URL of an already running validator +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### join + +The blockchain join command configures your validator node to begin validating a new Blockchain. + +To complete this process, you must have access to the machine running your validator. If the +CLI is running on the same machine as your validator, it can generate or update your node's +config file automatically. Alternatively, the command can print the necessary instructions +to update your node manually. To complete the validation process, the Blockchain's admins must add +the NodeID of your validator to the Blockchain's allow list by calling addValidator with your +NodeID. + +After you update your validator's config, you need to restart your validator manually. If +you provide the --avalanchego-config flag, this command attempts to edit the config file +at that path. + +This command currently only supports Blockchains deployed on the Fuji Testnet and Mainnet. + +**Usage:** +```bash +avalanche blockchain join [subcommand] [flags] +``` + +**Flags:** + +```bash +--avalanchego-config string file path of the avalanchego config file +--cluster string operate on the given cluster +--data-dir string path of avalanchego's data dir directory +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--force-write if true, skip to prompt to overwrite the config file +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for join +-k, --key string select the key to use [fuji only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-id string set the NodeID of the validator to check +--plugin-dir string file path of avalanchego's plugin directory +--print if true, print the manual config without prompting +--stake-amount uint amount of tokens to stake on validator +--staking-period duration how long validator validates for after start time +--start-time string start time that validator starts validating +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### list + +The blockchain list command prints the names of all created Blockchain configurations. Without any flags, +it prints some general, static information about the Blockchain. With the --deployed flag, the command +shows additional information including the VMID, BlockchainID and SubnetID. + +**Usage:** +```bash +avalanche blockchain list [subcommand] [flags] +``` + +**Flags:** + +```bash +--deployed show additional deploy information +-h, --help help for list +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### publish + +The blockchain publish command publishes the Blockchain's VM to a repository. + +**Usage:** +```bash +avalanche blockchain publish [subcommand] [flags] +``` + +**Flags:** + +```bash +--alias string We publish to a remote repo, but identify the repo locally under a user-provided alias (e.g. myrepo). +--force If true, ignores if the blockchain has been published in the past, and attempts a forced publish. +-h, --help help for publish +--no-repo-path string Do not let the tool manage file publishing, but have it only generate the files and put them in the location given by this flag. +--repo-url string The URL of the repo where we are publishing +--subnet-file-path string Path to the Blockchain description file. If not given, a prompting sequence will be initiated. +--vm-file-path string Path to the VM description file. If not given, a prompting sequence will be initiated. +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### removeValidator + +The blockchain removeValidator command stops a whitelisted blockchain network validator from +validating your deployed Blockchain. + +To remove the validator from the Subnet's allow list, provide the validator's unique NodeID. You can bypass +these prompts by providing the values with flags. + +**Usage:** +```bash +avalanche blockchain removeValidator [subcommand] [flags] +``` + +**Flags:** + +```bash +--aggregator-allow-private-peers allow the signature aggregator to connect to peers with private IP (default true) +--aggregator-extra-endpoints strings endpoints for extra nodes that are needed in signature aggregation +--aggregator-log-level string log level to use with signature aggregator (default "Debug") +--aggregator-log-to-stdout use stdout for signature aggregator logs +--auth-keys strings (for non-SOV blockchain only) control keys that will be used to authenticate the removeValidator tx +--blockchain-genesis-key use genesis allocated key to pay fees for completing the validator's removal (blockchain gas token) +--blockchain-key string CLI stored key to use to pay fees for completing the validator's removal (blockchain gas token) +--blockchain-private-key string private key to use to pay fees for completing the validator's removal (blockchain gas token) +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--force force validator removal even if it's not getting rewarded +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for removeValidator +-k, --key string select the key to use [fuji deploy only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji) +--ledger-addrs strings use the given ledger addresses +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-endpoint string remove validator that responds to the given endpoint +--node-id string node-id of the validator +--output-tx-path string (for non-SOV blockchain only) file path of the removeValidator tx +--rpc string connect to validator manager at the given rpc endpoint +-t, --testnet fuji operate on testnet (alias to fuji) +--uptime uint validator's uptime in seconds. If not provided, it will be automatically calculated +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### stats + +The blockchain stats command prints validator statistics for the given Blockchain. + +**Usage:** +```bash +avalanche blockchain stats [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for stats +-l, --local operate on a local network +-m, --mainnet operate on mainnet +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### upgrade + +The blockchain upgrade command suite provides a collection of tools for +updating your developmental and deployed Blockchains. + +**Usage:** +```bash +avalanche blockchain upgrade [subcommand] [flags] +``` + +**Subcommands:** + +- [`apply`](#avalanche-blockchain-upgrade-apply): Apply generated upgrade bytes to running Blockchain nodes to trigger a network upgrade. + +For public networks (Fuji Testnet or Mainnet), to complete this process, +you must have access to the machine running your validator. +If the CLI is running on the same machine as your validator, it can manipulate your node's +configuration automatically. Alternatively, the command can print the necessary instructions +to upgrade your node manually. + +After you update your validator's configuration, you need to restart your validator manually. +If you provide the --avalanchego-chain-config-dir flag, this command attempts to write the upgrade file at that path. +Refer to https://docs.avax.network/nodes/maintain/chain-config-flags#subnet-chain-configs for related documentation. +- [`export`](#avalanche-blockchain-upgrade-export): Export the upgrade bytes file to a location of choice on disk +- [`generate`](#avalanche-blockchain-upgrade-generate): The blockchain upgrade generate command builds a new upgrade.json file to customize your Blockchain. It +guides the user through the process using an interactive wizard. +- [`import`](#avalanche-blockchain-upgrade-import): Import the upgrade bytes file into the local environment +- [`print`](#avalanche-blockchain-upgrade-print): Print the upgrade.json file content +- [`vm`](#avalanche-blockchain-upgrade-vm): The blockchain upgrade vm command enables the user to upgrade their Blockchain's VM binary. The command +can upgrade both local Blockchains and publicly deployed Blockchains on Fuji and Mainnet. + +The command walks the user through an interactive wizard. The user can skip the wizard by providing +command line flags. + +**Flags:** + +```bash +-h, --help help for upgrade +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade apply + +Apply generated upgrade bytes to running Blockchain nodes to trigger a network upgrade. + +For public networks (Fuji Testnet or Mainnet), to complete this process, +you must have access to the machine running your validator. +If the CLI is running on the same machine as your validator, it can manipulate your node's +configuration automatically. Alternatively, the command can print the necessary instructions +to upgrade your node manually. + +After you update your validator's configuration, you need to restart your validator manually. +If you provide the --avalanchego-chain-config-dir flag, this command attempts to write the upgrade file at that path. +Refer to https://docs.avax.network/nodes/maintain/chain-config-flags#subnet-chain-configs for related documentation. + +**Usage:** +```bash +avalanche blockchain upgrade apply [subcommand] [flags] +``` + +**Flags:** + +```bash +--avalanchego-chain-config-dir string avalanchego's chain config file directory (default "/home/runner/.avalanchego/chains") +--config create upgrade config for future subnet deployments (same as generate) +--force If true, don't prompt for confirmation of timestamps in the past +--fuji fuji apply upgrade existing fuji deployment (alias for `testnet`) +-h, --help help for apply +--local local apply upgrade existing local deployment +--mainnet mainnet apply upgrade existing mainnet deployment +--print if true, print the manual config without prompting (for public networks only) +--testnet testnet apply upgrade existing testnet deployment (alias for `fuji`) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade export + +Export the upgrade bytes file to a location of choice on disk + +**Usage:** +```bash +avalanche blockchain upgrade export [subcommand] [flags] +``` + +**Flags:** + +```bash +--force If true, overwrite a possibly existing file without prompting +-h, --help help for export +--upgrade-filepath string Export upgrade bytes file to location of choice on disk +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade generate + +The blockchain upgrade generate command builds a new upgrade.json file to customize your Blockchain. It +guides the user through the process using an interactive wizard. + +**Usage:** +```bash +avalanche blockchain upgrade generate [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for generate +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade import + +Import the upgrade bytes file into the local environment + +**Usage:** +```bash +avalanche blockchain upgrade import [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for import +--upgrade-filepath string Import upgrade bytes file into local environment +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade print + +Print the upgrade.json file content + +**Usage:** +```bash +avalanche blockchain upgrade print [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for print +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### upgrade vm + +The blockchain upgrade vm command enables the user to upgrade their Blockchain's VM binary. The command +can upgrade both local Blockchains and publicly deployed Blockchains on Fuji and Mainnet. + +The command walks the user through an interactive wizard. The user can skip the wizard by providing +command line flags. + +**Usage:** +```bash +avalanche blockchain upgrade vm [subcommand] [flags] +``` + +**Flags:** + +```bash +--binary string Upgrade to custom binary +--config upgrade config for future subnet deployments +--fuji fuji upgrade existing fuji deployment (alias for `testnet`) +-h, --help help for vm +--latest upgrade to latest version +--local local upgrade existing local deployment +--mainnet mainnet upgrade existing mainnet deployment +--plugin-dir string plugin directory to automatically upgrade VM +--print print instructions for upgrading +--testnet testnet upgrade existing testnet deployment (alias for `fuji`) +--version string Upgrade to custom version +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### validators + +The blockchain validators command lists the validators of a blockchain and provides +several statistics about them. + +**Usage:** +```bash +avalanche blockchain validators [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for validators +-l, --local operate on a local network +-m, --mainnet operate on mainnet +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### vmid + +The blockchain vmid command prints the virtual machine ID (VMID) for the given Blockchain. + +**Usage:** +```bash +avalanche blockchain vmid [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for vmid +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche config + +Customize configuration for Avalanche-CLI + +**Usage:** +```bash +avalanche config [subcommand] [flags] +``` + +**Subcommands:** + +- [`authorize-cloud-access`](#avalanche-config-authorize-cloud-access): set preferences to authorize access to cloud resources +- [`metrics`](#avalanche-config-metrics): set user metrics collection preferences +- [`migrate`](#avalanche-config-migrate): migrate command migrates old ~/.avalanche-cli.json and ~/.avalanche-cli/config to /.avalanche-cli/config.json.. +- [`snapshotsAutoSave`](#avalanche-config-snapshotsautosave): set user preference between auto saving local network snapshots or not +- [`update`](#avalanche-config-update): set user preference between update check or not + +**Flags:** + +```bash +-h, --help help for config +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### authorize-cloud-access + +set preferences to authorize access to cloud resources + +**Usage:** +```bash +avalanche config authorize-cloud-access [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for authorize-cloud-access +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### metrics + +set user metrics collection preferences + +**Usage:** +```bash +avalanche config metrics [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for metrics +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### migrate + +migrate command migrates old ~/.avalanche-cli.json and ~/.avalanche-cli/config to /.avalanche-cli/config.json.. + +**Usage:** +```bash +avalanche config migrate [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for migrate +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### snapshotsAutoSave + +set user preference between auto saving local network snapshots or not + +**Usage:** +```bash +avalanche config snapshotsAutoSave [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for snapshotsAutoSave +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### update + +set user preference between update check or not + +**Usage:** +```bash +avalanche config update [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for update +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche contract + +The contract command suite provides a collection of tools for deploying +and interacting with smart contracts. + +**Usage:** +```bash +avalanche contract [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-contract-deploy): The contract command suite provides a collection of tools for deploying +smart contracts. +- [`initValidatorManager`](#avalanche-contract-initvalidatormanager): Initializes Proof of Authority(PoA) or Proof of Stake(PoS)Validator Manager contract on a Blockchain and sets up initial validator set on the Blockchain. For more info on Validator Manager, please head to https://github.com/ava-labs/icm-contracts/tree/main/contracts/validator-manager + +**Flags:** + +```bash +-h, --help help for contract +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### deploy + +The contract command suite provides a collection of tools for deploying +smart contracts. + +**Usage:** +```bash +avalanche contract deploy [subcommand] [flags] +``` + +**Subcommands:** + +- [`erc20`](#avalanche-contract-deploy-erc20): Deploy an ERC20 token into a given Network and Blockchain + +**Flags:** + +```bash +-h, --help help for deploy +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### deploy erc20 + +Deploy an ERC20 token into a given Network and Blockchain + +**Usage:** +```bash +avalanche contract deploy erc20 [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string deploy the ERC20 contract into the given CLI blockchain +--blockchain-id string deploy the ERC20 contract into the given blockchain ID/Alias +--c-chain deploy the ERC20 contract into C-Chain +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--funded string set the funded address +--genesis-key use genesis allocated key as contract deployer +-h, --help help for erc20 +--key string CLI stored key to use as contract deployer +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--private-key string private key to use as contract deployer +--rpc string deploy the contract into the given rpc endpoint +--supply uint set the token supply +--symbol string set the token symbol +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### initValidatorManager + +Initializes Proof of Authority(PoA) or Proof of Stake(PoS)Validator Manager contract on a Blockchain and sets up initial validator set on the Blockchain. For more info on Validator Manager, please head to https://github.com/ava-labs/icm-contracts/tree/main/contracts/validator-manager + +**Usage:** +```bash +avalanche contract initValidatorManager [subcommand] [flags] +``` + +**Flags:** + +```bash +--aggregator-allow-private-peers allow the signature aggregator to connect to peers with private IP (default true) +--aggregator-extra-endpoints strings endpoints for extra nodes that are needed in signature aggregation +--aggregator-log-level string log level to use with signature aggregator (default "Debug") +--aggregator-log-to-stdout dump signature aggregator logs to stdout +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key as contract deployer +-h, --help help for initValidatorManager +--key string CLI stored key to use as contract deployer +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--pos-maximum-stake-amount uint (PoS only) maximum stake amount (default 1000) +--pos-maximum-stake-multiplier uint8 (PoS only )maximum stake multiplier (default 1) +--pos-minimum-delegation-fee uint16 (PoS only) minimum delegation fee (default 1) +--pos-minimum-stake-amount uint (PoS only) minimum stake amount (default 1) +--pos-minimum-stake-duration uint (PoS only) minimum stake duration (in seconds) (default 100) +--pos-reward-calculator-address string (PoS only) initialize the ValidatorManager with reward calculator address +--pos-weight-to-value-factor uint (PoS only) weight to value factor (default 1) +--private-key string private key to use as contract deployer +--rpc string deploy the contract into the given rpc endpoint +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche help + +Help provides help for any command in the application. +Simply type avalanche help [path to command] for full details. + +**Usage:** +```bash +avalanche help [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for help +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche icm + +The messenger command suite provides a collection of tools for interacting +with ICM messenger contracts. + +**Usage:** +```bash +avalanche icm [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-icm-deploy): Deploys ICM Messenger and Registry into a given L1. +- [`sendMsg`](#avalanche-icm-sendmsg): Sends and wait reception for a ICM msg between two blockchains. + +**Flags:** + +```bash +-h, --help help for icm +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### deploy + +Deploys ICM Messenger and Registry into a given L1. + +**Usage:** +```bash +avalanche icm deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string deploy ICM into the given CLI blockchain +--blockchain-id string deploy ICM into the given blockchain ID/Alias +--c-chain deploy ICM into C-Chain +--cchain-key string key to be used to pay fees to deploy ICM to C-Chain +--cluster string operate on the given cluster +--deploy-messenger deploy ICM Messenger (default true) +--deploy-registry deploy ICM Registry (default true) +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--force-registry-deploy deploy ICM Registry even if Messenger has already been deployed +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key to fund ICM deploy +-h, --help help for deploy +--include-cchain deploy ICM also to C-Chain +--key string CLI stored key to use to fund ICM deploy +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--messenger-contract-address-path string path to a messenger contract address file +--messenger-deployer-address-path string path to a messenger deployer address file +--messenger-deployer-tx-path string path to a messenger deployer tx file +--private-key string private key to use to fund ICM deploy +--registry-bytecode-path string path to a registry bytecode file +--rpc-url string use the given RPC URL to connect to the subnet +-t, --testnet fuji operate on testnet (alias to fuji) +--version string version to deploy (default "latest") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### sendMsg + +Sends and wait reception for a ICM msg between two blockchains. + +**Usage:** +```bash +avalanche icm sendMsg [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--dest-rpc string use the given destination blockchain rpc endpoint +--destination-address string deliver the message to the given contract destination address +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key as message originator and to pay source blockchain fees +-h, --help help for sendMsg +--hex-encoded given message is hex encoded +--key string CLI stored key to use as message originator and to pay source blockchain fees +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--private-key string private key to use as message originator and to pay source blockchain fees +--source-rpc string use the given source blockchain rpc endpoint +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche ictt + +The ictt command suite provides tools to deploy and manage Interchain Token Transferrers. + +**Usage:** +```bash +avalanche ictt [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-ictt-deploy): Deploys a Token Transferrer into a given Network and Subnets + +**Flags:** + +```bash +-h, --help help for ictt +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### deploy + +Deploys a Token Transferrer into a given Network and Subnets + +**Usage:** +```bash +avalanche ictt deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--c-chain-home set the Transferrer's Home Chain into C-Chain +--c-chain-remote set the Transferrer's Remote Chain into C-Chain +--cluster string operate on the given cluster +--deploy-erc20-home string deploy a Transferrer Home for the given Chain's ERC20 Token +--deploy-native-home deploy a Transferrer Home for the Chain's Native Token +--deploy-native-remote deploy a Transferrer Remote for the Chain's Native Token +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for deploy +--home-blockchain string set the Transferrer's Home Chain into the given CLI blockchain +--home-genesis-key use genesis allocated key to deploy Transferrer Home +--home-key string CLI stored key to use to deploy Transferrer Home +--home-private-key string private key to use to deploy Transferrer Home +--home-rpc string use the given RPC URL to connect to the home blockchain +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--remote-blockchain string set the Transferrer's Remote Chain into the given CLI blockchain +--remote-genesis-key use genesis allocated key to deploy Transferrer Remote +--remote-key string CLI stored key to use to deploy Transferrer Remote +--remote-private-key string private key to use to deploy Transferrer Remote +--remote-rpc string use the given RPC URL to connect to the remote blockchain +--remote-token-decimals uint8 use the given number of token decimals for the Transferrer Remote [defaults to token home's decimals (18 for a new wrapped native home token)] +--remove-minter-admin remove the native minter precompile admin found on remote blockchain genesis +-t, --testnet fuji operate on testnet (alias to fuji) +--use-home string use the given Transferrer's Home Address +--version string tag/branch/commit of Avalanche Interchain Token Transfer (ICTT) to be used (defaults to main branch) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche interchain + +The interchain command suite provides a collection of tools to +set and manage interoperability between blockchains. + +**Usage:** +```bash +avalanche interchain [subcommand] [flags] +``` + +**Subcommands:** + +- [`messenger`](#avalanche-interchain-messenger): The messenger command suite provides a collection of tools for interacting +with ICM messenger contracts. +- [`relayer`](#avalanche-interchain-relayer): The relayer command suite provides a collection of tools for deploying +and configuring an ICM relayers. +- [`tokenTransferrer`](#avalanche-interchain-tokentransferrer): The tokenTransfer command suite provides tools to deploy and manage Token Transferrers. + +**Flags:** + +```bash +-h, --help help for interchain +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### messenger + +The messenger command suite provides a collection of tools for interacting +with ICM messenger contracts. + +**Usage:** +```bash +avalanche interchain messenger [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-interchain-messenger-deploy): Deploys ICM Messenger and Registry into a given L1. +- [`sendMsg`](#avalanche-interchain-messenger-sendmsg): Sends and wait reception for a ICM msg between two blockchains. + +**Flags:** + +```bash +-h, --help help for messenger +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### messenger deploy + +Deploys ICM Messenger and Registry into a given L1. + +**Usage:** +```bash +avalanche interchain messenger deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string deploy ICM into the given CLI blockchain +--blockchain-id string deploy ICM into the given blockchain ID/Alias +--c-chain deploy ICM into C-Chain +--cchain-key string key to be used to pay fees to deploy ICM to C-Chain +--cluster string operate on the given cluster +--deploy-messenger deploy ICM Messenger (default true) +--deploy-registry deploy ICM Registry (default true) +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--force-registry-deploy deploy ICM Registry even if Messenger has already been deployed +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key to fund ICM deploy +-h, --help help for deploy +--include-cchain deploy ICM also to C-Chain +--key string CLI stored key to use to fund ICM deploy +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--messenger-contract-address-path string path to a messenger contract address file +--messenger-deployer-address-path string path to a messenger deployer address file +--messenger-deployer-tx-path string path to a messenger deployer tx file +--private-key string private key to use to fund ICM deploy +--registry-bytecode-path string path to a registry bytecode file +--rpc-url string use the given RPC URL to connect to the subnet +-t, --testnet fuji operate on testnet (alias to fuji) +--version string version to deploy (default "latest") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### messenger sendMsg + +Sends and wait reception for a ICM msg between two blockchains. + +**Usage:** +```bash +avalanche interchain messenger sendMsg [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--dest-rpc string use the given destination blockchain rpc endpoint +--destination-address string deliver the message to the given contract destination address +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key as message originator and to pay source blockchain fees +-h, --help help for sendMsg +--hex-encoded given message is hex encoded +--key string CLI stored key to use as message originator and to pay source blockchain fees +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--private-key string private key to use as message originator and to pay source blockchain fees +--source-rpc string use the given source blockchain rpc endpoint +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### relayer + +The relayer command suite provides a collection of tools for deploying +and configuring an ICM relayers. + +**Usage:** +```bash +avalanche interchain relayer [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-interchain-relayer-deploy): Deploys an ICM Relayer for the given Network. +- [`logs`](#avalanche-interchain-relayer-logs): Shows pretty formatted AWM relayer logs +- [`start`](#avalanche-interchain-relayer-start): Starts AWM relayer on the specified network (Currently only for local network). +- [`stop`](#avalanche-interchain-relayer-stop): Stops AWM relayer on the specified network (Currently only for local network, cluster). + +**Flags:** + +```bash +-h, --help help for relayer +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### relayer deploy + +Deploys an ICM Relayer for the given Network. + +**Usage:** +```bash +avalanche interchain relayer deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--allow-private-ips allow relayer to connec to private ips (default true) +--amount float automatically fund l1s fee payments with the given amount +--bin-path string use the given relayer binary +--blockchain-funding-key string key to be used to fund relayer account on all l1s +--blockchains strings blockchains to relay as source and destination +--cchain relay C-Chain as source and destination +--cchain-amount float automatically fund cchain fee payments with the given amount +--cchain-funding-key string key to be used to fund relayer account on cchain +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for deploy +--key string key to be used by default both for rewards and to pay fees +-l, --local operate on a local network +--log-level string log level to use for relayer logs +-t, --testnet fuji operate on testnet (alias to fuji) +--version string version to deploy (default "latest-prerelease") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--skip-update-check skip check for new versions +``` + + +#### relayer logs + +Shows pretty formatted AWM relayer logs + +**Usage:** +```bash +avalanche interchain relayer logs [subcommand] [flags] +``` + +**Flags:** + +```bash +--endpoint string use the given endpoint for network operations +--first uint output first N log lines +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for logs +--last uint output last N log lines +-l, --local operate on a local network +--raw raw logs output +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### relayer start + +Starts AWM relayer on the specified network (Currently only for local network). + +**Usage:** +```bash +avalanche interchain relayer start [subcommand] [flags] +``` + +**Flags:** + +```bash +--bin-path string use the given relayer binary +--cluster string operate on the given cluster +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for start +-l, --local operate on a local network +-t, --testnet fuji operate on testnet (alias to fuji) +--version string version to use (default "latest-prerelease") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### relayer stop + +Stops AWM relayer on the specified network (Currently only for local network, cluster). + +**Usage:** +```bash +avalanche interchain relayer stop [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for stop +-l, --local operate on a local network +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### tokenTransferrer + +The tokenTransfer command suite provides tools to deploy and manage Token Transferrers. + +**Usage:** +```bash +avalanche interchain tokenTransferrer [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-interchain-tokentransferrer-deploy): Deploys a Token Transferrer into a given Network and Subnets + +**Flags:** + +```bash +-h, --help help for tokenTransferrer +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### tokenTransferrer deploy + +Deploys a Token Transferrer into a given Network and Subnets + +**Usage:** +```bash +avalanche interchain tokenTransferrer deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--c-chain-home set the Transferrer's Home Chain into C-Chain +--c-chain-remote set the Transferrer's Remote Chain into C-Chain +--cluster string operate on the given cluster +--deploy-erc20-home string deploy a Transferrer Home for the given Chain's ERC20 Token +--deploy-native-home deploy a Transferrer Home for the Chain's Native Token +--deploy-native-remote deploy a Transferrer Remote for the Chain's Native Token +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for deploy +--home-blockchain string set the Transferrer's Home Chain into the given CLI blockchain +--home-genesis-key use genesis allocated key to deploy Transferrer Home +--home-key string CLI stored key to use to deploy Transferrer Home +--home-private-key string private key to use to deploy Transferrer Home +--home-rpc string use the given RPC URL to connect to the home blockchain +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--remote-blockchain string set the Transferrer's Remote Chain into the given CLI blockchain +--remote-genesis-key use genesis allocated key to deploy Transferrer Remote +--remote-key string CLI stored key to use to deploy Transferrer Remote +--remote-private-key string private key to use to deploy Transferrer Remote +--remote-rpc string use the given RPC URL to connect to the remote blockchain +--remote-token-decimals uint8 use the given number of token decimals for the Transferrer Remote [defaults to token home's decimals (18 for a new wrapped native home token)] +--remove-minter-admin remove the native minter precompile admin found on remote blockchain genesis +-t, --testnet fuji operate on testnet (alias to fuji) +--use-home string use the given Transferrer's Home Address +--version string tag/branch/commit of Avalanche Interchain Token Transfer (ICTT) to be used (defaults to main branch) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche key + +The key command suite provides a collection of tools for creating and managing +signing keys. You can use these keys to deploy Subnets to the Fuji Testnet, +but these keys are NOT suitable to use in production environments. DO NOT use +these keys on Mainnet. + +To get started, use the key create command. + +**Usage:** +```bash +avalanche key [subcommand] [flags] +``` + +**Subcommands:** + +- [`create`](#avalanche-key-create): The key create command generates a new private key to use for creating and controlling +test Subnets. Keys generated by this command are NOT cryptographically secure enough to +use in production environments. DO NOT use these keys on Mainnet. + +The command works by generating a secp256 key and storing it with the provided keyName. You +can use this key in other commands by providing this keyName. + +If you'd like to import an existing key instead of generating one from scratch, provide the +--file flag. +- [`delete`](#avalanche-key-delete): The key delete command deletes an existing signing key. + +To delete a key, provide the keyName. The command prompts for confirmation +before deleting the key. To skip the confirmation, provide the --force flag. +- [`export`](#avalanche-key-export): The key export command exports a created signing key. You can use an exported key in other +applications or import it into another instance of Avalanche-CLI. + +By default, the tool writes the hex encoded key to stdout. If you provide the --output +flag, the command writes the key to a file of your choosing. +- [`list`](#avalanche-key-list): The key list command prints information for all stored signing +keys or for the ledger addresses associated to certain indices. +- [`transfer`](#avalanche-key-transfer): The key transfer command allows to transfer funds between stored keys or ledger addresses. + +**Flags:** + +```bash +-h, --help help for key +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### create + +The key create command generates a new private key to use for creating and controlling +test Subnets. Keys generated by this command are NOT cryptographically secure enough to +use in production environments. DO NOT use these keys on Mainnet. + +The command works by generating a secp256 key and storing it with the provided keyName. You +can use this key in other commands by providing this keyName. + +If you'd like to import an existing key instead of generating one from scratch, provide the +--file flag. + +**Usage:** +```bash +avalanche key create [subcommand] [flags] +``` + +**Flags:** + +```bash +--file string import the key from an existing key file +-f, --force overwrite an existing key with the same name +-h, --help help for create +--skip-balances do not query public network balances for an imported key +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### delete + +The key delete command deletes an existing signing key. + +To delete a key, provide the keyName. The command prompts for confirmation +before deleting the key. To skip the confirmation, provide the --force flag. + +**Usage:** +```bash +avalanche key delete [subcommand] [flags] +``` + +**Flags:** + +```bash +-f, --force delete the key without confirmation +-h, --help help for delete +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### export + +The key export command exports a created signing key. You can use an exported key in other +applications or import it into another instance of Avalanche-CLI. + +By default, the tool writes the hex encoded key to stdout. If you provide the --output +flag, the command writes the key to a file of your choosing. + +**Usage:** +```bash +avalanche key export [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for export +-o, --output string write the key to the provided file path +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### list + +The key list command prints information for all stored signing +keys or for the ledger addresses associated to certain indices. + +**Usage:** +```bash +avalanche key list [subcommand] [flags] +``` + +**Flags:** + +```bash +-a, --all-networks list all network addresses +--blockchains strings blockchains to show information about (p=p-chain, x=x-chain, c=c-chain, and blockchain names) (default p,x,c) +-c, --cchain list C-Chain addresses (default true) +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for list +--keys strings list addresses for the given keys +-g, --ledger uints list ledger addresses for the given indices (default []) +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--pchain list P-Chain addresses (default true) +--subnets strings subnets to show information about (p=p-chain, x=x-chain, c=c-chain, and blockchain names) (default p,x,c) +-t, --testnet fuji operate on testnet (alias to fuji) +--tokens strings provide balance information for the given token contract addresses (Evm only) (default [Native]) +--use-gwei use gwei for EVM balances +-n, --use-nano-avax use nano Avax for balances +--xchain list X-Chain addresses (default true) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### transfer + +The key transfer command allows to transfer funds between stored keys or ledger addresses. + +**Usage:** +```bash +avalanche key transfer [subcommand] [flags] +``` + +**Flags:** + +```bash +-o, --amount float amount to send or receive (AVAX or TOKEN units) +--c-chain-receiver receive at C-Chain +--c-chain-sender send from C-Chain +--cluster string operate on the given cluster +-a, --destination-addr string destination address +--destination-key string key associated to a destination address +--destination-subnet string subnet where the funds will be sent (token transferrer experimental) +--destination-transferrer-address string token transferrer address at the destination subnet (token transferrer experimental) +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for transfer +-k, --key string key associated to the sender or receiver address +-i, --ledger uint32 ledger index associated to the sender or receiver address (default 32768) +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--origin-subnet string subnet where the funds belong (token transferrer experimental) +--origin-transferrer-address string token transferrer address at the origin subnet (token transferrer experimental) +--p-chain-receiver receive at P-Chain +--p-chain-sender send from P-Chain +--receiver-blockchain string receive at the given CLI blockchain +--receiver-blockchain-id string receive at the given blockchain ID/Alias +--sender-blockchain string send from the given CLI blockchain +--sender-blockchain-id string send from the given blockchain ID/Alias +-t, --testnet fuji operate on testnet (alias to fuji) +--x-chain-receiver receive at X-Chain +--x-chain-sender send from X-Chain +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche network + +The network command suite provides a collection of tools for managing local Blockchain +deployments. + +When you deploy a Blockchain locally, it runs on a local, multi-node Avalanche network. The +blockchain deploy command starts this network in the background. This command suite allows you +to shutdown, restart, and clear that network. + +This network currently supports multiple, concurrently deployed Blockchains. + +**Usage:** +```bash +avalanche network [subcommand] [flags] +``` + +**Subcommands:** + +- [`clean`](#avalanche-network-clean): The network clean command shuts down your local, multi-node network. All deployed Subnets +shutdown and delete their state. You can restart the network by deploying a new Subnet +configuration. +- [`start`](#avalanche-network-start): The network start command starts a local, multi-node Avalanche network on your machine. + +By default, the command loads the default snapshot. If you provide the --snapshot-name +flag, the network loads that snapshot instead. The command fails if the local network is +already running. +- [`status`](#avalanche-network-status): The network status command prints whether or not a local Avalanche +network is running and some basic stats about the network. +- [`stop`](#avalanche-network-stop): The network stop command shuts down your local, multi-node network. + +All deployed Subnets shutdown gracefully and save their state. If you provide the +--snapshot-name flag, the network saves its state under this named snapshot. You can +reload this snapshot with network start --snapshot-name `snapshotName`. Otherwise, the +network saves to the default snapshot, overwriting any existing state. You can reload the +default snapshot with network start. + +**Flags:** + +```bash +-h, --help help for network +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### clean + +The network clean command shuts down your local, multi-node network. All deployed Subnets +shutdown and delete their state. You can restart the network by deploying a new Subnet +configuration. + +**Usage:** +```bash +avalanche network clean [subcommand] [flags] +``` + +**Flags:** + +```bash +--hard Also clean downloaded avalanchego and plugin binaries +-h, --help help for clean +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### start + +The network start command starts a local, multi-node Avalanche network on your machine. + +By default, the command loads the default snapshot. If you provide the --snapshot-name +flag, the network loads that snapshot instead. The command fails if the local network is +already running. + +**Usage:** +```bash +avalanche network start [subcommand] [flags] +``` + +**Flags:** + +```bash +--avalanchego-path string use this avalanchego binary path +--avalanchego-version string use this version of avalanchego (ex: v1.17.12) (default "latest-prerelease") +-h, --help help for start +--num-nodes uint32 number of nodes to be created on local network (default 2) +--relayer-path string use this relayer binary path +--relayer-version string use this relayer version (default "latest-prerelease") +--snapshot-name string name of snapshot to use to start the network from (default "default-1654102509") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### status + +The network status command prints whether or not a local Avalanche +network is running and some basic stats about the network. + +**Usage:** +```bash +avalanche network status [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for status +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### stop + +The network stop command shuts down your local, multi-node network. + +All deployed Subnets shutdown gracefully and save their state. If you provide the +--snapshot-name flag, the network saves its state under this named snapshot. You can +reload this snapshot with network start --snapshot-name `snapshotName`. Otherwise, the +network saves to the default snapshot, overwriting any existing state. You can reload the +default snapshot with network start. + +**Usage:** +```bash +avalanche network stop [subcommand] [flags] +``` + +**Flags:** + +```bash +--dont-save do not save snapshot, just stop the network +-h, --help help for stop +--snapshot-name string name of snapshot to use to save network state into (default "default-1654102509") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche node + +The node command suite provides a collection of tools for creating and maintaining +validators on Avalanche Network. + +To get started, use the node create command wizard to walk through the +configuration to make your node a primary validator on Avalanche public network. You can use the +rest of the commands to maintain your node and make your node a Subnet Validator. + +**Usage:** +```bash +avalanche node [subcommand] [flags] +``` + +**Subcommands:** + +- [`addDashboard`](#avalanche-node-adddashboard): (ALPHA Warning) This command is currently in experimental mode. + +The node addDashboard command adds custom dashboard to the Grafana monitoring dashboard for the +cluster. +- [`create`](#avalanche-node-create): (ALPHA Warning) This command is currently in experimental mode. + +The node create command sets up a validator on a cloud server of your choice. +The validator will be validating the Avalanche Primary Network and Subnet +of your choice. By default, the command runs an interactive wizard. It +walks you through all the steps you need to set up a validator. +Once this command is completed, you will have to wait for the validator +to finish bootstrapping on the primary network before running further +commands on it, e.g. validating a Subnet. You can check the bootstrapping +status by running avalanche node status + +The created node will be part of group of validators called `clusterName` +and users can call node commands with `clusterName` so that the command +will apply to all nodes in the cluster +- [`destroy`](#avalanche-node-destroy): (ALPHA Warning) This command is currently in experimental mode. + +The node destroy command terminates all running nodes in cloud server and deletes all storage disks. + +If there is a static IP address attached, it will be released. +- [`devnet`](#avalanche-node-devnet): (ALPHA Warning) This command is currently in experimental mode. + +The node devnet command suite provides a collection of commands related to devnets. +You can check the updated status by calling avalanche node status `clusterName` +- [`export`](#avalanche-node-export): (ALPHA Warning) This command is currently in experimental mode. + +The node export command exports cluster configuration and its nodes config to a text file. + +If no file is specified, the configuration is printed to the stdout. + +Use --include-secrets to include keys in the export. In this case please keep the file secure as it contains sensitive information. + +Exported cluster configuration without secrets can be imported by another user using node import command. +- [`import`](#avalanche-node-import): (ALPHA Warning) This command is currently in experimental mode. + +The node import command imports cluster configuration and its nodes configuration from a text file +created from the node export command. + +Prior to calling this command, call node whitelist command to have your SSH public key and IP whitelisted by +the cluster owner. This will enable you to use avalanche-cli commands to manage the imported cluster. + +Please note, that this imported cluster will be considered as EXTERNAL by avalanche-cli, so some commands +affecting cloud nodes like node create or node destroy will be not applicable to it. +- [`list`](#avalanche-node-list): (ALPHA Warning) This command is currently in experimental mode. + +The node list command lists all clusters together with their nodes. +- [`loadtest`](#avalanche-node-loadtest): (ALPHA Warning) This command is currently in experimental mode. + +The node loadtest command suite starts and stops a load test for an existing devnet cluster. +- [`local`](#avalanche-node-local): The node local command suite provides a collection of commands related to local nodes +- [`refresh-ips`](#avalanche-node-refresh-ips): (ALPHA Warning) This command is currently in experimental mode. + +The node refresh-ips command obtains the current IP for all nodes with dynamic IPs in the cluster, +and updates the local node information used by CLI commands. +- [`resize`](#avalanche-node-resize): (ALPHA Warning) This command is currently in experimental mode. + +The node resize command can change the amount of CPU, memory and disk space available for the cluster nodes. +- [`scp`](#avalanche-node-scp): (ALPHA Warning) This command is currently in experimental mode. + +The node scp command securely copies files to and from nodes. Remote source or destionation can be specified using the following format: +[clusterName|nodeID|instanceID|IP]:/path/to/file. Regular expressions are supported for the source files like /tmp/*.txt. +File transfer to the nodes are parallelized. IF source or destination is cluster, the other should be a local file path. +If both destinations are remote, they must be nodes for the same cluster and not clusters themselves. +For example: +$ avalanche node scp [cluster1|node1]:/tmp/file.txt /tmp/file.txt +$ avalanche node scp /tmp/file.txt [cluster1|NodeID-XXXX]:/tmp/file.txt +$ avalanche node scp node1:/tmp/file.txt NodeID-XXXX:/tmp/file.txt +- [`ssh`](#avalanche-node-ssh): (ALPHA Warning) This command is currently in experimental mode. + +The node ssh command execute a given command [cmd] using ssh on all nodes in the cluster if ClusterName is given. +If no command is given, just prints the ssh command to be used to connect to each node in the cluster. +For provided NodeID or InstanceID or IP, the command [cmd] will be executed on that node. +If no [cmd] is provided for the node, it will open ssh shell there. +- [`status`](#avalanche-node-status): (ALPHA Warning) This command is currently in experimental mode. + +The node status command gets the bootstrap status of all nodes in a cluster with the Primary Network. +If no cluster is given, defaults to node list behaviour. + +To get the bootstrap status of a node with a Blockchain, use --blockchain flag +- [`sync`](#avalanche-node-sync): (ALPHA Warning) This command is currently in experimental mode. + +The node sync command enables all nodes in a cluster to be bootstrapped to a Blockchain. +You can check the blockchain bootstrap status by calling avalanche node status `clusterName` --blockchain `blockchainName` +- [`update`](#avalanche-node-update): (ALPHA Warning) This command is currently in experimental mode. + +The node update command suite provides a collection of commands for nodes to update +their avalanchego or VM config. + +You can check the status after update by calling avalanche node status +- [`upgrade`](#avalanche-node-upgrade): (ALPHA Warning) This command is currently in experimental mode. + +The node update command suite provides a collection of commands for nodes to update +their avalanchego or VM version. + +You can check the status after upgrade by calling avalanche node status +- [`validate`](#avalanche-node-validate): (ALPHA Warning) This command is currently in experimental mode. + +The node validate command suite provides a collection of commands for nodes to join +the Primary Network and Subnets as validators. +If any of the commands is run before the nodes are bootstrapped on the Primary Network, the command +will fail. You can check the bootstrap status by calling avalanche node status `clusterName` +- [`whitelist`](#avalanche-node-whitelist): (ALPHA Warning) The whitelist command suite provides a collection of tools for granting access to the cluster. + + Command adds IP if --ip params provided to cloud security access rules allowing it to access all nodes in the cluster via ssh or http. + It also command adds SSH public key to all nodes in the cluster if --ssh params is there. + If no params provided it detects current user IP automaticaly and whitelists it + +**Flags:** + +```bash +-h, --help help for node +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### addDashboard + +(ALPHA Warning) This command is currently in experimental mode. + +The node addDashboard command adds custom dashboard to the Grafana monitoring dashboard for the +cluster. + +**Usage:** +```bash +avalanche node addDashboard [subcommand] [flags] +``` + +**Flags:** + +```bash +--add-grafana-dashboard string path to additional grafana dashboard json file +-h, --help help for addDashboard +--subnet string subnet that the dasbhoard is intended for (if any) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### create + +(ALPHA Warning) This command is currently in experimental mode. + +The node create command sets up a validator on a cloud server of your choice. +The validator will be validating the Avalanche Primary Network and Subnet +of your choice. By default, the command runs an interactive wizard. It +walks you through all the steps you need to set up a validator. +Once this command is completed, you will have to wait for the validator +to finish bootstrapping on the primary network before running further +commands on it, e.g. validating a Subnet. You can check the bootstrapping +status by running avalanche node status + +The created node will be part of group of validators called `clusterName` +and users can call node commands with `clusterName` so that the command +will apply to all nodes in the cluster + +**Usage:** +```bash +avalanche node create [subcommand] [flags] +``` + +**Flags:** + +```bash +--add-grafana-dashboard string path to additional grafana dashboard json file +--alternative-key-pair-name string key pair name to use if default one generates conflicts +--authorize-access authorize CLI to create cloud resources +--auto-replace-keypair automatically replaces key pair to access node if previous key pair is not found +--avalanchego-version-from-subnet string install latest avalanchego version, that is compatible with the given subnet, on node/s +--aws create node/s in AWS cloud +--aws-profile string aws profile to use (default "default") +--aws-volume-iops int AWS iops (for gp3, io1, and io2 volume types only) (default 3000) +--aws-volume-size int AWS volume size in GB (default 1000) +--aws-volume-throughput int AWS throughput in MiB/s (for gp3 volume type only) (default 125) +--aws-volume-type string AWS volume type (default "gp3") +--bootstrap-ids stringArray nodeIDs of bootstrap nodes +--bootstrap-ips stringArray IP:port pairs of bootstrap nodes +--cluster string operate on the given cluster +--custom-avalanchego-version string install given avalanchego version on node/s +--devnet operate on a devnet network +--enable-monitoring set up Prometheus monitoring for created nodes. This option creates a separate monitoring cloud instance and incures additional cost +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--gcp create node/s in GCP cloud +--gcp-credentials string use given GCP credentials +--gcp-project string use given GCP project +--genesis string path to genesis file +--grafana-pkg string use grafana pkg instead of apt repo(by default), for example https://dl.grafana.com/oss/release/grafana_10.4.1_amd64.deb +-h, --help help for create +--latest-avalanchego-pre-release-version install latest avalanchego pre-release version on node/s +--latest-avalanchego-version install latest avalanchego release version on node/s +-m, --mainnet operate on mainnet +--node-type string cloud instance type. Use 'default' to use recommended default instance type +--num-apis ints number of API nodes(nodes without stake) to create in the new Devnet +--num-validators ints number of nodes to create per region(s). Use comma to separate multiple numbers for each region in the same order as --region flag +--partial-sync primary network partial sync (default true) +--public-http-port allow public access to avalanchego HTTP port +--region strings create node(s) in given region(s). Use comma to separate multiple regions +--ssh-agent-identity string use given ssh identity(only for ssh agent). If not set, default will be used +-t, --testnet fuji operate on testnet (alias to fuji) +--upgrade string path to upgrade file +--use-ssh-agent use ssh agent(ex: Yubikey) for ssh auth +--use-static-ip attach static Public IP on cloud servers (default true) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### destroy + +(ALPHA Warning) This command is currently in experimental mode. + +The node destroy command terminates all running nodes in cloud server and deletes all storage disks. + +If there is a static IP address attached, it will be released. + +**Usage:** +```bash +avalanche node destroy [subcommand] [flags] +``` + +**Flags:** + +```bash +--all destroy all existing clusters created by Avalanche CLI +--authorize-access authorize CLI to release cloud resources +-y, --authorize-all authorize all CLI requests +--authorize-remove authorize CLI to remove all local files related to cloud nodes +--aws-profile string aws profile to use (default "default") +-h, --help help for destroy +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### devnet + +(ALPHA Warning) This command is currently in experimental mode. + +The node devnet command suite provides a collection of commands related to devnets. +You can check the updated status by calling avalanche node status `clusterName` + +**Usage:** +```bash +avalanche node devnet [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-node-devnet-deploy): (ALPHA Warning) This command is currently in experimental mode. + +The node devnet deploy command deploys a subnet into a devnet cluster, creating subnet and blockchain txs for it. +It saves the deploy info both locally and remotely. +- [`wiz`](#avalanche-node-devnet-wiz): (ALPHA Warning) This command is currently in experimental mode. + +The node wiz command creates a devnet and deploys, sync and validate a subnet into it. It creates the subnet if so needed. + +**Flags:** + +```bash +-h, --help help for devnet +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### devnet deploy + +(ALPHA Warning) This command is currently in experimental mode. + +The node devnet deploy command deploys a subnet into a devnet cluster, creating subnet and blockchain txs for it. +It saves the deploy info both locally and remotely. + +**Usage:** +```bash +avalanche node devnet deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for deploy +--no-checks do not check for healthy status or rpc compatibility of nodes against subnet +--subnet-aliases strings additional subnet aliases to be used for RPC calls in addition to subnet blockchain name +--subnet-only only create a subnet +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### devnet wiz + +(ALPHA Warning) This command is currently in experimental mode. + +The node wiz command creates a devnet and deploys, sync and validate a subnet into it. It creates the subnet if so needed. + +**Usage:** +```bash +avalanche node devnet wiz [subcommand] [flags] +``` + +**Flags:** + +```bash +--add-grafana-dashboard string path to additional grafana dashboard json file +--alternative-key-pair-name string key pair name to use if default one generates conflicts +--authorize-access authorize CLI to create cloud resources +--auto-replace-keypair automatically replaces key pair to access node if previous key pair is not found +--aws create node/s in AWS cloud +--aws-profile string aws profile to use (default "default") +--aws-volume-iops int AWS iops (for gp3, io1, and io2 volume types only) (default 3000) +--aws-volume-size int AWS volume size in GB (default 1000) +--aws-volume-throughput int AWS throughput in MiB/s (for gp3 volume type only) (default 125) +--aws-volume-type string AWS volume type (default "gp3") +--chain-config string path to the chain configuration for subnet +--custom-avalanchego-version string install given avalanchego version on node/s +--custom-subnet use a custom VM as the subnet virtual machine +--custom-vm-branch string custom vm branch or commit +--custom-vm-build-script string custom vm build-script +--custom-vm-repo-url string custom vm repository url +--default-validator-params use default weight/start/duration params for subnet validator +--deploy-icm-messenger deploy Interchain Messenger (default true) +--deploy-icm-registry deploy Interchain Registry (default true) +--deploy-teleporter-messenger deploy Interchain Messenger (default true) +--deploy-teleporter-registry deploy Interchain Registry (default true) +--enable-monitoring set up Prometheus monitoring for created nodes. Please note that this option creates a separate monitoring instance and incures additional cost +--evm-chain-id uint chain ID to use with Subnet-EVM +--evm-defaults use default production settings with Subnet-EVM +--evm-production-defaults use default production settings for your blockchain +--evm-subnet use Subnet-EVM as the subnet virtual machine +--evm-test-defaults use default test settings for your blockchain +--evm-token string token name to use with Subnet-EVM +--evm-version string version of Subnet-EVM to use +--force-subnet-create overwrite the existing subnet configuration if one exists +--gcp create node/s in GCP cloud +--gcp-credentials string use given GCP credentials +--gcp-project string use given GCP project +--grafana-pkg string use grafana pkg instead of apt repo(by default), for example https://dl.grafana.com/oss/release/grafana_10.4.1_amd64.deb +-h, --help help for wiz +--icm generate an icm-ready vm +--icm-messenger-contract-address-path string path to an icm messenger contract address file +--icm-messenger-deployer-address-path string path to an icm messenger deployer address file +--icm-messenger-deployer-tx-path string path to an icm messenger deployer tx file +--icm-registry-bytecode-path string path to an icm registry bytecode file +--icm-version string icm version to deploy (default "latest") +--latest-avalanchego-pre-release-version install latest avalanchego pre-release version on node/s +--latest-avalanchego-version install latest avalanchego release version on node/s +--latest-evm-version use latest Subnet-EVM released version +--latest-pre-released-evm-version use latest Subnet-EVM pre-released version +--node-config string path to avalanchego node configuration for subnet +--node-type string cloud instance type. Use 'default' to use recommended default instance type +--num-apis ints number of API nodes(nodes without stake) to create in the new Devnet +--num-validators ints number of nodes to create per region(s). Use comma to separate multiple numbers for each region in the same order as --region flag +--public-http-port allow public access to avalanchego HTTP port +--region strings create node/s in given region(s). Use comma to separate multiple regions +--relayer run AWM relayer when deploying the vm +--ssh-agent-identity string use given ssh identity(only for ssh agent). If not set, default will be used. +--subnet-aliases strings additional subnet aliases to be used for RPC calls in addition to subnet blockchain name +--subnet-config string path to the subnet configuration for subnet +--subnet-genesis string file path of the subnet genesis +--teleporter generate an icm-ready vm +--teleporter-messenger-contract-address-path string path to an icm messenger contract address file +--teleporter-messenger-deployer-address-path string path to an icm messenger deployer address file +--teleporter-messenger-deployer-tx-path string path to an icm messenger deployer tx file +--teleporter-registry-bytecode-path string path to an icm registry bytecode file +--teleporter-version string icm version to deploy (default "latest") +--use-ssh-agent use ssh agent for ssh +--use-static-ip attach static Public IP on cloud servers (default true) +--validators strings deploy subnet into given comma separated list of validators. defaults to all cluster nodes +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### export + +(ALPHA Warning) This command is currently in experimental mode. + +The node export command exports cluster configuration and its nodes config to a text file. + +If no file is specified, the configuration is printed to the stdout. + +Use --include-secrets to include keys in the export. In this case please keep the file secure as it contains sensitive information. + +Exported cluster configuration without secrets can be imported by another user using node import command. + +**Usage:** +```bash +avalanche node export [subcommand] [flags] +``` + +**Flags:** + +```bash +--file string specify the file to export the cluster configuration to +--force overwrite the file if it exists +-h, --help help for export +--include-secrets include keys in the export +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### import + +(ALPHA Warning) This command is currently in experimental mode. + +The node import command imports cluster configuration and its nodes configuration from a text file +created from the node export command. + +Prior to calling this command, call node whitelist command to have your SSH public key and IP whitelisted by +the cluster owner. This will enable you to use avalanche-cli commands to manage the imported cluster. + +Please note, that this imported cluster will be considered as EXTERNAL by avalanche-cli, so some commands +affecting cloud nodes like node create or node destroy will be not applicable to it. + +**Usage:** +```bash +avalanche node import [subcommand] [flags] +``` + +**Flags:** + +```bash +--file string specify the file to export the cluster configuration to +-h, --help help for import +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### list + +(ALPHA Warning) This command is currently in experimental mode. + +The node list command lists all clusters together with their nodes. + +**Usage:** +```bash +avalanche node list [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for list +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### loadtest + +(ALPHA Warning) This command is currently in experimental mode. + +The node loadtest command suite starts and stops a load test for an existing devnet cluster. + +**Usage:** +```bash +avalanche node loadtest [subcommand] [flags] +``` + +**Subcommands:** + +- [`start`](#avalanche-node-loadtest-start): (ALPHA Warning) This command is currently in experimental mode. + +The node loadtest command starts load testing for an existing devnet cluster. If the cluster does +not have an existing load test host, the command creates a separate cloud server and builds the load +test binary based on the provided load test Git Repo URL and load test binary build command. + +The command will then run the load test binary based on the provided load test run command. +- [`stop`](#avalanche-node-loadtest-stop): (ALPHA Warning) This command is currently in experimental mode. + +The node loadtest stop command stops load testing for an existing devnet cluster and terminates the +separate cloud server created to host the load test. + +**Flags:** + +```bash +-h, --help help for loadtest +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### loadtest start + +(ALPHA Warning) This command is currently in experimental mode. + +The node loadtest command starts load testing for an existing devnet cluster. If the cluster does +not have an existing load test host, the command creates a separate cloud server and builds the load +test binary based on the provided load test Git Repo URL and load test binary build command. + +The command will then run the load test binary based on the provided load test run command. + +**Usage:** +```bash +avalanche node loadtest start [subcommand] [flags] +``` + +**Flags:** + +```bash +--authorize-access authorize CLI to create cloud resources +--aws create loadtest node in AWS cloud +--aws-profile string aws profile to use (default "default") +--gcp create loadtest in GCP cloud +-h, --help help for start +--load-test-branch string load test branch or commit +--load-test-build-cmd string command to build load test binary +--load-test-cmd string command to run load test +--load-test-repo string load test repo url to use +--node-type string cloud instance type for loadtest script +--region string create load test node in a given region +--ssh-agent-identity string use given ssh identity(only for ssh agent). If not set, default will be used +--use-ssh-agent use ssh agent(ex: Yubikey) for ssh auth +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### loadtest stop + +(ALPHA Warning) This command is currently in experimental mode. + +The node loadtest stop command stops load testing for an existing devnet cluster and terminates the +separate cloud server created to host the load test. + +**Usage:** +```bash +avalanche node loadtest stop [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for stop +--load-test strings stop specified load test node(s). Use comma to separate multiple load test instance names +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### local + +The node local command suite provides a collection of commands related to local nodes + +**Usage:** +```bash +avalanche node local [subcommand] [flags] +``` + +**Subcommands:** + +- [`destroy`](#avalanche-node-local-destroy): Cleanup local node. +- [`start`](#avalanche-node-local-start): The node local start command creates Avalanche nodes on the local machine. +Once this command is completed, you will have to wait for the Avalanche node +to finish bootstrapping on the primary network before running further +commands on it, e.g. validating a Subnet. + +You can check the bootstrapping status by running avalanche node status local. +- [`status`](#avalanche-node-local-status): Get status of local node. +- [`stop`](#avalanche-node-local-stop): Stop local node. +- [`track`](#avalanche-node-local-track): Track specified blockchain with local node +- [`validate`](#avalanche-node-local-validate): Use Avalanche Node set up on local machine to set up specified L1 by providing the +RPC URL of the L1. + +This command can only be used to validate Proof of Stake L1. + +**Flags:** + +```bash +-h, --help help for local +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local destroy + +Cleanup local node. + +**Usage:** +```bash +avalanche node local destroy [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for destroy +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local start + +The node local start command creates Avalanche nodes on the local machine. +Once this command is completed, you will have to wait for the Avalanche node +to finish bootstrapping on the primary network before running further +commands on it, e.g. validating a Subnet. + +You can check the bootstrapping status by running avalanche node status local. + +**Usage:** +```bash +avalanche node local start [subcommand] [flags] +``` + +**Flags:** + +```bash +--avalanchego-path string use this avalanchego binary path +--bootstrap-id stringArray nodeIDs of bootstrap nodes +--bootstrap-ip stringArray IP:port pairs of bootstrap nodes +--cluster string operate on the given cluster +--custom-avalanchego-version string install given avalanchego version on node/s +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--genesis string path to genesis file +-h, --help help for start +--latest-avalanchego-pre-release-version install latest avalanchego pre-release version on node/s (default true) +--latest-avalanchego-version install latest avalanchego release version on node/s +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-config string path to common avalanchego config settings for all nodes +--num-nodes uint32 number of Avalanche nodes to create on local machine (default 1) +--partial-sync primary network partial sync (default true) +--staking-cert-key-path string path to provided staking cert key for node +--staking-signer-key-path string path to provided staking signer key for node +--staking-tls-key-path string path to provided staking tls key for node +-t, --testnet fuji operate on testnet (alias to fuji) +--upgrade string path to upgrade file +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local status + +Get status of local node. + +**Usage:** +```bash +avalanche node local status [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string specify the blockchain the node is syncing with +-h, --help help for status +--l1 string specify the blockchain the node is syncing with +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local stop + +Stop local node. + +**Usage:** +```bash +avalanche node local stop [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for stop +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local track + +Track specified blockchain with local node + +**Usage:** +```bash +avalanche node local track [subcommand] [flags] +``` + +**Flags:** + +```bash +--avalanchego-path string use this avalanchego binary path +--custom-avalanchego-version string install given avalanchego version on node/s +-h, --help help for track +--latest-avalanchego-pre-release-version install latest avalanchego pre-release version on node/s (default true) +--latest-avalanchego-version install latest avalanchego release version on node/s +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### local validate + +Use Avalanche Node set up on local machine to set up specified L1 by providing the +RPC URL of the L1. + +This command can only be used to validate Proof of Stake L1. + +**Usage:** +```bash +avalanche node local validate [subcommand] [flags] +``` + +**Flags:** + +```bash +--aggregator-log-level string log level to use with signature aggregator (default "Debug") +--aggregator-log-to-stdout use stdout for signature aggregator logs +--balance float amount of AVAX to increase validator's balance by +--blockchain string specify the blockchain the node is syncing with +--delegation-fee uint16 delegation fee (in bips) (default 100) +--disable-owner string P-Chain address that will able to disable the validator with a P-Chain transaction +-h, --help help for validate +--l1 string specify the blockchain the node is syncing with +--minimum-stake-duration uint minimum stake duration (in seconds) (default 100) +--remaining-balance-owner string P-Chain address that will receive any leftover AVAX from the validator when it is removed from Subnet +--rpc string connect to validator manager at the given rpc endpoint +--stake-amount uint amount of tokens to stake +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### refresh-ips + +(ALPHA Warning) This command is currently in experimental mode. + +The node refresh-ips command obtains the current IP for all nodes with dynamic IPs in the cluster, +and updates the local node information used by CLI commands. + +**Usage:** +```bash +avalanche node refresh-ips [subcommand] [flags] +``` + +**Flags:** + +```bash +--aws-profile string aws profile to use (default "default") +-h, --help help for refresh-ips +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### resize + +(ALPHA Warning) This command is currently in experimental mode. + +The node resize command can change the amount of CPU, memory and disk space available for the cluster nodes. + +**Usage:** +```bash +avalanche node resize [subcommand] [flags] +``` + +**Flags:** + +```bash +--aws-profile string aws profile to use (default "default") +--disk-size string Disk size to resize in Gb (e.g. 1000Gb) +-h, --help help for resize +--node-type string Node type to resize (e.g. t3.2xlarge) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### scp + +(ALPHA Warning) This command is currently in experimental mode. + +The node scp command securely copies files to and from nodes. Remote source or destionation can be specified using the following format: +[clusterName|nodeID|instanceID|IP]:/path/to/file. Regular expressions are supported for the source files like /tmp/*.txt. +File transfer to the nodes are parallelized. IF source or destination is cluster, the other should be a local file path. +If both destinations are remote, they must be nodes for the same cluster and not clusters themselves. +For example: +$ avalanche node scp [cluster1|node1]:/tmp/file.txt /tmp/file.txt +$ avalanche node scp /tmp/file.txt [cluster1|NodeID-XXXX]:/tmp/file.txt +$ avalanche node scp node1:/tmp/file.txt NodeID-XXXX:/tmp/file.txt + +**Usage:** +```bash +avalanche node scp [subcommand] [flags] +``` + +**Flags:** + +```bash +--compress use compression for ssh +-h, --help help for scp +--recursive copy directories recursively +--with-loadtest include loadtest node for scp cluster operations +--with-monitor include monitoring node for scp cluster operations +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### ssh + +(ALPHA Warning) This command is currently in experimental mode. + +The node ssh command execute a given command [cmd] using ssh on all nodes in the cluster if ClusterName is given. +If no command is given, just prints the ssh command to be used to connect to each node in the cluster. +For provided NodeID or InstanceID or IP, the command [cmd] will be executed on that node. +If no [cmd] is provided for the node, it will open ssh shell there. + +**Usage:** +```bash +avalanche node ssh [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for ssh +--parallel run ssh command on all nodes in parallel +--with-loadtest include loadtest node for ssh cluster operations +--with-monitor include monitoring node for ssh cluster operations +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### status + +(ALPHA Warning) This command is currently in experimental mode. + +The node status command gets the bootstrap status of all nodes in a cluster with the Primary Network. +If no cluster is given, defaults to node list behaviour. + +To get the bootstrap status of a node with a Blockchain, use --blockchain flag + +**Usage:** +```bash +avalanche node status [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string specify the blockchain the node is syncing with +-h, --help help for status +--subnet string specify the blockchain the node is syncing with +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### sync + +(ALPHA Warning) This command is currently in experimental mode. + +The node sync command enables all nodes in a cluster to be bootstrapped to a Blockchain. +You can check the blockchain bootstrap status by calling avalanche node status `clusterName` --blockchain `blockchainName` + +**Usage:** +```bash +avalanche node sync [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for sync +--no-checks do not check for bootstrapped/healthy status or rpc compatibility of nodes against subnet +--subnet-aliases strings subnet alias to be used for RPC calls. defaults to subnet blockchain ID +--validators strings sync subnet into given comma separated list of validators. defaults to all cluster nodes +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### update + +(ALPHA Warning) This command is currently in experimental mode. + +The node update command suite provides a collection of commands for nodes to update +their avalanchego or VM config. + +You can check the status after update by calling avalanche node status + +**Usage:** +```bash +avalanche node update [subcommand] [flags] +``` + +**Subcommands:** + +- [`subnet`](#avalanche-node-update-subnet): (ALPHA Warning) This command is currently in experimental mode. + +The node update subnet command updates all nodes in a cluster with latest Subnet configuration and VM for custom VM. +You can check the updated subnet bootstrap status by calling avalanche node status `clusterName` --subnet `subnetName` + +**Flags:** + +```bash +-h, --help help for update +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### update subnet + +(ALPHA Warning) This command is currently in experimental mode. + +The node update subnet command updates all nodes in a cluster with latest Subnet configuration and VM for custom VM. +You can check the updated subnet bootstrap status by calling avalanche node status `clusterName` --subnet `subnetName` + +**Usage:** +```bash +avalanche node update subnet [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for subnet +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### upgrade + +(ALPHA Warning) This command is currently in experimental mode. + +The node update command suite provides a collection of commands for nodes to update +their avalanchego or VM version. + +You can check the status after upgrade by calling avalanche node status + +**Usage:** +```bash +avalanche node upgrade [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for upgrade +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### validate + +(ALPHA Warning) This command is currently in experimental mode. + +The node validate command suite provides a collection of commands for nodes to join +the Primary Network and Subnets as validators. +If any of the commands is run before the nodes are bootstrapped on the Primary Network, the command +will fail. You can check the bootstrap status by calling avalanche node status `clusterName` + +**Usage:** +```bash +avalanche node validate [subcommand] [flags] +``` + +**Subcommands:** + +- [`primary`](#avalanche-node-validate-primary): (ALPHA Warning) This command is currently in experimental mode. + +The node validate primary command enables all nodes in a cluster to be validators of Primary +Network. +- [`subnet`](#avalanche-node-validate-subnet): (ALPHA Warning) This command is currently in experimental mode. + +The node validate subnet command enables all nodes in a cluster to be validators of a Subnet. +If the command is run before the nodes are Primary Network validators, the command will first +make the nodes Primary Network validators before making them Subnet validators. +If The command is run before the nodes are bootstrapped on the Primary Network, the command will fail. +You can check the bootstrap status by calling avalanche node status `clusterName` +If The command is run before the nodes are synced to the subnet, the command will fail. +You can check the subnet sync status by calling avalanche node status `clusterName` --subnet `subnetName` + +**Flags:** + +```bash +-h, --help help for validate +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### validate primary + +(ALPHA Warning) This command is currently in experimental mode. + +The node validate primary command enables all nodes in a cluster to be validators of Primary +Network. + +**Usage:** +```bash +avalanche node validate primary [subcommand] [flags] +``` + +**Flags:** + +```bash +-e, --ewoq use ewoq key [fuji/devnet only] +-h, --help help for primary +-k, --key string select the key to use [fuji only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +--stake-amount uint how many AVAX to stake in the validator +--staking-period duration how long validator validates for after start time +--start-time string UTC start time when this validator starts validating, in 'YYYY-MM-DD HH:MM:SS' format +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +#### validate subnet + +(ALPHA Warning) This command is currently in experimental mode. + +The node validate subnet command enables all nodes in a cluster to be validators of a Subnet. +If the command is run before the nodes are Primary Network validators, the command will first +make the nodes Primary Network validators before making them Subnet validators. +If The command is run before the nodes are bootstrapped on the Primary Network, the command will fail. +You can check the bootstrap status by calling avalanche node status `clusterName` +If The command is run before the nodes are synced to the subnet, the command will fail. +You can check the subnet sync status by calling avalanche node status `clusterName` --subnet `subnetName` + +**Usage:** +```bash +avalanche node validate subnet [subcommand] [flags] +``` + +**Flags:** + +```bash +--default-validator-params use default weight/start/duration params for subnet validator +-e, --ewoq use ewoq key [fuji/devnet only] +-h, --help help for subnet +-k, --key string select the key to use [fuji/devnet only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji/devnet) +--ledger-addrs strings use the given ledger addresses +--no-checks do not check for bootstrapped status or healthy status +--no-validation-checks do not check if subnet is already synced or validated (default true) +--stake-amount uint how many AVAX to stake in the validator +--staking-period duration how long validator validates for after start time +--start-time string UTC start time when this validator starts validating, in 'YYYY-MM-DD HH:MM:SS' format +--validators strings validate subnet for the given comma separated list of validators. defaults to all cluster nodes +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### whitelist + +(ALPHA Warning) The whitelist command suite provides a collection of tools for granting access to the cluster. + + Command adds IP if --ip params provided to cloud security access rules allowing it to access all nodes in the cluster via ssh or http. + It also command adds SSH public key to all nodes in the cluster if --ssh params is there. + If no params provided it detects current user IP automaticaly and whitelists it + +**Usage:** +```bash +avalanche node whitelist [subcommand] [flags] +``` + +**Flags:** + +```bash +-y, --current-ip whitelist current host ip +-h, --help help for whitelist +--ip string ip address to whitelist +--ssh string ssh public key to whitelist +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche primary + +The primary command suite provides a collection of tools for interacting with the +Primary Network + +**Usage:** +```bash +avalanche primary [subcommand] [flags] +``` + +**Subcommands:** + +- [`addValidator`](#avalanche-primary-addvalidator): The primary addValidator command adds a node as a validator +in the Primary Network +- [`describe`](#avalanche-primary-describe): The subnet describe command prints details of the primary network configuration to the console. + +**Flags:** + +```bash +-h, --help help for primary +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### addValidator + +The primary addValidator command adds a node as a validator +in the Primary Network + +**Usage:** +```bash +avalanche primary addValidator [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--delegation-fee uint32 set the delegation fee (20 000 is equivalent to 2%) +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for addValidator +-k, --key string select the key to use [fuji only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji) +--ledger-addrs strings use the given ledger addresses +-m, --mainnet operate on mainnet +--nodeID string set the NodeID of the validator to add +--proof-of-possession string set the BLS proof of possession of the validator to add +--public-key string set the BLS public key of the validator to add +--staking-period duration how long this validator will be staking +--start-time string UTC start time when this validator starts validating, in 'YYYY-MM-DD HH:MM:SS' format +-t, --testnet fuji operate on testnet (alias to fuji) +--weight uint set the staking weight of the validator to add +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### describe + +The subnet describe command prints details of the primary network configuration to the console. + +**Usage:** +```bash +avalanche primary describe [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +-h, --help help for describe +-l, --local operate on a local network +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche teleporter + +The messenger command suite provides a collection of tools for interacting +with ICM messenger contracts. + +**Usage:** +```bash +avalanche teleporter [subcommand] [flags] +``` + +**Subcommands:** + +- [`deploy`](#avalanche-teleporter-deploy): Deploys ICM Messenger and Registry into a given L1. +- [`sendMsg`](#avalanche-teleporter-sendmsg): Sends and wait reception for a ICM msg between two blockchains. + +**Flags:** + +```bash +-h, --help help for teleporter +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### deploy + +Deploys ICM Messenger and Registry into a given L1. + +**Usage:** +```bash +avalanche teleporter deploy [subcommand] [flags] +``` + +**Flags:** + +```bash +--blockchain string deploy ICM into the given CLI blockchain +--blockchain-id string deploy ICM into the given blockchain ID/Alias +--c-chain deploy ICM into C-Chain +--cchain-key string key to be used to pay fees to deploy ICM to C-Chain +--cluster string operate on the given cluster +--deploy-messenger deploy ICM Messenger (default true) +--deploy-registry deploy ICM Registry (default true) +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +--force-registry-deploy deploy ICM Registry even if Messenger has already been deployed +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key to fund ICM deploy +-h, --help help for deploy +--include-cchain deploy ICM also to C-Chain +--key string CLI stored key to use to fund ICM deploy +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--messenger-contract-address-path string path to a messenger contract address file +--messenger-deployer-address-path string path to a messenger deployer address file +--messenger-deployer-tx-path string path to a messenger deployer tx file +--private-key string private key to use to fund ICM deploy +--registry-bytecode-path string path to a registry bytecode file +--rpc-url string use the given RPC URL to connect to the subnet +-t, --testnet fuji operate on testnet (alias to fuji) +--version string version to deploy (default "latest") +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### sendMsg + +Sends and wait reception for a ICM msg between two blockchains. + +**Usage:** +```bash +avalanche teleporter sendMsg [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--dest-rpc string use the given destination blockchain rpc endpoint +--destination-address string deliver the message to the given contract destination address +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +--genesis-key use genesis allocated key as message originator and to pay source blockchain fees +-h, --help help for sendMsg +--hex-encoded given message is hex encoded +--key string CLI stored key to use as message originator and to pay source blockchain fees +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--private-key string private key to use as message originator and to pay source blockchain fees +--source-rpc string use the given source blockchain rpc endpoint +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche transaction + +The transaction command suite provides all of the utilities required to sign multisig transactions. + +**Usage:** +```bash +avalanche transaction [subcommand] [flags] +``` + +**Subcommands:** + +- [`commit`](#avalanche-transaction-commit): The transaction commit command commits a transaction by submitting it to the P-Chain. +- [`sign`](#avalanche-transaction-sign): The transaction sign command signs a multisig transaction. + +**Flags:** + +```bash +-h, --help help for transaction +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### commit + +The transaction commit command commits a transaction by submitting it to the P-Chain. + +**Usage:** +```bash +avalanche transaction commit [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for commit +--input-tx-filepath string Path to the transaction signed by all signatories +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### sign + +The transaction sign command signs a multisig transaction. + +**Usage:** +```bash +avalanche transaction sign [subcommand] [flags] +``` + +**Flags:** + +```bash +-h, --help help for sign +--input-tx-filepath string Path to the transaction file for signing +-k, --key string select the key to use [fuji only] +-g, --ledger use ledger instead of key (always true on mainnet, defaults to false on fuji) +--ledger-addrs strings use the given ledger addresses +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche update + +Check if an update is available, and prompt the user to install it + +**Usage:** +```bash +avalanche update [subcommand] [flags] +``` + +**Flags:** + +```bash +-c, --confirm Assume yes for installation +-h, --help help for update +-v, --version version for update +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +## avalanche validator + +The validator command suite provides a collection of tools for managing validator +balance on P-Chain. + +Validator's balance is used to pay for continuous fee to the P-Chain. When this Balance reaches 0, +the validator will be considered inactive and will no longer participate in validating the L1 + +**Usage:** +```bash +avalanche validator [subcommand] [flags] +``` + +**Subcommands:** + +- [`getBalance`](#avalanche-validator-getbalance): This command gets the remaining validator P-Chain balance that is available to pay +P-Chain continuous fee +- [`increaseBalance`](#avalanche-validator-increasebalance): This command increases the validator P-Chain balance +- [`list`](#avalanche-validator-list): This command gets a list of the validators of the L1 + +**Flags:** + +```bash +-h, --help help for validator +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### getBalance + +This command gets the remaining validator P-Chain balance that is available to pay +P-Chain continuous fee + +**Usage:** +```bash +avalanche validator getBalance [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for getBalance +--l1 string name of L1 +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-id string node ID of the validator +-t, --testnet fuji operate on testnet (alias to fuji) +--validation-id string validation ID of the validator +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### increaseBalance + +This command increases the validator P-Chain balance + +**Usage:** +```bash +avalanche validator increaseBalance [subcommand] [flags] +``` + +**Flags:** + +```bash +--balance float amount of AVAX to increase validator's balance by +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for increaseBalance +-k, --key string select the key to use [fuji/devnet deploy only] +--l1 string name of L1 (to increase balance of bootstrap validators only) +-l, --local operate on a local network +-m, --mainnet operate on mainnet +--node-id string node ID of the validator +-t, --testnet fuji operate on testnet (alias to fuji) +--validation-id string validationIDStr of the validator +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + + +### list + +This command gets a list of the validators of the L1 + +**Usage:** +```bash +avalanche validator list [subcommand] [flags] +``` + +**Flags:** + +```bash +--cluster string operate on the given cluster +--devnet operate on a devnet network +--endpoint string use the given endpoint for network operations +-f, --fuji testnet operate on fuji (alias to testnet +-h, --help help for list +-l, --local operate on a local network +-m, --mainnet operate on mainnet +-t, --testnet fuji operate on testnet (alias to fuji) +--config string config file (default is $HOME/.avalanche-cli/config.json) +--log-level string log level for the application (default "ERROR") +--skip-update-check skip check for new versions +``` + diff --git a/cmd/contractcmd/deploy_erc20.go b/cmd/contractcmd/deploy_erc20.go index 704cab7c7..d4a357c06 100644 --- a/cmd/contractcmd/deploy_erc20.go +++ b/cmd/contractcmd/deploy_erc20.go @@ -26,14 +26,7 @@ type DeployERC20Flags struct { rpcEndpoint string } -var ( - deployERC20SupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - } - deployERC20Flags DeployERC20Flags -) +var deployERC20Flags DeployERC20Flags // avalanche contract deploy erc20 func newDeployERC20Cmd() *cobra.Command { @@ -44,7 +37,7 @@ func newDeployERC20Cmd() *cobra.Command { RunE: deployERC20, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &deployERC20Flags.Network, true, deployERC20SupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &deployERC20Flags.Network, true, networkoptions.DefaultSupportedNetworkOptions) deployERC20Flags.PrivateKeyFlags.AddToCmd(cmd, "as contract deployer") // enabling blockchain names, C-Chain and blockchain IDs deployERC20Flags.chainFlags.SetEnabled(true, true, false, false, true) @@ -63,7 +56,7 @@ func deployERC20(_ *cobra.Command, _ []string) error { deployERC20Flags.Network, true, false, - deployERC20SupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/contractcmd/init_validator_manager.go b/cmd/contractcmd/init_validator_manager.go index d56bcbd49..ec6a9a009 100644 --- a/cmd/contractcmd/init_validator_manager.go +++ b/cmd/contractcmd/init_validator_manager.go @@ -6,12 +6,16 @@ import ( "fmt" "math/big" + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + "github.com/ava-labs/avalanche-cli/cmd/blockchaincmd" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/contract" "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/prompts" + "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/validatormanager" blockchainSDK "github.com/ava-labs/avalanche-cli/sdk/blockchain" @@ -27,6 +31,7 @@ type ValidatorManagerFlags struct { PrivateKeyFlags contract.PrivateKeyFlags rpcEndpoint string aggregatorLogLevel string + aggregatorLogToStdout bool aggregatorExtraEndpoints []string aggregatorAllowPrivatePeers bool } @@ -42,12 +47,6 @@ type POSManagerSpecFlags struct { } var ( - validatorManagerSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, - } validatorManagerFlags ValidatorManagerFlags initPOSManagerFlags POSManagerSpecFlags ) @@ -61,17 +60,18 @@ func newInitValidatorManagerCmd() *cobra.Command { RunE: initValidatorManager, Args: cobrautils.ExactArgs(1), } - networkoptions.AddNetworkFlagsToCmd(cmd, &validatorManagerFlags.Network, true, validatorManagerSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &validatorManagerFlags.Network, true, networkoptions.DefaultSupportedNetworkOptions) validatorManagerFlags.PrivateKeyFlags.AddToCmd(cmd, "as contract deployer") cmd.Flags().StringVar(&validatorManagerFlags.rpcEndpoint, "rpc", "", "deploy the contract into the given rpc endpoint") cmd.Flags().StringSliceVar(&validatorManagerFlags.aggregatorExtraEndpoints, "aggregator-extra-endpoints", nil, "endpoints for extra nodes that are needed in signature aggregation") cmd.Flags().BoolVar(&validatorManagerFlags.aggregatorAllowPrivatePeers, "aggregator-allow-private-peers", true, "allow the signature aggregator to connect to peers with private IP") - cmd.Flags().StringVar(&validatorManagerFlags.aggregatorLogLevel, "aggregator-log-level", "Off", "log level to use with signature aggregator") + cmd.Flags().StringVar(&validatorManagerFlags.aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator") + cmd.Flags().BoolVar(&validatorManagerFlags.aggregatorLogToStdout, "aggregator-log-to-stdout", false, "dump signature aggregator logs to stdout") cmd.Flags().StringVar(&initPOSManagerFlags.rewardCalculatorAddress, "pos-reward-calculator-address", "", "(PoS only) initialize the ValidatorManager with reward calculator address") cmd.Flags().Uint64Var(&initPOSManagerFlags.minimumStakeAmount, "pos-minimum-stake-amount", 1, "(PoS only) minimum stake amount") cmd.Flags().Uint64Var(&initPOSManagerFlags.maximumStakeAmount, "pos-maximum-stake-amount", 1000, "(PoS only) maximum stake amount") - cmd.Flags().Uint64Var(&initPOSManagerFlags.minimumStakeDuration, "pos-minimum-stake-duration", 100, "(PoS only) minimum stake duration") + cmd.Flags().Uint64Var(&initPOSManagerFlags.minimumStakeDuration, "pos-minimum-stake-duration", constants.PoSL1MinimumStakeDurationSeconds, "(PoS only) minimum stake duration (in seconds)") cmd.Flags().Uint16Var(&initPOSManagerFlags.minimumDelegationFee, "pos-minimum-delegation-fee", 1, "(PoS only) minimum delegation fee") cmd.Flags().Uint8Var(&initPOSManagerFlags.maximumStakeMultiplier, "pos-maximum-stake-multiplier", 1, "(PoS only )maximum stake multiplier") cmd.Flags().Uint64Var(&initPOSManagerFlags.weightToValueFactor, "pos-weight-to-value-factor", 1, "(PoS only) weight to value factor") @@ -89,7 +89,7 @@ func initValidatorManager(_ *cobra.Command, args []string) error { validatorManagerFlags.Network, true, false, - validatorManagerSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -150,7 +150,18 @@ func initValidatorManager(_ *cobra.Command, args []string) error { return err } clusterName := scNetwork.ClusterName - extraAggregatorPeers, err := blockchaincmd.GetAggregatorExtraPeers(clusterName, validatorManagerFlags.aggregatorExtraEndpoints) + extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterName, validatorManagerFlags.aggregatorExtraEndpoints) + if err != nil { + return err + } + aggregatorLogger, err := utils.NewLogger( + constants.SignatureAggregatorLogName, + validatorManagerFlags.aggregatorLogLevel, + constants.DefaultAggregatorLogLevel, + app.GetAggregatorLogDir(clusterName), + validatorManagerFlags.aggregatorLogToStdout, + ux.Logger.PrintToUser, + ) if err != nil { return err } @@ -187,7 +198,7 @@ func initValidatorManager(_ *cobra.Command, args []string) error { privateKey, extraAggregatorPeers, validatorManagerFlags.aggregatorAllowPrivatePeers, - validatorManagerFlags.aggregatorLogLevel, + aggregatorLogger, ); err != nil { return err } @@ -203,7 +214,7 @@ func initValidatorManager(_ *cobra.Command, args []string) error { privateKey, extraAggregatorPeers, validatorManagerFlags.aggregatorAllowPrivatePeers, - validatorManagerFlags.aggregatorLogLevel, + aggregatorLogger, validatorManagerSDK.PoSParams{ MinimumStakeAmount: big.NewInt(int64(initPOSManagerFlags.minimumStakeAmount)), MaximumStakeAmount: big.NewInt(int64(initPOSManagerFlags.maximumStakeAmount)), diff --git a/cmd/interchaincmd/messengercmd/deploy.go b/cmd/interchaincmd/messengercmd/deploy.go index cb294c631..f958ac7e9 100644 --- a/cmd/interchaincmd/messengercmd/deploy.go +++ b/cmd/interchaincmd/messengercmd/deploy.go @@ -42,14 +42,7 @@ const ( cChainName = "c-chain" ) -var ( - deploySupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - } - deployFlags DeployFlags -) +var deployFlags DeployFlags // avalanche interchain messenger deploy func NewDeployCmd() *cobra.Command { @@ -60,7 +53,7 @@ func NewDeployCmd() *cobra.Command { RunE: deploy, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, deploySupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, networkoptions.DefaultSupportedNetworkOptions) deployFlags.PrivateKeyFlags.AddToCmd(cmd, "to fund ICM deploy") deployFlags.ChainFlags.SetEnabled(true, true, false, false, true) deployFlags.ChainFlags.AddToCmd(cmd, "deploy ICM into %s") @@ -91,7 +84,7 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { flags.Network, true, false, - deploySupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/interchaincmd/messengercmd/send_msg.go b/cmd/interchaincmd/messengercmd/send_msg.go index 686cf6924..e148649b4 100644 --- a/cmd/interchaincmd/messengercmd/send_msg.go +++ b/cmd/interchaincmd/messengercmd/send_msg.go @@ -29,25 +29,18 @@ type MsgFlags struct { DestRPCEndpoint string } -var ( - msgSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - } - msgFlags MsgFlags -) +var msgFlags MsgFlags // avalanche interchain messenger sendMsg func NewSendMsgCmd() *cobra.Command { cmd := &cobra.Command{ Use: "sendMsg [sourceBlockchainName] [destinationBlockchainName] [messageContent]", - Short: "Verifies exchange of ICM message between two subnets", - Long: `Sends and wait reception for a ICM msg between two subnets.`, + Short: "Verifies exchange of ICM message between two blockchains", + Long: `Sends and wait reception for a ICM msg between two blockchains.`, RunE: sendMsg, Args: cobrautils.ExactArgs(3), } - networkoptions.AddNetworkFlagsToCmd(cmd, &msgFlags.Network, true, msgSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &msgFlags.Network, true, networkoptions.DefaultSupportedNetworkOptions) msgFlags.PrivateKeyFlags.AddToCmd(cmd, "as message originator and to pay source blockchain fees") cmd.Flags().BoolVar(&msgFlags.HexEncodedMessage, "hex-encoded", false, "given message is hex encoded") cmd.Flags().StringVar(&msgFlags.DestinationAddress, "destination-address", "", "deliver the message to the given contract destination address") @@ -67,7 +60,7 @@ func sendMsg(_ *cobra.Command, args []string) error { msgFlags.Network, true, false, - msgSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -149,7 +142,7 @@ func sendMsg(_ *cobra.Command, args []string) error { } if sourceMessengerAddress != destMessengerAddress { - return fmt.Errorf("different ICM messenger addresses among subnets: %s vs %s", sourceMessengerAddress, destMessengerAddress) + return fmt.Errorf("different ICM messenger addresses among blockchains: %s vs %s", sourceMessengerAddress, destMessengerAddress) } encodedMessage := []byte(message) @@ -164,7 +157,7 @@ func sendMsg(_ *cobra.Command, args []string) error { destAddr = common.HexToAddress(msgFlags.DestinationAddress) } // send tx to the ICM contract at the source - ux.Logger.PrintToUser("Delivering message %q from source subnet %q (%s)", message, sourceBlockchainName, sourceBlockchainID) + ux.Logger.PrintToUser("Delivering message %q from source blockchain %q (%s)", message, sourceBlockchainName, sourceBlockchainID) tx, receipt, err := interchain.SendCrossChainMessage( sourceRPCEndpoint, common.HexToAddress(sourceMessengerAddress), @@ -204,7 +197,7 @@ func sendMsg(_ *cobra.Command, args []string) error { } // receive and process head from destination - ux.Logger.PrintToUser("Waiting for message to be delivered to destination subnet %q (%s)", destBlockchainName, destBlockchainID) + ux.Logger.PrintToUser("Waiting for message to be delivered to destination blockchain %q (%s)", destBlockchainName, destBlockchainID) arrivalCheckInterval := 100 * time.Millisecond arrivalCheckTimeout := 10 * time.Second diff --git a/cmd/interchaincmd/relayercmd/deploy.go b/cmd/interchaincmd/relayercmd/deploy.go index 8131a860e..2b7465814 100644 --- a/cmd/interchaincmd/relayercmd/deploy.go +++ b/cmd/interchaincmd/relayercmd/deploy.go @@ -21,7 +21,6 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/vm" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ethereum/go-ethereum/crypto" "github.com/spf13/cobra" ) @@ -34,22 +33,19 @@ type DeployFlags struct { BlockchainsToRelay []string Key string Amount float64 + CChainAmount float64 BlockchainFundingKey string CChainFundingKey string BinPath string AllowPrivateIPs bool } -var ( - deploySupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - } - deployFlags DeployFlags -) +var deployFlags DeployFlags -const disableDeployToRemotePrompt = true +const ( + disableDeployToRemotePrompt = true + aproxFundingFee = 0.01 +) // avalanche interchain relayer deploy func newDeployCmd() *cobra.Command { @@ -60,7 +56,7 @@ func newDeployCmd() *cobra.Command { RunE: deploy, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, deploySupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, networkoptions.NonMainnetSupportedNetworkOptions) cmd.Flags().StringVar(&deployFlags.BinPath, "bin-path", "", "use the given relayer binary") cmd.Flags().StringVar( &deployFlags.Version, @@ -72,7 +68,8 @@ func newDeployCmd() *cobra.Command { cmd.Flags().StringSliceVar(&deployFlags.BlockchainsToRelay, "blockchains", nil, "blockchains to relay as source and destination") cmd.Flags().BoolVar(&deployFlags.RelayCChain, "cchain", false, "relay C-Chain as source and destination") cmd.Flags().StringVar(&deployFlags.Key, "key", "", "key to be used by default both for rewards and to pay fees") - cmd.Flags().Float64Var(&deployFlags.Amount, "amount", 0, "automatically fund fee payments with the given amount") + cmd.Flags().Float64Var(&deployFlags.Amount, "amount", 0, "automatically fund l1s fee payments with the given amount") + cmd.Flags().Float64Var(&deployFlags.CChainAmount, "cchain-amount", 0, "automatically fund cchain fee payments with the given amount") cmd.Flags().StringVar(&deployFlags.BlockchainFundingKey, "blockchain-funding-key", "", "key to be used to fund relayer account on all l1s") cmd.Flags().StringVar(&deployFlags.CChainFundingKey, "cchain-funding-key", "", "key to be used to fund relayer account on cchain") cmd.Flags().BoolVar(&deployFlags.AllowPrivateIPs, "allow-private-ips", true, "allow relayer to connec to private ips") @@ -92,7 +89,7 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { flags.Network, true, false, - deploySupportedNetworkOptions, + networkoptions.NonMainnetSupportedNetworkOptions, "", ) if err != nil { @@ -231,11 +228,10 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { // from the blockchain id (as relayer logs cmd) ux.Logger.PrintToUser("") for _, destination := range configSpec.destinations { - pk, err := crypto.HexToECDSA(destination.privateKey) + addr, err := utils.PrivateKeyToAddress(destination.privateKey) if err != nil { return err } - addr := crypto.PubkeyToAddress(pk.PublicKey) client, err := evm.GetClient(destination.rpcEndpoint) if err != nil { return err @@ -278,26 +274,39 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { if fundBlockchains { for _, destination := range configSpec.destinations { - pk, err := crypto.HexToECDSA(destination.privateKey) + addr, err := utils.PrivateKeyToAddress(destination.privateKey) if err != nil { return err } - addr := crypto.PubkeyToAddress(pk.PublicKey) client, err := evm.GetClient(destination.rpcEndpoint) if err != nil { return err } + cchainBlockchainID, err := contract.GetBlockchainID( + app, + network, + contract.ChainSpec{ + CChain: true, + }, + ) + if err != nil { + return err + } + isCChainDestination := cchainBlockchainID.String() == destination.blockchainID doPay := false - if flags.Amount != 0 { + switch { + case !isCChainDestination && flags.Amount != 0: + doPay = true + case isCChainDestination && flags.CChainAmount != 0: doPay = true - } else { + default: balance, err := evm.GetAddressBalance(client, addr.Hex()) if err != nil { return err } balanceFlt := new(big.Float).SetInt(balance) balanceFlt = balanceFlt.Quo(balanceFlt, new(big.Float).SetInt(vm.OneAvax)) - prompt := fmt.Sprintf("Do you want to fund relayer for destination %s (balance=%.9f)?", destination.blockchainDesc, balanceFlt) + prompt := fmt.Sprintf("Do you want to fund relayer for destination %s (current C-Chain AVAX balance: %.9f)?", destination.blockchainDesc, balanceFlt) yesOption := "Yes, I will send funds to it" noOption := "Not now" options := []string{yesOption, noOption} @@ -330,17 +339,7 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { privateKey = genesisPrivateKey } if flags.BlockchainFundingKey != "" || flags.CChainFundingKey != "" { - cchainBlockchainID, err := contract.GetBlockchainID( - app, - network, - contract.ChainSpec{ - CChain: true, - }, - ) - if err != nil { - return err - } - if cchainBlockchainID.String() == destination.blockchainID { + if isCChainDestination { if flags.CChainFundingKey != "" { k, err := app.GetKey(flags.CChainFundingKey, network, false) if err != nil { @@ -371,15 +370,32 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { return err } } + balance, err := evm.GetPrivateKeyBalance(client, privateKey) + if err != nil { + return err + } + if balance.Cmp(big.NewInt(0)) == 0 { + return fmt.Errorf("destination %s funding key as no balance", destination.blockchainDesc) + } + balanceBigFlt := new(big.Float).SetInt(balance) + balanceBigFlt = balanceBigFlt.Quo(balanceBigFlt, new(big.Float).SetInt(vm.OneAvax)) + balanceFlt, _ := balanceBigFlt.Float64() + balanceFlt -= aproxFundingFee var amountFlt float64 - if flags.Amount != 0 { + switch { + case !isCChainDestination && flags.Amount != 0: amountFlt = flags.Amount - } else { + case isCChainDestination && flags.CChainAmount != 0: + amountFlt = flags.CChainAmount + default: amountFlt, err = app.Prompt.CaptureFloat( - "Amount to transfer", + fmt.Sprintf("Amount to transfer (available: %f)", balanceFlt), func(f float64) error { if f <= 0 { - return fmt.Errorf("not positive") + return fmt.Errorf("%f is not positive", f) + } + if f > balanceFlt { + return fmt.Errorf("%f exceeds available funding balance of %f", f, balanceFlt) } return nil }, @@ -388,6 +404,14 @@ func CallDeploy(_ []string, flags DeployFlags, network models.Network) error { return err } } + if amountFlt > balanceFlt { + return fmt.Errorf( + "desired balance %f for destination %s exceeds available funding balance of %f", + amountFlt, + destination.blockchainDesc, + balanceFlt, + ) + } amountBigFlt := new(big.Float).SetFloat64(amountFlt) amountBigFlt = amountBigFlt.Mul(amountBigFlt, new(big.Float).SetInt(vm.OneAvax)) amount, _ := amountBigFlt.Int(nil) diff --git a/cmd/interchaincmd/relayercmd/logs.go b/cmd/interchaincmd/relayercmd/logs.go index 99b345fa0..1be5bcb46 100644 --- a/cmd/interchaincmd/relayercmd/logs.go +++ b/cmd/interchaincmd/relayercmd/logs.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/utils" + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" "github.com/ava-labs/avalanchego/utils/logging" "github.com/jedib0t/go-pretty/v6/table" @@ -131,7 +132,7 @@ func logs(_ *cobra.Command, _ []string) error { keys := maps.Keys(logMap) sort.Strings(keys) for _, k := range keys { - if !utils.Belongs([]string{"logger", "caller", "level", "timestamp", "msg"}, k) { + if !sdkUtils.Belongs([]string{"logger", "caller", "level", "timestamp", "msg"}, k) { logMsg = addAditionalInfo( logMsg, logMap, @@ -190,7 +191,7 @@ func getLogSubnet( } func getBlockchainIDToBlockchainNameMap(network models.Network) (map[string]string, error) { - blockchainNames, err := app.GetBlockchainNamesOnNetwork(network) + blockchainNames, err := app.GetBlockchainNamesOnNetwork(network, false) if err != nil { return nil, err } diff --git a/cmd/interchaincmd/tokentransferrercmd/deploy.go b/cmd/interchaincmd/tokentransferrercmd/deploy.go index b3fca4989..1735e54de 100644 --- a/cmd/interchaincmd/tokentransferrercmd/deploy.go +++ b/cmd/interchaincmd/tokentransferrercmd/deploy.go @@ -52,14 +52,7 @@ type DeployFlags struct { version string } -var ( - deploySupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - } - deployFlags DeployFlags -) +var deployFlags DeployFlags // avalanche interchain tokenTransferrer deploy func NewDeployCmd() *cobra.Command { @@ -70,7 +63,7 @@ func NewDeployCmd() *cobra.Command { RunE: deploy, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, deploySupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &deployFlags.Network, true, networkoptions.DefaultSupportedNetworkOptions) deployFlags.homeFlags.chainFlags.SetFlagNames( "home-blockchain", "c-chain-home", @@ -156,7 +149,7 @@ func CallDeploy(_ []string, flags DeployFlags) error { flags.Network, true, false, - deploySupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/keycmd/list.go b/cmd/keycmd/list.go index 44c2dd1bc..e52608de0 100644 --- a/cmd/keycmd/list.go +++ b/cmd/keycmd/list.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" "github.com/ava-labs/avalanchego/ids" ledger "github.com/ava-labs/avalanchego/utils/crypto/ledger" "github.com/ava-labs/avalanchego/utils/formatting/address" @@ -21,6 +22,7 @@ import ( "github.com/ava-labs/avalanchego/vms/avm" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/coreth/ethclient" + "github.com/ethereum/go-ethereum/common" goethereumethclient "github.com/ethereum/go-ethereum/ethclient" "github.com/liyue201/erc20-go/erc20" @@ -39,28 +41,22 @@ const ( ) var ( - globalNetworkFlags networkoptions.NetworkFlags - listSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Mainnet, - networkoptions.Fuji, - networkoptions.Local, - networkoptions.Devnet, - } - all bool - pchain bool - cchain bool - xchain bool - useNanoAvax bool - useGwei bool - ledgerIndices []uint - keys []string - tokenAddresses []string - subnetToken string - subnets []string - showNativeToken bool + globalNetworkFlags networkoptions.NetworkFlags + all bool + pchain bool + cchain bool + xchain bool + useNanoAvax bool + useGwei bool + ledgerIndices []uint + keys []string + tokenAddresses []string + subnetToken string + subnets []string + showNativeToken bool ) -// avalanche subnet list +// avalanche blockchain list func newListCmd() *cobra.Command { cmd := &cobra.Command{ Use: "list", @@ -69,7 +65,7 @@ func newListCmd() *cobra.Command { keys or for the ledger addresses associated to certain indices.`, RunE: listKeys, } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, listSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().BoolVarP( &all, allFlag, @@ -126,7 +122,7 @@ keys or for the ledger addresses associated to certain indices.`, &subnets, "subnets", []string{}, - "subnets to show information about (p=p-chain, x=x-chain, c=c-chain, and subnet names) (default p,x,c)", + "subnets to show information about (p=p-chain, x=x-chain, c=c-chain, and blockchain names) (default p,x,c)", ) cmd.Flags().StringSliceVar( &subnets, @@ -285,7 +281,7 @@ func listKeys(*cobra.Command, []string) error { globalNetworkFlags, true, false, - listSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { @@ -296,13 +292,13 @@ func listKeys(*cobra.Command, []string) error { if len(subnets) == 0 { subnets = []string{"p", "x", "c"} } - if !utils.Belongs(subnets, "p") { + if !sdkUtils.Belongs(subnets, "p") { pchain = false } - if !utils.Belongs(subnets, "x") { + if !sdkUtils.Belongs(subnets, "x") { xchain = false } - if !utils.Belongs(subnets, "c") { + if !sdkUtils.Belongs(subnets, "c") { cchain = false } queryLedger := len(ledgerIndices) > 0 @@ -311,7 +307,7 @@ func listKeys(*cobra.Command, []string) error { cchain = false xchain = false } - if utils.Belongs(tokenAddresses, "Native") || utils.Belongs(tokenAddresses, "native") { + if sdkUtils.Belongs(tokenAddresses, "Native") || sdkUtils.Belongs(tokenAddresses, "native") { showNativeToken = true } tokenAddresses = utils.RemoveFromSlice(tokenAddresses, "Native") @@ -347,7 +343,7 @@ func getStoredKeysInfo( return nil, err } if len(keys) != 0 { - keyNames = utils.Filter(keyNames, func(keyName string) bool { return utils.Belongs(keys, keyName) }) + keyNames = utils.Filter(keyNames, func(keyName string) bool { return sdkUtils.Belongs(keys, keyName) }) } addrInfos := []addressInfo{} for _, keyName := range keyNames { diff --git a/cmd/keycmd/transfer.go b/cmd/keycmd/transfer.go index a860aef79..783ba4b86 100644 --- a/cmd/keycmd/transfer.go +++ b/cmd/keycmd/transfer.go @@ -46,12 +46,6 @@ const ( ) var ( - transferSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Mainnet, - networkoptions.Fuji, - networkoptions.Devnet, - networkoptions.Local, - } keyName string ledgerIndex uint32 destinationAddrStr string @@ -75,7 +69,7 @@ func newTransferCmd() *cobra.Command { RunE: transferF, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, transferSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVarP( &keyName, keyNameFlag, @@ -164,7 +158,7 @@ func transferF(*cobra.Command, []string) error { globalNetworkFlags, true, false, - transferSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/networkcmd/clean.go b/cmd/networkcmd/clean.go index 237b80ba1..b9399ab8f 100644 --- a/cmd/networkcmd/clean.go +++ b/cmd/networkcmd/clean.go @@ -84,7 +84,7 @@ func clean(*cobra.Command, []string) error { return err } - return node.DestroyCurrentIfLocalNetwork(app) + return node.DestroyLocalNetworkConnectedCluster(app) } func removeLocalDeployInfoFromSidecars() error { diff --git a/cmd/networkcmd/helpers.go b/cmd/networkcmd/helpers.go index 7cb366a9e..9bf679888 100644 --- a/cmd/networkcmd/helpers.go +++ b/cmd/networkcmd/helpers.go @@ -146,7 +146,7 @@ func TrackSubnet( } } } - ux.Logger.PrintToUser("Restarting node %s to track subnet", nodeInfo.Name) + ux.Logger.PrintToUser("Restarting node %s to track newly deployed network", nodeInfo.Name) subnets := strings.TrimSpace(nodeInfo.WhitelistedSubnets) if subnets != "" { subnets += "," diff --git a/cmd/networkcmd/network.go b/cmd/networkcmd/network.go index 7fcfaafe1..6023d9ec8 100644 --- a/cmd/networkcmd/network.go +++ b/cmd/networkcmd/network.go @@ -14,15 +14,15 @@ func NewCmd(injectedApp *application.Avalanche) *cobra.Command { app = injectedApp cmd := &cobra.Command{ Use: "network", - Short: "Manage locally deployed subnets", - Long: `The network command suite provides a collection of tools for managing local Subnet + Short: "Manage locally deployed blockchains", + Long: `The network command suite provides a collection of tools for managing local Blockchain deployments. -When you deploy a Subnet locally, it runs on a local, multi-node Avalanche network. The -subnet deploy command starts this network in the background. This command suite allows you +When you deploy a Blockchain locally, it runs on a local, multi-node Avalanche network. The +blockchain deploy command starts this network in the background. This command suite allows you to shutdown, restart, and clear that network. -This network currently supports multiple, concurrently deployed Subnets.`, +This network currently supports multiple, concurrently deployed Blockchains.`, RunE: cobrautils.CommandSuiteUsage, Args: cobrautils.ExactArgs(0), } diff --git a/cmd/networkcmd/stop.go b/cmd/networkcmd/stop.go index 57a8d842a..2202a70a8 100644 --- a/cmd/networkcmd/stop.go +++ b/cmd/networkcmd/stop.go @@ -116,7 +116,7 @@ func stopAndSaveNetwork(flags StopFlags) error { } } - if err := node.StopCurrentIfLocalNetwork(app); err != nil { + if err := node.StopLocalNetworkConnectedCluster(app); err != nil { return err } diff --git a/cmd/nodecmd/create.go b/cmd/nodecmd/create.go index e456905fd..894c6c9fe 100644 --- a/cmd/nodecmd/create.go +++ b/cmd/nodecmd/create.go @@ -45,7 +45,6 @@ const ( ) var ( - createSupportedNetworkOptions = []networkoptions.NetworkOption{networkoptions.Fuji, networkoptions.Devnet, networkoptions.Mainnet} globalNetworkFlags networkoptions.NetworkFlags useAWS bool useGCP bool @@ -97,7 +96,7 @@ will apply to all nodes in the cluster`, RunE: createNodes, PersistentPostRun: handlePostRun, } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, createSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.NonLocalSupportedNetworkOptions) cmd.Flags().BoolVar(&useStaticIP, "use-static-ip", true, "attach static Public IP on cloud servers") cmd.Flags().BoolVar(&useAWS, "aws", false, "create node/s in AWS cloud") cmd.Flags().BoolVar(&useGCP, "gcp", false, "create node/s in GCP cloud") @@ -289,7 +288,7 @@ func createNodes(cmd *cobra.Command, args []string) error { globalNetworkFlags, false, true, - createSupportedNetworkOptions, + networkoptions.NonLocalSupportedNetworkOptions, "", ) if err := preCreateChecks(clusterName); err != nil { diff --git a/cmd/nodecmd/load_test_start.go b/cmd/nodecmd/load_test_start.go index b8c5c1c5b..98181c5ea 100644 --- a/cmd/nodecmd/load_test_start.go +++ b/cmd/nodecmd/load_test_start.go @@ -388,7 +388,7 @@ func getDeployedSubnetInfo(clusterName string, blockchainName string) (string, s } } } - return "", "", fmt.Errorf("unable to find deployed Cluster info, please call avalanche subnet deploy --cluster first") + return "", "", fmt.Errorf("unable to find deployed Cluster info, please call avalanche blockchain deploy --cluster first") } func createClusterYAMLFile(clusterName, subnetID, chainID string, separateHost *models.Host) error { diff --git a/cmd/nodecmd/local.go b/cmd/nodecmd/local.go index 10d2a05be..72f8e0222 100644 --- a/cmd/nodecmd/local.go +++ b/cmd/nodecmd/local.go @@ -4,50 +4,73 @@ package nodecmd import ( "fmt" + "math/big" "path/filepath" + "strings" + "time" + + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" + + "github.com/ava-labs/avalanchego/api/info" + + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + "github.com/ava-labs/avalanche-cli/pkg/constants" + "github.com/ava-labs/avalanche-cli/pkg/subnet" + "github.com/ava-labs/avalanche-cli/pkg/validatormanager" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/formatting/address" + warpMessage "github.com/ava-labs/avalanchego/vms/platformvm/warp/message" "github.com/ava-labs/avalanche-cli/pkg/binutils" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/keychain" "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/node" + "github.com/ava-labs/avalanche-cli/pkg/prompts" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/units" "github.com/spf13/cobra" ) var ( - localStartSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, - } avalanchegoBinaryPath string - bootstrapIDs []string - bootstrapIPs []string - genesisPath string - upgradePath string - stakingTLSKeyPath string - stakingCertKeyPath string - stakingSignerKeyPath string - numNodes uint32 - nodeConfigPath string - partialSync bool + bootstrapIDs []string + bootstrapIPs []string + genesisPath string + upgradePath string + stakingTLSKeyPath string + stakingCertKeyPath string + stakingSignerKeyPath string + numNodes uint32 + nodeConfigPath string + partialSync bool + stakeAmount uint64 + rpcURL string + balanceAVAX float64 + remainingBalanceOwnerAddr string + disableOwnerAddr string + aggregatorLogLevel string + aggregatorLogToStdout bool + delegationFee uint16 + publicKey string + pop string + minimumStakeDuration uint64 ) // const snapshotName = "local_snapshot" func newLocalCmd() *cobra.Command { cmd := &cobra.Command{ Use: "local", - Short: "(ALPHA Warning) Suite of commands for a local avalanche node", - Long: `(ALPHA Warning) This command is currently in experimental mode. - -The node local command suite provides a collection of commands related to local nodes`, - RunE: cobrautils.CommandSuiteUsage, + Short: "Suite of commands for a local avalanche node", + Long: `The node local command suite provides a collection of commands related to local nodes`, + RunE: cobrautils.CommandSuiteUsage, } // node local start cmd.AddCommand(newLocalStartCmd()) @@ -59,29 +82,27 @@ The node local command suite provides a collection of commands related to local cmd.AddCommand(newLocalTrackCmd()) // node local status cmd.AddCommand(newLocalStatusCmd()) + // node local validate + cmd.AddCommand(newLocalValidateCmd()) return cmd } func newLocalStartCmd() *cobra.Command { cmd := &cobra.Command{ Use: "start [clusterName]", - Short: "(ALPHA Warning) Create a new validator on local machine", - Long: `(ALPHA Warning) This command is currently in experimental mode. - -The node local start command sets up a validator on a local server. -The validator will be validating the Avalanche Primary Network and Subnet -of your choice. By default, the command runs an interactive wizard. It -walks you through all the steps you need to set up a validator. -Once this command is completed, you will have to wait for the validator + Short: "Create new Avalanche nodes on local machine", + Long: `The node local start command creates Avalanche nodes on the local machine. +Once this command is completed, you will have to wait for the Avalanche node to finish bootstrapping on the primary network before running further -commands on it, e.g. validating a Subnet. You can check the bootstrapping -status by running avalanche node status local +commands on it, e.g. validating a Subnet. + +You can check the bootstrapping status by running avalanche node status local. `, Args: cobra.ExactArgs(1), RunE: localStartNode, PersistentPostRun: handlePostRun, } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, localStartSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().BoolVar(&useLatestAvalanchegoReleaseVersion, "latest-avalanchego-version", false, "install latest avalanchego release version on node/s") cmd.Flags().BoolVar(&useLatestAvalanchegoPreReleaseVersion, "latest-avalanchego-pre-release-version", true, "install latest avalanchego pre-release version on node/s") cmd.Flags().StringVar(&useCustomAvalanchegoVersion, "custom-avalanchego-version", "", "install given avalanchego version on node/s") @@ -93,7 +114,7 @@ status by running avalanche node status local cmd.Flags().StringVar(&stakingTLSKeyPath, "staking-tls-key-path", "", "path to provided staking tls key for node") cmd.Flags().StringVar(&stakingCertKeyPath, "staking-cert-key-path", "", "path to provided staking cert key for node") cmd.Flags().StringVar(&stakingSignerKeyPath, "staking-signer-key-path", "", "path to provided staking signer key for node") - cmd.Flags().Uint32Var(&numNodes, "num-nodes", 1, "number of nodes to start") + cmd.Flags().Uint32Var(&numNodes, "num-nodes", 1, "number of Avalanche nodes to create on local machine") cmd.Flags().StringVar(&nodeConfigPath, "node-config", "", "path to common avalanchego config settings for all nodes") cmd.Flags().BoolVar(&partialSync, "partial-sync", true, "primary network partial sync") return cmd @@ -102,7 +123,7 @@ status by running avalanche node status local func newLocalStopCmd() *cobra.Command { return &cobra.Command{ Use: "stop", - Short: "(ALPHA Warning) Stop local node", + Short: "Stop local node", Long: `Stop local node.`, Args: cobra.ExactArgs(0), RunE: localStopNode, @@ -112,8 +133,8 @@ func newLocalStopCmd() *cobra.Command { func newLocalTrackCmd() *cobra.Command { cmd := &cobra.Command{ Use: "track [clusterName] [blockchainName]", - Short: "(ALPHA Warning) make the local node at the cluster to track given blockchain", - Long: "(ALPHA Warning) make the local node at the cluster to track given blockchain", + Short: "Track specified blockchain with local node", + Long: "Track specified blockchain with local node", Args: cobra.ExactArgs(2), RunE: localTrack, } @@ -127,7 +148,7 @@ func newLocalTrackCmd() *cobra.Command { func newLocalDestroyCmd() *cobra.Command { return &cobra.Command{ Use: "destroy [clusterName]", - Short: "(ALPHA Warning) Cleanup local node", + Short: "Cleanup local node", Long: `Cleanup local node.`, Args: cobra.ExactArgs(1), RunE: localDestroyNode, @@ -137,13 +158,13 @@ func newLocalDestroyCmd() *cobra.Command { func newLocalStatusCmd() *cobra.Command { cmd := &cobra.Command{ Use: "status", - Short: "(ALPHA Warning) Get status of local node", + Short: "Get status of local node", Long: `Get status of local node.`, Args: cobra.MaximumNArgs(1), RunE: localStatus, } - cmd.Flags().StringVar(&blockchainName, "subnet", "", "specify the blockchain the node is syncing with") + cmd.Flags().StringVar(&blockchainName, "l1", "", "specify the blockchain the node is syncing with") cmd.Flags().StringVar(&blockchainName, "blockchain", "", "specify the blockchain the node is syncing with") return cmd @@ -190,7 +211,7 @@ func localStartNode(_ *cobra.Command, args []string) error { avaGoVersionSetting, models.Network{}, globalNetworkFlags, - localStartSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, ) } @@ -242,3 +263,351 @@ func notImplementedForLocal(what string) error { ux.Logger.PrintToUser("Unsupported cmd: %s is not supported by local clusters", logging.LightBlue.Wrap(what)) return nil } + +func newLocalValidateCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "validate [clusterName]", + Short: "Validate a specified L1 with an Avalanche Node set up on local machine (PoS only)", + Long: `Use Avalanche Node set up on local machine to set up specified L1 by providing the +RPC URL of the L1. + +This command can only be used to validate Proof of Stake L1.`, + Args: cobra.ExactArgs(1), + RunE: localValidate, + } + + cmd.Flags().StringVar(&blockchainName, "l1", "", "specify the blockchain the node is syncing with") + cmd.Flags().StringVar(&blockchainName, "blockchain", "", "specify the blockchain the node is syncing with") + cmd.Flags().Uint64Var(&stakeAmount, "stake-amount", 0, "amount of tokens to stake") + cmd.Flags().StringVar(&rpcURL, "rpc", "", "connect to validator manager at the given rpc endpoint") + cmd.Flags().Float64Var(&balanceAVAX, "balance", 0, "amount of AVAX to increase validator's balance by") + cmd.Flags().Uint16Var(&delegationFee, "delegation-fee", 100, "delegation fee (in bips)") + cmd.Flags().StringVar(&aggregatorLogLevel, "aggregator-log-level", constants.DefaultAggregatorLogLevel, "log level to use with signature aggregator") + cmd.Flags().BoolVar(&aggregatorLogToStdout, "aggregator-log-to-stdout", false, "use stdout for signature aggregator logs") + cmd.Flags().StringVar(&remainingBalanceOwnerAddr, "remaining-balance-owner", "", "P-Chain address that will receive any leftover AVAX from the validator when it is removed from Subnet") + cmd.Flags().StringVar(&disableOwnerAddr, "disable-owner", "", "P-Chain address that will able to disable the validator with a P-Chain transaction") + cmd.Flags().Uint64Var(&minimumStakeDuration, "minimum-stake-duration", constants.PoSL1MinimumStakeDurationSeconds, "minimum stake duration (in seconds)") + + return cmd +} + +func localValidate(_ *cobra.Command, args []string) error { + clusterName := "" + if len(args) > 0 { + clusterName = args[0] + } + + if clusterName == "" { + return fmt.Errorf("local cluster name cannot be empty") + } + + if ok, err := node.CheckClusterIsLocal(app, clusterName); err != nil || !ok { + return fmt.Errorf("local cluster %q not found, please create it first using avalanche node local start %q", clusterName, clusterName) + } + + network, err := networkoptions.GetNetworkFromCmdLineFlags( + app, + "", + globalNetworkFlags, + true, + false, + networkoptions.DefaultSupportedNetworkOptions, + "", + ) + if err != nil { + return err + } + + fee := network.GenesisParams().TxFeeConfig.StaticFeeConfig.AddSubnetValidatorFee + kc, err := keychain.GetKeychainFromCmdLineFlags( + app, + "to pay for transaction fees on P-Chain", + network, + keyName, + useEwoq, + useLedger, + ledgerAddresses, + fee, + ) + if err != nil { + return err + } + + // should take input prior to here for stake amount, delegation fee, and min stake duration + if stakeAmount == 0 { + stakeAmount, err = app.Prompt.CaptureUint64Compare( + "Enter the amount of token to stake for each validator", + []prompts.Comparator{ + { + Label: "Positive", + Type: prompts.MoreThan, + Value: 0, + }, + }, + ) + if err != nil { + return err + } + } + + if rpcURL == "" { + rpcURL, err = app.Prompt.CaptureURL("What is the RPC endpoint?", false) + if err != nil { + return err + } + } + _, blockchainID, err := utils.SplitAvalanchegoRPCURI(rpcURL) + // if there is error that means RPC URL did not contain blockchain in it + // RPC might be in the format of something like https://etna.avax-dev.network + // We will prompt for blockchainID in that case + if err != nil { + blockchainID, err = app.Prompt.CaptureString("What is the Blockchain ID of the L1?") + if err != nil { + return err + } + } + chainSpec := contract.ChainSpec{ + BlockchainID: blockchainID, + } + if balanceAVAX == 0 { + availableBalance, err := utils.GetNetworkBalance(kc.Addresses().List(), network.Endpoint) + if err != nil { + return err + } + prompt := "How many AVAX do you want to each validator to start with?" + balanceAVAX, err = blockchain.PromptValidatorBalance(app, float64(availableBalance)/float64(units.Avax), prompt) + if err != nil { + return err + } + } + balance := uint64(balanceAVAX * float64(units.Avax)) + + if remainingBalanceOwnerAddr == "" { + remainingBalanceOwnerAddr, err = blockchain.GetKeyForChangeOwner(app, network) + if err != nil { + return err + } + } + remainingBalanceOwnerAddrID, err := address.ParseToIDs([]string{remainingBalanceOwnerAddr}) + if err != nil { + return fmt.Errorf("failure parsing remaining balanche owner address %s: %w", remainingBalanceOwnerAddr, err) + } + remainingBalanceOwners := warpMessage.PChainOwner{ + Threshold: 1, + Addresses: remainingBalanceOwnerAddrID, + } + + if disableOwnerAddr == "" { + disableOwnerAddr, err = prompts.PromptAddress( + app.Prompt, + "be able to disable the validator using P-Chain transactions", + app.GetKeyDir(), + app.GetKey, + "", + network, + prompts.PChainFormat, + "Enter P-Chain address (Example: P-...)", + ) + if err != nil { + return err + } + } + disableOwnerAddrID, err := address.ParseToIDs([]string{disableOwnerAddr}) + if err != nil { + return fmt.Errorf("failure parsing disable owner address %s: %w", disableOwnerAddr, err) + } + disableOwners := warpMessage.PChainOwner{ + Threshold: 1, + Addresses: disableOwnerAddrID, + } + + ux.Logger.PrintToUser("A private key is needed to pay for initialization of the validator's registration (Blockchain gas token).") + payerPrivateKey, err := prompts.PromptPrivateKey( + app.Prompt, + "pay the fee", + app.GetKeyDir(), + app.GetKey, + "", + "", + ) + if err != nil { + return err + } + + extraAggregatorPeers, err := blockchain.GetAggregatorExtraPeers(app, clusterName, []string{}) + if err != nil { + return err + } + aggregatorLogger, err := utils.NewLogger( + constants.SignatureAggregatorLogName, + aggregatorLogLevel, + constants.DefaultAggregatorLogLevel, + app.GetAggregatorLogDir(clusterName), + aggregatorLogToStdout, + ux.Logger.PrintToUser, + ) + if err != nil { + return err + } + + ctx, cancel := network.BootstrappingContext() + defer cancel() + cli, err := binutils.NewGRPCClientWithEndpoint( + binutils.LocalClusterGRPCServerEndpoint, + binutils.WithAvoidRPCVersionCheck(true), + binutils.WithDialTimeout(constants.FastGRPCDialTimeout), + ) + if err != nil { + return err + } + status, err := cli.Status(ctx) + if err != nil { + return err + } + + for _, node := range status.ClusterInfo.NodeInfos { + if err = addAsValidator(network, + node.Name, + chainSpec, + remainingBalanceOwners, disableOwners, + extraAggregatorPeers, + aggregatorLogger, + kc, + balance, + payerPrivateKey, + ); err != nil { + return err + } + } + + ux.Logger.PrintToUser(" ") + ux.Logger.GreenCheckmarkToUser("All validators are successfully added to the L1") + return nil +} + +func addAsValidator(network models.Network, + nodeName string, + chainSpec contract.ChainSpec, + remainingBalanceOwners, disableOwners warpMessage.PChainOwner, + extraAggregatorPeers []info.Peer, + aggregatorLogger logging.Logger, + kc *keychain.Keychain, + balance uint64, + payerPrivateKey string, +) error { + var nodeIDStr string + // get node data + nodeInfo, err := node.GetNodeInfo(nodeName) + if err != nil { + return err + } + nodeIDStr, publicKey, pop, err = node.GetNodeData(nodeInfo.Uri) + if err != nil { + return err + } + nodeID, err := ids.NodeIDFromString(nodeIDStr) + if err != nil { + return err + } + + ux.Logger.PrintToUser(" ") + ux.Logger.PrintToUser("Adding validator %s", nodeIDStr) + ux.Logger.PrintToUser(" ") + + blockchainTimestamp, err := blockchain.GetBlockchainTimestamp(network) + if err != nil { + return fmt.Errorf("failed to get blockchain timestamp: %w", err) + } + expiry := uint64(blockchainTimestamp.Add(constants.DefaultValidationIDExpiryDuration).Unix()) + + blsInfo, err := blockchain.ConvertToBLSProofOfPossession(publicKey, pop) + if err != nil { + return fmt.Errorf("failure parsing BLS info: %w", err) + } + + signedMessage, validationID, err := validatormanager.InitValidatorRegistration( + app, + network, + rpcURL, + chainSpec, + payerPrivateKey, + nodeID, + blsInfo.PublicKey[:], + expiry, + remainingBalanceOwners, + disableOwners, + 0, + extraAggregatorPeers, + true, + aggregatorLogger, + true, + delegationFee, + time.Duration(minimumStakeDuration)*time.Second, + big.NewInt(int64(stakeAmount)), + ) + if err != nil { + return err + } + ux.Logger.PrintToUser("ValidationID: %s", validationID) + + deployer := subnet.NewPublicDeployer(app, kc, network) + txID, _, err := deployer.RegisterL1Validator(balance, blsInfo, signedMessage) + if err != nil { + if !strings.Contains(err.Error(), "warp message already issued for validationID") { + return err + } + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The Validation ID was already registered on the P-Chain. Proceeding to the next step")) + } else { + ux.Logger.PrintToUser("RegisterL1ValidatorTx ID: %s", txID) + if err := blockchain.UpdatePChainHeight( + "Waiting for P-Chain to update validator information ...", + ); err != nil { + return err + } + } + + if err := validatormanager.FinishValidatorRegistration( + app, + network, + rpcURL, + chainSpec, + payerPrivateKey, + validationID, + extraAggregatorPeers, + true, + aggregatorLogger, + ); err != nil { + return err + } + + validatorWeight, err := getPoSValidatorWeight(network, chainSpec, nodeID) + if err != nil { + return err + } + + ux.Logger.PrintToUser(" NodeID: %s", nodeID) + ux.Logger.PrintToUser(" Network: %s", network.Name()) + ux.Logger.PrintToUser(" Weight: %d", validatorWeight) + ux.Logger.PrintToUser(" Balance: %.5f AVAX", float64(balance)/float64(units.Avax)) + ux.Logger.GreenCheckmarkToUser("Validator %s successfully added to the L1", nodeIDStr) + return nil +} + +func getPoSValidatorWeight(network models.Network, chainSpec contract.ChainSpec, nodeID ids.NodeID) (uint64, error) { + pClient := platformvm.NewClient(network.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + subnetID, err := contract.GetSubnetID( + app, + network, + chainSpec, + ) + if err != nil { + return 0, err + } + validatorsList, err := pClient.GetValidatorsAt(ctx, subnetID, api.ProposedHeight) + if err != nil { + return 0, err + } + return validatorsList[nodeID].Weight, nil +} diff --git a/cmd/nodecmd/update_subnet.go b/cmd/nodecmd/update_subnet.go index 8a71328f8..c04f41f50 100644 --- a/cmd/nodecmd/update_subnet.go +++ b/cmd/nodecmd/update_subnet.go @@ -76,7 +76,7 @@ func updateSubnet(_ *cobra.Command, args []string) error { } // doUpdateSubnet exports deployed subnet in user's local machine to cloud server and calls node to -// restart tracking the specified subnet (similar to avalanche subnet join command) +// restart tracking the specified subnet (similar to avalanche blockchain join command) func doUpdateSubnet( hosts []*models.Host, clusterName string, diff --git a/cmd/nodecmd/validate_primary.go b/cmd/nodecmd/validate_primary.go index 3331d9a3b..d80fc2084 100644 --- a/cmd/nodecmd/validate_primary.go +++ b/cmd/nodecmd/validate_primary.go @@ -160,7 +160,7 @@ func PromptWeightPrimaryNetwork(network models.Network) (uint64, error) { case defaultWeight: return defaultStake, nil default: - return app.Prompt.CaptureWeight(txt) + return app.Prompt.CaptureWeight(txt, func(uint64) error { return nil }) } } diff --git a/cmd/primarycmd/add_validator.go b/cmd/primarycmd/add_validator.go index 73ae8c018..ce8e64adc 100644 --- a/cmd/primarycmd/add_validator.go +++ b/cmd/primarycmd/add_validator.go @@ -25,12 +25,7 @@ import ( ) var ( - globalNetworkFlags networkoptions.NetworkFlags - addValidatorSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Fuji, - networkoptions.Mainnet, - networkoptions.Devnet, - } + globalNetworkFlags networkoptions.NetworkFlags keyName string useLedger bool ledgerAddresses []string @@ -60,7 +55,7 @@ in the Primary Network`, RunE: addValidator, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, addValidatorSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.NonLocalSupportedNetworkOptions) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji only]") cmd.Flags().StringVar(&nodeIDStr, "nodeID", "", "set the NodeID of the validator to add") cmd.Flags().Uint64Var(&weight, "weight", 0, "set the staking weight of the validator to add") @@ -92,7 +87,7 @@ func promptProofOfPossession() (jsonProofOfPossession, error) { if publicKey == "" || pop == "" { ux.Logger.PrintToUser("Next, we need the public key and proof of possession of the node's BLS") ux.Logger.PrintToUser("SSH into the node and call info.getNodeID API to get the node's BLS info") - ux.Logger.PrintToUser("Check https://docs.avax.network/apis/avalanchego/apis/info#infogetnodeid for instructions on calling info.getNodeID API") + ux.Logger.PrintToUser("Check https://docs.avax.network/api-reference/info-api#infogetnodeid for instructions on calling info.getNodeID API") } var err error if publicKey == "" { @@ -125,7 +120,7 @@ func addValidator(_ *cobra.Command, _ []string) error { globalNetworkFlags, true, false, - addValidatorSupportedNetworkOptions, + networkoptions.NonLocalSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/primarycmd/describe.go b/cmd/primarycmd/describe.go index bf70242dc..5b0395805 100644 --- a/cmd/primarycmd/describe.go +++ b/cmd/primarycmd/describe.go @@ -33,8 +33,6 @@ const art = ` \_____| \_____|_| |_|\__,_|_|_| |_| |_| \__,_|_| \__,_|_| |_| |_|___/ ` -var describeSupportedNetworkOptions = []networkoptions.NetworkOption{networkoptions.Local, networkoptions.Cluster} - // avalanche primary describe func newDescribeCmd() *cobra.Command { cmd := &cobra.Command{ @@ -44,7 +42,7 @@ func newDescribeCmd() *cobra.Command { RunE: describe, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, describeSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, false, networkoptions.LocalClusterSupportedNetworkOptions) return cmd } @@ -55,7 +53,7 @@ func describe(_ *cobra.Command, _ []string) error { globalNetworkFlags, false, false, - describeSupportedNetworkOptions, + networkoptions.LocalClusterSupportedNetworkOptions, "", ) if err != nil { diff --git a/cmd/root.go b/cmd/root.go index c1c25617e..1dfe24b30 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -59,10 +59,10 @@ func NewRootCmd() *cobra.Command { Use: "avalanche", Long: `Avalanche-CLI is a command-line tool that gives developers access to everything Avalanche. This release specializes in helping developers -build and test Subnets. +build and test Blockchain networks. To get started, look at the documentation for the subcommands or jump right -in with avalanche subnet create myNewSubnet.`, +in with avalanche blockchain create myNewBlockchain.`, PersistentPreRunE: createApp, Version: Version, PersistentPostRun: handleTracking, @@ -121,21 +121,6 @@ in with avalanche subnet create myNewSubnet.`, subcmd.Long = "The ictt command suite provides tools to deploy and manage Interchain Token Transferrers." rootCmd.AddCommand(subcmd) - // add subnet command - subcmd = blockchaincmd.NewCmd(app) - subcmd.Use = "subnet" - subcmd.Short = "Create and deploy blockchains (deprecation notice: use 'avalanche blockchain')" - subcmd.Long = `The subnet command suite provides a collection of tools for developing -and deploying Blockchains. - -To get started, use the subnet create command wizard to walk through the -configuration of your very first Blockchain. Then, go ahead and deploy it -with the subnet deploy command. You can use the rest of the commands to -manage your Blockchain configurations and live deployments. - -Deprecation notice: use 'avalanche blockchain'` - rootCmd.AddCommand(subcmd) - // add contract command rootCmd.AddCommand(contractcmd.NewCmd(app)) // add validator command diff --git a/cmd/transactioncmd/transaction.go b/cmd/transactioncmd/transaction.go index 410a3cee9..9ad599b7e 100644 --- a/cmd/transactioncmd/transaction.go +++ b/cmd/transactioncmd/transaction.go @@ -10,7 +10,7 @@ import ( var app *application.Avalanche -// avalanche subnet vm +// avalanche blockchain vm func NewCmd(injectedApp *application.Avalanche) *cobra.Command { cmd := &cobra.Command{ Use: "transaction", diff --git a/cmd/transactioncmd/transaction_commit.go b/cmd/transactioncmd/transaction_commit.go index 4550a804e..235d4b7ef 100644 --- a/cmd/transactioncmd/transaction_commit.go +++ b/cmd/transactioncmd/transaction_commit.go @@ -8,6 +8,7 @@ import ( "github.com/ava-labs/avalanche-cli/cmd/blockchaincmd" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" "github.com/ava-labs/avalanche-cli/pkg/keychain" + "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/subnet" "github.com/ava-labs/avalanche-cli/pkg/txutils" "github.com/ava-labs/avalanche-cli/pkg/ux" @@ -19,11 +20,11 @@ import ( // avalanche transaction commit func newTransactionCommitCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "commit [subnetName]", + Use: "commit [blockchainName]", Short: "commit a transaction", Long: "The transaction commit command commits a transaction by submitting it to the P-Chain.", RunE: commitTx, - Args: cobrautils.ExactArgs(1), + Args: cobrautils.MaximumNArgs(1), } cmd.Flags().StringVar(&inputTxPath, inputTxPathFlag, "", "Path to the transaction signed by all signatories") @@ -43,19 +44,54 @@ func commitTx(_ *cobra.Command, args []string) error { return err } + isCreateChainTx := txutils.IsCreateChainTx(tx) + network, err := txutils.GetNetwork(tx) if err != nil { return err } - subnetName := args[0] - sc, err := app.LoadSidecar(subnetName) + subnetID, err := txutils.GetSubnetID(tx) if err != nil { return err } - subnetID := sc.Networks[network.Name()].SubnetID - if subnetID == ids.Empty { - return errNoSubnetID + var ( + blockchainName string + sc models.Sidecar + ) + if len(args) > 0 { + blockchainName = args[0] + // subnet ID from tx is always preferred + if subnetID == ids.Empty { + sc, err = app.LoadSidecar(blockchainName) + if err != nil { + return err + } + subnetID = sc.Networks[network.Name()].SubnetID + if subnetID == ids.Empty { + return errNoSubnetID + } + } + } else if isCreateChainTx { + ux.Logger.PrintToUser("Tx is going to create a new blockchain ID but CLI can't locally persist") + ux.Logger.PrintToUser("the new metadata as no blockchain name was provided.") + ux.Logger.PrintToUser("If you desire to locally persist the blockchain metadata, please ensure") + ux.Logger.PrintToUser("that CLI manages the blockchain configuration.") + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("For that you should use the machine where 'avalanche blockchain create' was") + ux.Logger.PrintToUser("executed, or use another machine but first follow a export/import procedure using") + ux.Logger.PrintToUser("'avalanche blockchain export' 'avalanche blockchain import file'") + ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("In case of continuing without preserving the metadata, please keep a manual record of") + ux.Logger.PrintToUser("the subnet ID and the new blockchain ID") + ux.Logger.PrintToUser("") + yes, err := app.Prompt.CaptureYesNo("Do you want to continue execution without locally presenving metadata?") + if err != nil { + return err + } + if !yes { + return nil + } } isPermissioned, controlKeys, _, err := txutils.GetOwners(network, subnetID) @@ -73,7 +109,7 @@ func commitTx(_ *cobra.Command, args []string) error { if len(remainingSubnetAuthKeys) != 0 { signedCount := len(subnetAuthKeys) - len(remainingSubnetAuthKeys) ux.Logger.PrintToUser("%d of %d required signatures have been signed.", signedCount, len(subnetAuthKeys)) - blockchaincmd.PrintRemainingToSignMsg(subnetName, remainingSubnetAuthKeys, inputTxPath) + blockchaincmd.PrintRemainingToSignMsg(blockchainName, remainingSubnetAuthKeys, inputTxPath) return fmt.Errorf("tx is not fully signed") } @@ -92,11 +128,15 @@ func commitTx(_ *cobra.Command, args []string) error { ux.Logger.PrintToUser("Transaction successful, transaction ID: %s", txID) - if txutils.IsCreateChainTx(tx) { - if err := blockchaincmd.PrintDeployResults(subnetName, subnetID, txID); err != nil { + if isCreateChainTx { + if err := blockchaincmd.PrintDeployResults(blockchainName, subnetID, txID); err != nil { return err } - return app.UpdateSidecarNetworks(&sc, network, subnetID, txID, "", "", sc.Networks[network.Name()].BootstrapValidators, "") + if blockchainName != "" { + return app.UpdateSidecarNetworks(&sc, network, subnetID, txID, "", "", sc.Networks[network.Name()].BootstrapValidators, "") + } + ux.Logger.PrintToUser("This CLI instance will not locally preserve blockchain metadata.") + ux.Logger.PrintToUser("Please keep a manual record of the subnet ID and blockchain ID information.") } return nil diff --git a/cmd/transactioncmd/transaction_sign.go b/cmd/transactioncmd/transaction_sign.go index 0299dde25..a9b1061a6 100644 --- a/cmd/transactioncmd/transaction_sign.go +++ b/cmd/transactioncmd/transaction_sign.go @@ -32,11 +32,11 @@ var ( // avalanche transaction sign func newTransactionSignCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "sign [subnetName]", + Use: "sign [blockchainName]", Short: "sign a transaction", Long: "The transaction sign command signs a multisig transaction.", RunE: signTx, - Args: cobrautils.ExactArgs(1), + Args: cobrautils.MaximumNArgs(1), } cmd.Flags().StringVar(&inputTxPath, inputTxPathFlag, "", "Path to the transaction file for signing") @@ -96,23 +96,25 @@ func signTx(_ *cobra.Command, args []string) error { return errors.New("unsupported network") } - // we need subnet wallet signing validation + process - subnetName := args[0] - sc, err := app.LoadSidecar(subnetName) + // we need subnet ID for the wallet signing validation + process + subnetID, err := txutils.GetSubnetID(tx) if err != nil { return err } - subnetID := sc.Networks[network.Name()].SubnetID - if subnetID == ids.Empty { - return errNoSubnetID - } - - subnetIDFromTX, err := txutils.GetSubnetID(tx) - if err != nil { - return err - } - if subnetIDFromTX != ids.Empty { - subnetID = subnetIDFromTX + var blockchainName string + if len(args) > 0 { + blockchainName = args[0] + // subnet ID from tx is always preferred + if subnetID == ids.Empty { + sc, err := app.LoadSidecar(blockchainName) + if err != nil { + return err + } + subnetID = sc.Networks[network.Name()].SubnetID + if subnetID == ids.Empty { + return errNoSubnetID + } + } } isPermissioned, controlKeys, _, err := txutils.GetOwners(network, subnetID) @@ -130,7 +132,7 @@ func signTx(_ *cobra.Command, args []string) error { } if len(remainingSubnetAuthKeys) == 0 { - blockchaincmd.PrintReadyToSignMsg(subnetName, inputTxPath) + blockchaincmd.PrintReadyToSignMsg(blockchainName, inputTxPath) ux.Logger.PrintToUser("") return fmt.Errorf("tx is already fully signed") } @@ -174,7 +176,7 @@ func signTx(_ *cobra.Command, args []string) error { if err := blockchaincmd.SaveNotFullySignedTx( "Tx", tx, - subnetName, + blockchainName, subnetAuthKeys, remainingSubnetAuthKeys, inputTxPath, diff --git a/cmd/validatorcmd/getBalance.go b/cmd/validatorcmd/getBalance.go index b6340aa46..eaedbaf5c 100644 --- a/cmd/validatorcmd/getBalance.go +++ b/cmd/validatorcmd/getBalance.go @@ -4,14 +4,24 @@ package validatorcmd import ( "fmt" + "sort" "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/networkoptions" - "github.com/ava-labs/avalanche-cli/pkg/txutils" + "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/sdk/validator" + "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" + "github.com/ethereum/go-ethereum/common" + "github.com/spf13/cobra" + "golang.org/x/exp/maps" ) var globalNetworkFlags networkoptions.NetworkFlags @@ -19,15 +29,9 @@ var globalNetworkFlags networkoptions.NetworkFlags var ( l1 string validationIDStr string + nodeIDStr string ) -var getBalanceSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - func NewGetBalanceCmd() *cobra.Command { cmd := &cobra.Command{ Use: "getBalance", @@ -38,9 +42,10 @@ P-Chain continuous fee`, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, getBalanceSupportedNetworkOptions) - cmd.Flags().StringVar(&l1, "l1", "", "name of L1 (required to get balance of bootstrap validators)") - cmd.Flags().StringVar(&validationIDStr, "validation-id", "", "validationIDStr of the validator") + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) + cmd.Flags().StringVar(&l1, "l1", "", "name of L1") + cmd.Flags().StringVar(&validationIDStr, "validation-id", "", "validation ID of the validator") + cmd.Flags().StringVar(&nodeIDStr, "node-id", "", "node ID of the validator") return cmd } @@ -51,75 +56,153 @@ func getBalance(_ *cobra.Command, _ []string) error { globalNetworkFlags, true, false, - getBalanceSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { return err } - var balance uint64 - if validationIDStr != "" { - validationID, err := ids.FromString(validationIDStr) - if err != nil { - return err - } - balance, err = txutils.GetValidatorPChainBalanceValidationID(network, validationID) - if err != nil { - return err - } - ux.Logger.PrintToUser(" Validator Balance: %.5f", float64(balance)/float64(units.Avax)) + validationID, cancel, err := getNodeValidationID(network, l1, nodeIDStr, validationIDStr) + if err != nil { + return err + } + if cancel { return nil } + if validationID == ids.Empty { + return fmt.Errorf("the specified node is not a L1 validator") + } - isBootstrapValidator, err := app.Prompt.CaptureYesNo("Is the validator a bootstrap validator?") + balance, err := validator.GetValidatorBalance(network.SDKNetwork(), validationID) if err != nil { return err } - if isBootstrapValidator { - if l1 == "" { - return fmt.Errorf("--l1 flag is required to get bootstrap validator balance") - } - sc, err := app.LoadSidecar(l1) + ux.Logger.PrintToUser(" Validator Balance: %.5f AVAX", float64(balance)/float64(units.Avax)) + + return nil +} + +// getNodeValidationID returns the node validation ID based on input +// present in given args and prompted to the user +// it also returns a boolean that is true if the user cancels +// operations during prompting +func getNodeValidationID( + network models.Network, + l1 string, + nodeIDStr string, + validationIDStr string, +) (ids.ID, bool, error) { + var ( + validationID ids.ID + err error + ) + if validationIDStr != "" { + validationID, err = ids.FromString(validationIDStr) if err != nil { - return fmt.Errorf("failed to load sidecar: %w", err) + return validationID, false, err } - if !sc.Sovereign { - return fmt.Errorf("avalanche validator getBalance command is only applicable to sovereign L1s") + return validationID, false, nil + } + l1ListOption := "I will choose from the L1 validators list" + validationIDOption := "I know the validation ID" + cancelOption := "Cancel" + option := l1ListOption + if l1 == "" && nodeIDStr == "" { + options := []string{l1ListOption, validationIDOption, cancelOption} + option, err = app.Prompt.CaptureList( + "How do you want to specify the L1 validator", + options, + ) + if err != nil { + return ids.Empty, false, err } - bootstrapValidators := sc.Networks[network.Name()].BootstrapValidators - if len(bootstrapValidators) == 0 { - return fmt.Errorf("this L1 does not have any bootstrap validators") + } + switch option { + case l1ListOption: + chainSpec := contract.ChainSpec{ + BlockchainName: l1, } - bootstrapValidatorsString := []string{} - bootstrapValidatorsToIndexMap := make(map[string]int) - for index, validator := range bootstrapValidators { - bootstrapValidatorsString = append(bootstrapValidatorsString, validator.NodeID) - bootstrapValidatorsToIndexMap[validator.NodeID] = index + chainSpec.SetEnabled( + true, // prompt blockchain name + false, // do not prompt for PChain + false, // do not prompt for XChain + false, // do not prompt for CChain + true, // prompt blockchain ID + ) + chainSpec.OnlySOV = true + if l1 == "" { + if cancel, err := contract.PromptChain( + app, + network, + "Choose the L1", + "", + &chainSpec, + ); err != nil { + return ids.Empty, false, err + } else if cancel { + return ids.Empty, true, nil + } + l1 = chainSpec.BlockchainName } - chosenValidator, err := app.Prompt.CaptureList("Which bootstrap validator do you want to get balance of?", bootstrapValidatorsString) - if err != nil { - return err + if nodeIDStr == "" { + if l1 != "" { + sc, err := app.LoadSidecar(l1) + if err != nil { + return ids.Empty, false, fmt.Errorf("failed to load sidecar: %w", err) + } + if !sc.Sovereign { + return ids.Empty, false, fmt.Errorf("avalanche validator commands are only applicable to sovereign L1s") + } + } + subnetID, err := contract.GetSubnetID(app, network, chainSpec) + if err != nil { + return ids.Empty, false, err + } + pClient := platformvm.NewClient(network.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + validators, err := pClient.GetValidatorsAt(ctx, subnetID, api.ProposedHeight) + if err != nil { + return ids.Empty, false, err + } + if len(validators) == 0 { + return ids.Empty, false, fmt.Errorf("l1 has no validators") + } + nodeIDs := maps.Keys(validators) + nodeIDStrs := utils.Map(nodeIDs, func(nodeID ids.NodeID) string { return nodeID.String() }) + sort.Strings(nodeIDStrs) + nodeIDStr, err = app.Prompt.CaptureListWithSize("Choose Node ID of the validator", nodeIDStrs, 8) + if err != nil { + return ids.Empty, false, err + } } - validationID, err := ids.FromString(bootstrapValidators[bootstrapValidatorsToIndexMap[chosenValidator]].ValidationID) + nodeID, err := ids.NodeIDFromString(nodeIDStr) if err != nil { - return err + return ids.Empty, false, err } - balance, err = txutils.GetValidatorPChainBalanceValidationID(network, validationID) + rpcURL, _, err := contract.GetBlockchainEndpoints( + app, + network, + chainSpec, + true, + false, + ) if err != nil { - return err + return ids.Empty, false, err } - } else { - validationID, err := app.Prompt.CaptureID("What is the validator's validationID?") + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) + validationID, err = validator.GetRegisteredValidator(rpcURL, managerAddress, nodeID) if err != nil { - return err + return ids.Empty, false, err } - balance, err = txutils.GetValidatorPChainBalanceValidationID(network, validationID) + case validationIDOption: + validationID, err = app.Prompt.CaptureID("What is the validator's validationID?") if err != nil { - return err + return ids.Empty, false, err } + case cancelOption: + return ids.Empty, true, nil } - ux.Logger.PrintToUser(" Validator Balance: %.5f AVAX", float64(balance)/float64(units.Avax)) - - return nil + return validationID, false, nil } diff --git a/cmd/validatorcmd/increaseBalance.go b/cmd/validatorcmd/increaseBalance.go index aa2834668..190bb3948 100644 --- a/cmd/validatorcmd/increaseBalance.go +++ b/cmd/validatorcmd/increaseBalance.go @@ -5,15 +5,16 @@ package validatorcmd import ( "fmt" + "github.com/ava-labs/avalanche-cli/pkg/blockchain" + + "github.com/ava-labs/avalanche-cli/pkg/cobrautils" "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/keychain" + "github.com/ava-labs/avalanche-cli/pkg/networkoptions" "github.com/ava-labs/avalanche-cli/pkg/subnet" "github.com/ava-labs/avalanche-cli/pkg/utils" - - "github.com/ava-labs/avalanche-cli/pkg/cobrautils" - "github.com/ava-labs/avalanche-cli/pkg/networkoptions" - "github.com/ava-labs/avalanche-cli/pkg/txutils" "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/sdk/validator" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/units" "github.com/spf13/cobra" @@ -24,30 +25,24 @@ var ( useLedger bool useEwoq bool ledgerAddresses []string - balanceFlag float64 + balanceAVAX float64 ) -var increaseBalanceSupportedNetworkOptions = []networkoptions.NetworkOption{ - networkoptions.Local, - networkoptions.Devnet, - networkoptions.Fuji, - networkoptions.Mainnet, -} - func NewIncreaseBalanceCmd() *cobra.Command { cmd := &cobra.Command{ Use: "increaseBalance", - Short: "Increase current balance of validator on P-Chain", + Short: "Increases current balance of validator on P-Chain", Long: `This command increases the validator P-Chain balance`, RunE: increaseBalance, Args: cobrautils.ExactArgs(0), } - networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, increaseBalanceSupportedNetworkOptions) + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) cmd.Flags().StringVarP(&keyName, "key", "k", "", "select the key to use [fuji/devnet deploy only]") cmd.Flags().StringVar(&l1, "l1", "", "name of L1 (to increase balance of bootstrap validators only)") cmd.Flags().StringVar(&validationIDStr, "validation-id", "", "validationIDStr of the validator") - cmd.Flags().Float64Var(&balanceFlag, "balance", 0, "amount of AVAX to increase validator's balance by") + cmd.Flags().StringVar(&nodeIDStr, "node-id", "", "node ID of the validator") + cmd.Flags().Float64Var(&balanceAVAX, "balance", 0, "amount of AVAX to increase validator's balance by") return cmd } @@ -58,60 +53,24 @@ func increaseBalance(_ *cobra.Command, _ []string) error { globalNetworkFlags, true, false, - getBalanceSupportedNetworkOptions, + networkoptions.DefaultSupportedNetworkOptions, "", ) if err != nil { return err } - var balance uint64 - var validationID ids.ID - if validationIDStr != "" { - validationID, err = ids.FromString(validationIDStr) - if err != nil { - return err - } - } else { - isBootstrapValidator, err := app.Prompt.CaptureYesNo("Is the validator a bootstrap validator?") - if err != nil { - return err - } - if isBootstrapValidator { - if l1 == "" { - return fmt.Errorf("--l1 flag is required to get bootstrap validator balance") - } - sc, err := app.LoadSidecar(l1) - if err != nil { - return fmt.Errorf("failed to load sidecar: %w", err) - } - if !sc.Sovereign { - return fmt.Errorf("avalanche validator increaseBalance command is only applicable to sovereign L1s") - } - bootstrapValidators := sc.Networks[network.Name()].BootstrapValidators - if len(bootstrapValidators) == 0 { - return fmt.Errorf("this L1 does not have any bootstrap validators") - } - bootstrapValidatorsString := []string{} - bootstrapValidatorsToIndexMap := make(map[string]int) - for index, validator := range bootstrapValidators { - bootstrapValidatorsString = append(bootstrapValidatorsString, validator.NodeID) - bootstrapValidatorsToIndexMap[validator.NodeID] = index - } - chosenValidator, err := app.Prompt.CaptureList("Which bootstrap validator do you want to get balance of?", bootstrapValidatorsString) - if err != nil { - return err - } - validationID, err = ids.FromString(bootstrapValidators[bootstrapValidatorsToIndexMap[chosenValidator]].ValidationID) - if err != nil { - return err - } - } else { - validationID, err = app.Prompt.CaptureID("What is the validator's validationID?") - if err != nil { - return err - } - } + + validationID, cancel, err := getNodeValidationID(network, l1, nodeIDStr, validationIDStr) + if err != nil { + return err + } + if cancel { + return nil } + if validationID == ids.Empty { + return fmt.Errorf("the specified node is not a L1 validator") + } + fee := network.GenesisParams().TxFeeConfig.StaticFeeConfig.TxFee kc, err := keychain.GetKeychainFromCmdLineFlags( app, @@ -127,25 +86,27 @@ func increaseBalance(_ *cobra.Command, _ []string) error { return err } deployer := subnet.NewPublicDeployer(app, kc, network) - if balanceFlag == 0 { + + var balance uint64 + if balanceAVAX == 0 { availableBalance, err := utils.GetNetworkBalance(kc.Addresses().List(), network.Endpoint) if err != nil { return err } - balance, err = promptValidatorBalance(availableBalance / units.Avax) + prompt := "How many AVAX do you want to increase the balance of this validator by?" + balanceAVAX, err = blockchain.PromptValidatorBalance(app, float64(availableBalance)/float64(units.Avax), prompt) if err != nil { return err } - } else { - balance = uint64(balanceFlag * float64(units.Avax)) } + balance = uint64(balanceAVAX * float64(units.Avax)) _, err = deployer.IncreaseValidatorPChainBalance(validationID, balance) if err != nil { return err } deployer.CleanCacheWallet() - balance, err = txutils.GetValidatorPChainBalanceValidationID(network, validationID) + balance, err = validator.GetValidatorBalance(network.SDKNetwork(), validationID) if err != nil { return err } @@ -153,10 +114,3 @@ func increaseBalance(_ *cobra.Command, _ []string) error { return nil } - -func promptValidatorBalance(availableBalance uint64) (uint64, error) { - ux.Logger.PrintToUser("Validator's balance is used to pay for continuous fee to the P-Chain") - ux.Logger.PrintToUser("When this Balance reaches 0, the validator will be considered inactive and will no longer participate in validating the L1") - txt := "How many AVAX do you want to increase the balance of this validator by?" - return app.Prompt.CaptureValidatorBalance(txt, availableBalance, 0) -} diff --git a/cmd/validatorcmd/list.go b/cmd/validatorcmd/list.go new file mode 100644 index 000000000..b4512383a --- /dev/null +++ b/cmd/validatorcmd/list.go @@ -0,0 +1,121 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package validatorcmd + +import ( + "fmt" + "sort" + + "github.com/ava-labs/avalanche-cli/pkg/cobrautils" + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/pkg/networkoptions" + "github.com/ava-labs/avalanche-cli/pkg/utils" + "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanche-cli/sdk/validator" + "github.com/ava-labs/avalanche-cli/sdk/validatormanager" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/units" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" + "golang.org/x/exp/maps" + + "github.com/ethereum/go-ethereum/common" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" +) + +func NewListCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "list [blockchainName]", + Short: "Lists the validators of an L1", + Long: `This command gets a list of the validators of the L1`, + RunE: list, + Args: cobrautils.ExactArgs(1), + } + + networkoptions.AddNetworkFlagsToCmd(cmd, &globalNetworkFlags, true, networkoptions.DefaultSupportedNetworkOptions) + return cmd +} + +func list(_ *cobra.Command, args []string) error { + blockchainName := args[0] + sc, err := app.LoadSidecar(blockchainName) + if err != nil { + return fmt.Errorf("failed to load sidecar: %w", err) + } + if !sc.Sovereign { + return fmt.Errorf("avalanche validator commands are only applicable to sovereign L1s") + } + + network, err := networkoptions.GetNetworkFromCmdLineFlags( + app, + "", + globalNetworkFlags, + true, + false, + networkoptions.DefaultSupportedNetworkOptions, + "", + ) + if err != nil { + return err + } + + chainSpec := contract.ChainSpec{ + BlockchainName: blockchainName, + } + + rpcURL, _, err := contract.GetBlockchainEndpoints( + app, + network, + chainSpec, + true, + false, + ) + if err != nil { + return err + } + + subnetID, err := contract.GetSubnetID(app, network, chainSpec) + if err != nil { + return err + } + + pClient := platformvm.NewClient(network.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + validators, err := pClient.GetValidatorsAt(ctx, subnetID, api.ProposedHeight) + if err != nil { + return err + } + + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) + + t := ux.DefaultTable( + fmt.Sprintf("%s Validators", blockchainName), + table.Row{"Node ID", "Validation ID", "Weight", "Remaining Balance (AVAX)"}, + ) + + nodeIDs := maps.Keys(validators) + nodeIDStrs := utils.Map(nodeIDs, func(nodeID ids.NodeID) string { return nodeID.String() }) + sort.Strings(nodeIDStrs) + + for _, nodeIDStr := range nodeIDStrs { + nodeID, err := ids.NodeIDFromString(nodeIDStr) + if err != nil { + return err + } + balance := uint64(0) + validationID, err := validator.GetRegisteredValidator(rpcURL, managerAddress, nodeID) + if err != nil { + ux.Logger.RedXToUser("could not get validation ID for node %s due to %s", nodeID, err) + } else { + balance, err = validator.GetValidatorBalance(network.SDKNetwork(), validationID) + if err != nil { + ux.Logger.RedXToUser("could not get balance for node %s due to %s", nodeID, err) + } + } + t.AppendRow(table.Row{nodeID, validationID, validators[nodeID].Weight, float64(balance) / float64(units.Avax)}) + } + fmt.Println(t.Render()) + return nil +} diff --git a/cmd/validatorcmd/validator.go b/cmd/validatorcmd/validator.go index 54c3fe25d..4ba330e54 100644 --- a/cmd/validatorcmd/validator.go +++ b/cmd/validatorcmd/validator.go @@ -23,6 +23,8 @@ the validator will be considered inactive and will no longer participate in vali RunE: cobrautils.CommandSuiteUsage, } app = injectedApp + // validator list + cmd.AddCommand(NewListCmd()) // validator getBalance cmd.AddCommand(NewGetBalanceCmd()) // validator increaseBalance diff --git a/go.mod b/go.mod index be1bfb166..720ee868b 100644 --- a/go.mod +++ b/go.mod @@ -7,16 +7,17 @@ require ( github.com/ava-labs/avalanche-network-runner v1.8.4-0.20241130135139-a0946c5366be github.com/ava-labs/avalanchego v1.12.1-0.20241210172525-c7ebd8fbae88 github.com/ava-labs/coreth v0.13.9-rc.1 - github.com/ava-labs/icm-services v1.4.1-0.20241210192415-fbb658863e67 + github.com/ava-labs/icm-services v1.4.1-0.20250102154147-7d1e095dc849 github.com/ava-labs/subnet-evm v0.6.13-0.20241205165027-6c98da796f35 - github.com/aws/aws-sdk-go-v2 v1.32.6 - github.com/aws/aws-sdk-go-v2/config v1.28.6 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.182.0 - github.com/chelnak/ysmrr v0.4.0 - github.com/docker/docker v27.4.0+incompatible + github.com/aws/aws-sdk-go-v2 v1.33.0 + github.com/aws/aws-sdk-go-v2/config v1.28.10 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.200.0 + github.com/cavaliergopher/grab/v3 v3.0.1 + github.com/chelnak/ysmrr v0.5.0 + github.com/docker/docker v27.5.0+incompatible github.com/ethereum/go-ethereum v1.13.14 github.com/fatih/color v1.18.0 - github.com/go-git/go-git/v5 v5.12.0 + github.com/go-git/go-git/v5 v5.13.1 github.com/jedib0t/go-pretty/v6 v6.6.5 github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 @@ -26,66 +27,65 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 github.com/okteto/remote v0.0.0-20210428052247-99de42c04148 github.com/olekukonko/tablewriter v0.0.5 - github.com/onsi/ginkgo/v2 v2.22.0 - github.com/onsi/gomega v1.36.1 + github.com/onsi/ginkgo/v2 v2.22.2 + github.com/onsi/gomega v1.36.2 github.com/pborman/ansi v1.0.0 github.com/pingcap/errors v0.11.4 github.com/posthog/posthog-go v1.2.24 github.com/prometheus/client_golang v1.20.5 - github.com/schollz/progressbar/v3 v3.16.1 + github.com/schollz/progressbar/v3 v3.17.1 github.com/shirou/gopsutil v3.21.11+incompatible - github.com/spf13/afero v1.11.0 + github.com/spf13/afero v1.12.0 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.10.0 go.uber.org/mock v0.5.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.31.0 + golang.org/x/crypto v0.32.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/mod v0.22.0 - golang.org/x/net v0.32.0 - golang.org/x/oauth2 v0.23.0 + golang.org/x/net v0.34.0 + golang.org/x/oauth2 v0.25.0 golang.org/x/sync v0.10.0 golang.org/x/text v0.21.0 - google.golang.org/api v0.184.0 - google.golang.org/protobuf v1.35.2 + google.golang.org/api v0.216.0 + google.golang.org/protobuf v1.36.2 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - cloud.google.com/go/auth v0.5.1 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/auth v0.13.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect dario.cat/mergo v1.0.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/ProtonMail/go-crypto v1.1.3 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect - github.com/ava-labs/icm-contracts v1.0.9-0.20241210181701-a4bd5c92b056 // indirect + github.com/ava-labs/icm-contracts v1.0.9-0.20241231155804-0845b3c9fd39 // indirect github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.47 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.51 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.37.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.37.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 // indirect github.com/aws/smithy-go v1.22.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.10.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect - github.com/cavaliergopher/grab/v3 v3.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect @@ -100,7 +100,7 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/creack/pty v1.1.11 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.3.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect @@ -113,9 +113,9 @@ require ( github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect - github.com/gliderlabs/ssh v0.3.7 // indirect + github.com/gliderlabs/ssh v0.3.8 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-billy/v5 v5.6.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -128,12 +128,12 @@ require ( github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/renameio/v2 v2.0.0 // indirect - github.com/google/s2a-go v0.1.7 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.14.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect @@ -165,6 +165,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/moby/sys/reexec v0.1.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect @@ -173,20 +174,20 @@ require ( github.com/pires/go-proxyproto v0.6.2 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pkg/sftp v1.13.6 // indirect + github.com/pkg/sftp v1.13.7 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sirupsen/logrus v1.9.0 // indirect - github.com/skeema/knownhosts v1.2.2 // indirect + github.com/skeema/knownhosts v1.3.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -205,25 +206,25 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v1.0.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.33.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/sdk v1.33.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/term v0.28.0 // indirect + golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.28.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.68.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect + google.golang.org/grpc v1.69.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 6e010214d..7ed2223cf 100644 --- a/go.sum +++ b/go.sum @@ -8,15 +8,15 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= -cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= -cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= +cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= +cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= -cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= @@ -60,8 +60,8 @@ github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= @@ -89,50 +89,50 @@ github.com/ava-labs/avalanchego v1.12.1-0.20241210172525-c7ebd8fbae88 h1:tZdtOPF github.com/ava-labs/avalanchego v1.12.1-0.20241210172525-c7ebd8fbae88/go.mod h1:yhD5dpZyStIVbxQ550EDi5w5SL7DQ/xGE6TIxosb7U0= github.com/ava-labs/coreth v0.13.9-rc.1 h1:qIICpC/OZGYUP37QnLgIqqwGmxnLwLpZaUlqJNI85vU= github.com/ava-labs/coreth v0.13.9-rc.1/go.mod h1:7aMsRIo/3GBE44qWZMjnfqdqfcfZ5yShTTm2LObLaYo= -github.com/ava-labs/icm-contracts v1.0.9-0.20241210181701-a4bd5c92b056 h1:VJDtg5UW4SWBeEMtv6qdWgEohdZxEp3jGDAllH6f8eI= -github.com/ava-labs/icm-contracts v1.0.9-0.20241210181701-a4bd5c92b056/go.mod h1:b6Hr01e5LWPua+nuZrSjjCyqfEhgFFdjBmKoJMoWTZo= -github.com/ava-labs/icm-services v1.4.1-0.20241210192415-fbb658863e67 h1:KPgYE1Ij9IPH2LQ/9FuZVfiugOGaRxsW+SU2rKenXnI= -github.com/ava-labs/icm-services v1.4.1-0.20241210192415-fbb658863e67/go.mod h1:5KIsL1x6K17YM53Cn2EEmCEILJxe3COHmPQY9afbmAo= +github.com/ava-labs/icm-contracts v1.0.9-0.20241231155804-0845b3c9fd39 h1:gDvyXiHtyGHL2TfyYz48gybEOfsapI3PBXY148EJ2h8= +github.com/ava-labs/icm-contracts v1.0.9-0.20241231155804-0845b3c9fd39/go.mod h1:hZS72/9tbM+9JKdTs/UuGIWF3z+FEVlcGW4B9C8gECs= +github.com/ava-labs/icm-services v1.4.1-0.20250102154147-7d1e095dc849 h1:u4WO48Fwrvra0Y1cdwciPANtpdRoZGQJ7YSGuMcK+Qk= +github.com/ava-labs/icm-services v1.4.1-0.20250102154147-7d1e095dc849/go.mod h1:tL3GJYp8SpJxOapHNMSCxb8S4fv8GFOzTdabe4Ev4+U= github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60 h1:EL66gtXOAwR/4KYBjOV03LTWgkEXvLePribLlJNu4g0= github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60/go.mod h1:/7qKobTfbzBu7eSTVaXMTr56yTYk4j2Px6/8G+idxHo= github.com/ava-labs/subnet-evm v0.6.13-0.20241205165027-6c98da796f35 h1:CbXWon0fwGDEDCCiChx2VeIIwO3UML9+8OUTyNwPsxA= github.com/ava-labs/subnet-evm v0.6.13-0.20241205165027-6c98da796f35/go.mod h1:SfAF4jjYPkezKWShPY/T31WQdD/UHrDyqy0kxA0LE0w= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= -github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4= -github.com/aws/aws-sdk-go-v2 v1.32.6/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2 v1.33.0 h1:Evgm4DI9imD81V0WwD+TN4DCwjUMdc94TrduMLbgZJs= +github.com/aws/aws-sdk-go-v2 v1.33.0/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= -github.com/aws/aws-sdk-go-v2/config v1.28.6 h1:D89IKtGrs/I3QXOLNTH93NJYtDhm8SYa9Q5CsPShmyo= -github.com/aws/aws-sdk-go-v2/config v1.28.6/go.mod h1:GDzxJ5wyyFSCoLkS+UhGB0dArhb9mI+Co4dHtoTxbko= +github.com/aws/aws-sdk-go-v2/config v1.28.10 h1:fKODZHfqQu06pCzR69KJ3GuttraRJkhlC8g80RZ0Dfg= +github.com/aws/aws-sdk-go-v2/config v1.28.10/go.mod h1:PvdxRYZ5Um9QMq9PQ0zHHNdtKK+he2NHtFCUFMXWXeg= github.com/aws/aws-sdk-go-v2/credentials v1.1.1/go.mod h1:mM2iIjwl7LULWtS6JCACyInboHirisUUdkBPoTHMOUo= -github.com/aws/aws-sdk-go-v2/credentials v1.17.47 h1:48bA+3/fCdi2yAwVt+3COvmatZ6jUDNkDTIsqDiMUdw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.47/go.mod h1:+KdckOejLW3Ks3b0E3b5rHsr2f9yuORBum0WPnE5o5w= +github.com/aws/aws-sdk-go-v2/credentials v1.17.51 h1:F/9Sm6Y6k4LqDesZDPJCLxQGXNNHd/ZtJiWd0lCZKRk= +github.com/aws/aws-sdk-go-v2/credentials v1.17.51/go.mod h1:TKbzCHm43AoPyA+iLGGcruXd4AFhF8tOmLex2R9jWNQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.2/go.mod h1:3hGg3PpiEjHnrkrlasTfxFqUsZ2GCk/fMUn4CbKgSkM= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 h1:AmoU1pziydclFT/xRV+xXE/Vb8fttJCLRPv8oAkprc0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21/go.mod h1:AjUdLYe4Tgs6kpH4Bv7uMZo7pottoyHMn4eTcIcneaY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 h1:s/fF4+yDQDoElYhfIVvSNyeCydfbuTKzhxSXDXCPasU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25/go.mod h1:IgPfDv5jqFIzQSNbUEMoitNooSMXjRSDkhXv8jiROvU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 h1:ZntTCl5EsYnhN/IygQEUugpdwbhdkom9uHcbCftiGgA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25/go.mod h1:DBdPrgeocww+CSl1C8cEV8PN1mHMBhuCDLpXezyvWkE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 h1:IBAoD/1d8A8/1aA8g4MBVtTRHhXRiNAgwdbo/xRM2DI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23/go.mod h1:vfENuCM7dofkgKpYzuzf1VT1UKkA/YL3qanfBn7HCaA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28 h1:igORFSiH3bfq4lxKFkTSYDhJEUCYo6C8VKiWJjYwQuQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.28/go.mod h1:3So8EA/aAYm36L7XIvCVwLa0s5N0P7o2b1oqnx/2R4g= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28 h1:1mOW9zAUMhTSrMDssEHS/ajx8JcAj/IcftzcmNlmVLI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.28/go.mod h1:kGlXVIWDfvt2Ox5zEaNglmq0hXPHgQFNMix33Tw22jA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.182.0 h1:LaeziEhHZ/SJZYBK223QVzl3ucHvA9IP4tQMcxGrc9I= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.182.0/go.mod h1:kYXaB4FzyhEJjvrJ84oPnMElLiEAjGxxUunVW2tBSng= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.200.0 h1:3hH6o7Z2WeE1twvz44Aitn6Qz8DZN3Dh5IB4Eh2xq7s= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.200.0/go.mod h1:I76S7jN0nfsYTBtuTgTsJtK2Q8yJVDgrLr5eLN64wMA= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.2/go.mod h1:45MfaXZ0cNbeuT0KQ1XJylq8A6+OpVV2E5kvY/Kq+u8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 h1:50+XsN70RS7dwJ2CkVNXzj7U2L1HKP8nqTd3XWEXBN4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6/go.mod h1:WqgLmwY7so32kG01zD8CPTJWVWM+TzJoOVHwTg4aPug= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.7 h1:dZmNIRtPUvtvUIIDVNpvtnJQ8N8Iqm7SQAxf18htZYw= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.7/go.mod h1:vj8PlfJH9mnGeIzd6uMLPi5VgiqzGG7AZoe1kf1uTXM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9 h1:TQmKDyETFGiXVhZfQ/I0cCFziqqX58pi4tKJGYGFSz0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.9/go.mod h1:HVLPK2iHQBUx7HfZeOQSEu3v2ubZaAY2YPbAm5/WUyY= +github.com/aws/aws-sdk-go-v2/service/kms v1.37.8 h1:KbLZjYqhQ9hyB4HwXiheiflTlYQa0+Fz0Ms/rh5f3mk= +github.com/aws/aws-sdk-go-v2/service/kms v1.37.8/go.mod h1:ANs9kBhK4Ghj9z1W+bsr3WsNaPF71qkgd6eE6Ekol/Y= github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7NkwbjlijluLsrIbu/iyl35RO4= github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 h1:rLnYAfXQ3YAccocshIH5mzNNwZBkBo+bP6EhIxak6Hw= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.7/go.mod h1:ZHtuQJ6t9A/+YDuxOLnbryAmITtr8UysSny3qcyvJTc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 h1:JnhTZR3PiYDNKlXy50/pNeix9aGMo6lLpXwJ1mw8MD4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6/go.mod h1:URronUEGfXZN1VpdktPSD1EkAL9mfrV+2F4sjH38qOY= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 h1:YqtxripbjWb2QLyzRK9pByfEDvgg95gpC2AyDq4hFE8= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.9/go.mod h1:lV8iQpg6OLOfBnqbGMBKYjilBlf633qwHnBEiMSPoHY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 h1:6dBT1Lz8fK11m22R+AqfRsFn8320K0T5DTGxxOQBSMw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8/go.mod h1:/kiBvRQXBc6xeJTYzhSdGvJ5vm1tjaDEjH+MSeRJnlY= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 h1:s4074ZO1Hk8qv65GqNXqDjmkf4HSQqJukaLuuW0TpDA= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.2/go.mod h1:mVggCnIWoM09jP71Wh+ea7+5gAp53q+49wDFs1SW5z8= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 h1:VwhTrsTuVn52an4mXx29PqRzs2Dvu921NpGk7y43tAM= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.6/go.mod h1:+8h7PZb3yY5ftmVLD7ocEoE98hdc8PoKS0H3wfx1dlc= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= @@ -169,12 +169,11 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -183,8 +182,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chelnak/ysmrr v0.4.0 h1:WMvLGPlBK0kb6wHf5z9FfNvpM6sB9765jy2ajYc1Sfs= -github.com/chelnak/ysmrr v0.4.0/go.mod h1:8vCna4PJsPCb6eevtoG7Tljzfx3twpsO203Qj2gafLM= +github.com/chelnak/ysmrr v0.5.0 h1:aCLTtiJbzJVhiRTL1zyTGnWSCdK3R44QeFklPZRt8tg= +github.com/chelnak/ysmrr v0.5.0/go.mod h1:Eg/IrbWqE3hOD5itwl2GlekRD7um93ap4gHOsxe+KvQ= github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -200,13 +199,11 @@ github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMn github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= @@ -243,8 +240,8 @@ github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXk github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= +github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -270,8 +267,8 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker v27.4.0+incompatible h1:I9z7sQ5qyzO0BfAb9IMOawRkAGxhYsidKiTMcm0DU+A= -github.com/docker/docker v27.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= +github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 h1:qwcF+vdFrvPSEUDSX5RVoRccG8a5DhOdWdQ4zN62zzo= @@ -282,13 +279,12 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= +github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= @@ -327,8 +323,8 @@ github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnR github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gliderlabs/ssh v0.3.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= -github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= @@ -337,12 +333,12 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= +github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= -github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= +github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -391,7 +387,6 @@ github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -432,7 +427,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -448,24 +442,24 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= +github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -648,6 +642,8 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/sys/reexec v0.1.0 h1:RrBi8e0EBTLEgfruBOFcxtElzRGTEUkeIFaVXgU7wok= +github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -684,16 +680,16 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= -github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= -github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -724,8 +720,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.12.0/go.mod h1:fUqqXB5vEgVCZ131L+9say31RAri6aF6KDViawhxKK8= github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg= -github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= -github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM= +github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -760,8 +756,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -776,8 +772,8 @@ github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWR github.com/sanity-io/litter v1.5.1 h1:dwnrSypP6q56o3lFxTU+t2fwQ9A+U5qrXVO4Qg9KwVU= github.com/sanity-io/litter v1.5.1/go.mod h1:5Z71SvaYy5kcGtyglXOC9rrUi3c1E8CamFWjQsazTh0= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ= -github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME= +github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U= +github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -791,16 +787,16 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= +github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= @@ -836,7 +832,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -903,24 +898,26 @@ github.com/zondax/ledger-go v1.0.0/go.mod h1:HpgkgFh3Jkwi9iYLDATdyRxc8CxqxcywsFj go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= +go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -951,12 +948,10 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1017,7 +1012,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -1027,19 +1021,17 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= -golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= +golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1108,22 +1100,20 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1133,16 +1123,16 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1202,8 +1192,8 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.184.0 h1:dmEdk6ZkJNXy1JcDhn/ou0ZUq7n9zropG2/tR4z+RDg= -google.golang.org/api v0.184.0/go.mod h1:CeDTtUEiYENAf8PPG5VZW2yNp2VM3VWbCeTioAZBTBA= +google.golang.org/api v0.216.0 h1:xnEHy+xWFrtYInWPy8OdGFsyIfWJjtVnO39g7pz2BFY= +google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1226,10 +1216,10 @@ google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= -google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= +google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1238,10 +1228,9 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= -google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= +google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= +google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1253,8 +1242,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU= +google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/mocks/prompter.go b/internal/mocks/prompter.go index eb42ec239..db75aa642 100644 --- a/internal/mocks/prompter.go +++ b/internal/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.2. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks @@ -341,7 +341,7 @@ func (_m *Prompter) CaptureID(promptStr string) (ids.ID, error) { } // CaptureIndex provides a mock function with given fields: promptStr, options -func (_m *Prompter) CaptureIndex(promptStr string, options []any) (int, error) { +func (_m *Prompter) CaptureIndex(promptStr string, options []interface{}) (int, error) { ret := _m.Called(promptStr, options) if len(ret) == 0 { @@ -350,16 +350,16 @@ func (_m *Prompter) CaptureIndex(promptStr string, options []any) (int, error) { var r0 int var r1 error - if rf, ok := ret.Get(0).(func(string, []any) (int, error)); ok { + if rf, ok := ret.Get(0).(func(string, []interface{}) (int, error)); ok { return rf(promptStr, options) } - if rf, ok := ret.Get(0).(func(string, []any) int); ok { + if rf, ok := ret.Get(0).(func(string, []interface{}) int); ok { r0 = rf(promptStr, options) } else { r0 = ret.Get(0).(int) } - if rf, ok := ret.Get(1).(func(string, []any) error); ok { + if rf, ok := ret.Get(1).(func(string, []interface{}) error); ok { r1 = rf(promptStr, options) } else { r1 = ret.Error(1) @@ -485,7 +485,7 @@ func (_m *Prompter) CaptureMainnetL1StakingDuration(promptStr string) (time.Dura ret := _m.Called(promptStr) if len(ret) == 0 { - panic("no return value specified for CaptureMainnetDuration") + panic("no return value specified for CaptureMainnetL1StakingDuration") } var r0 time.Duration @@ -989,25 +989,25 @@ func (_m *Prompter) CaptureValidatedString(promptStr string, validator func(stri } // CaptureValidatorBalance provides a mock function with given fields: promptStr, availableBalance, minBalance -func (_m *Prompter) CaptureValidatorBalance(promptStr string, availableBalance uint64, minBalance float64) (uint64, error) { +func (_m *Prompter) CaptureValidatorBalance(promptStr string, availableBalance float64, minBalance float64) (float64, error) { ret := _m.Called(promptStr, availableBalance, minBalance) if len(ret) == 0 { panic("no return value specified for CaptureValidatorBalance") } - var r0 uint64 + var r0 float64 var r1 error - if rf, ok := ret.Get(0).(func(string, uint64, float64) (uint64, error)); ok { + if rf, ok := ret.Get(0).(func(string, float64, float64) (float64, error)); ok { return rf(promptStr, availableBalance, minBalance) } - if rf, ok := ret.Get(0).(func(string, uint64, float64) uint64); ok { + if rf, ok := ret.Get(0).(func(string, float64, float64) float64); ok { r0 = rf(promptStr, availableBalance, minBalance) } else { - r0 = ret.Get(0).(uint64) + r0 = ret.Get(0).(float64) } - if rf, ok := ret.Get(1).(func(string, uint64, float64) error); ok { + if rf, ok := ret.Get(1).(func(string, float64, float64) error); ok { r1 = rf(promptStr, availableBalance, minBalance) } else { r1 = ret.Error(1) @@ -1044,9 +1044,9 @@ func (_m *Prompter) CaptureVersion(promptStr string) (string, error) { return r0, r1 } -// CaptureWeight provides a mock function with given fields: promptStr -func (_m *Prompter) CaptureWeight(promptStr string) (uint64, error) { - ret := _m.Called(promptStr) +// CaptureWeight provides a mock function with given fields: promptStr, validator +func (_m *Prompter) CaptureWeight(promptStr string, validator func(uint64) error) (uint64, error) { + ret := _m.Called(promptStr, validator) if len(ret) == 0 { panic("no return value specified for CaptureWeight") @@ -1054,17 +1054,17 @@ func (_m *Prompter) CaptureWeight(promptStr string) (uint64, error) { var r0 uint64 var r1 error - if rf, ok := ret.Get(0).(func(string) (uint64, error)); ok { - return rf(promptStr) + if rf, ok := ret.Get(0).(func(string, func(uint64) error) (uint64, error)); ok { + return rf(promptStr, validator) } - if rf, ok := ret.Get(0).(func(string) uint64); ok { - r0 = rf(promptStr) + if rf, ok := ret.Get(0).(func(string, func(uint64) error) uint64); ok { + r0 = rf(promptStr, validator) } else { r0 = ret.Get(0).(uint64) } - if rf, ok := ret.Get(1).(func(string) error); ok { - r1 = rf(promptStr) + if rf, ok := ret.Get(1).(func(string, func(uint64) error) error); ok { + r1 = rf(promptStr, validator) } else { r1 = ret.Error(1) } diff --git a/mkdocs.yml b/mkdocs.yml index 6989e848e..d37fbb41c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: avalanche-cli -site_description: Avalanche-CLI is a command-line interface for building, deploying, and maintaining Avalanche Subnets. It can be used to support the entire Subnet development lifecycle from initial prototyping to production deployments. Avalanche-CLI is available for Linux and Mac, and is open source on GitHub. +site_description: Avalanche-CLI is a command-line interface for building, deploying, and maintaining Avalanche Blockchains. It can be used to support the entire Blockchain development lifecycle from initial prototyping to production deployments. Avalanche-CLI is available for Linux and Mac, and is open source on GitHub. nav: - Introduction: index.md - Ledger Simulator: ledger-simulator.md diff --git a/pkg/apmintegration/file_test.go b/pkg/apmintegration/file_test.go index d9e08f8f1..daa5a600f 100644 --- a/pkg/apmintegration/file_test.go +++ b/pkg/apmintegration/file_test.go @@ -242,7 +242,7 @@ func TestLoadSubnetFile_BadKey(t *testing.T) { require.NoError(err) _, err = LoadSubnetFile(app, subnet1) - require.ErrorContains(err, "invalid subnet key") + require.ErrorContains(err, "invalid key") } func TestGetVMsInSubnet(t *testing.T) { diff --git a/pkg/apmintegration/helpers.go b/pkg/apmintegration/helpers.go index 0c86f85f6..56f524bfa 100644 --- a/pkg/apmintegration/helpers.go +++ b/pkg/apmintegration/helpers.go @@ -68,7 +68,7 @@ func MakeKey(alias, subnet string) string { func splitKey(subnetKey string) (string, string, error) { splitSubnet := strings.Split(subnetKey, ":") if len(splitSubnet) != 2 { - return "", "", fmt.Errorf("invalid subnet key: %s", subnetKey) + return "", "", fmt.Errorf("invalid key: %s", subnetKey) } repo := splitSubnet[0] subnetName := splitSubnet[1] diff --git a/pkg/apmintegration/helpers_test.go b/pkg/apmintegration/helpers_test.go index 2d472c126..3ec1648a1 100644 --- a/pkg/apmintegration/helpers_test.go +++ b/pkg/apmintegration/helpers_test.go @@ -182,5 +182,5 @@ func TestSplitKey_Errpr(t *testing.T) { key := "ava-labs/avalanche-plugins-core_wagmi" _, _, err := splitKey(key) - require.ErrorContains(err, "invalid subnet key:") + require.ErrorContains(err, "invalid key:") } diff --git a/pkg/application/app.go b/pkg/application/app.go index 73990145e..2b9e55096 100644 --- a/pkg/application/app.go +++ b/pkg/application/app.go @@ -98,6 +98,20 @@ func (app *Avalanche) GetLocalDir(clusterName string) string { return filepath.Join(app.baseDir, constants.LocalDir, clusterName) } +func (app *Avalanche) GetLogDir() string { + return filepath.Join(app.baseDir, constants.LogDir) +} + +func (app *Avalanche) GetAggregatorLogDir(clusterName string) string { + if clusterName != "" { + conf, err := app.GetClusterConfig(clusterName) + if err == nil && conf.Local { + return app.GetLocalDir(clusterName) + } + } + return app.GetLogDir() +} + // Remove all plugins from plugin dir func (app *Avalanche) ResetPluginsDir() error { pluginDir := app.GetPluginsDir() @@ -271,7 +285,7 @@ func (app *Avalanche) GetAPMBaseDir() string { } func (app *Avalanche) GetAPMLog() string { - return filepath.Join(app.baseDir, constants.LogDir, constants.APMLogName) + return filepath.Join(app.GetLogDir(), constants.APMLogName) } func (app *Avalanche) GetAPMPluginDir() string { @@ -558,7 +572,7 @@ func (app *Avalanche) UpdateSidecarNetworks( ClusterName: clusterName, } if err := app.UpdateSidecar(sc); err != nil { - return fmt.Errorf("creation of chains and subnet was successful, but failed to update sidecar: %w", err) + return fmt.Errorf("creation of blockchain was successful, but failed to update sidecar: %w", err) } return nil } @@ -598,7 +612,10 @@ func (app *Avalanche) GetBlockchainNames() ([]string, error) { return names, nil } -func (app *Avalanche) GetBlockchainNamesOnNetwork(network models.Network) ([]string, error) { +func (app *Avalanche) GetBlockchainNamesOnNetwork( + network models.Network, + onlySOV bool, +) ([]string, error) { blockchainNames, err := app.GetBlockchainNames() if err != nil { return nil, err @@ -620,7 +637,8 @@ func (app *Avalanche) GetBlockchainNamesOnNetwork(network models.Network) ([]str } } } - if sc.Networks[networkName].BlockchainID != ids.Empty { + sovKindCriteria := !onlySOV || onlySOV && sc.Sovereign + if sc.Networks[networkName].BlockchainID != ids.Empty && sovKindCriteria { filtered = append(filtered, blockchainName) } } diff --git a/pkg/binutils/binaries.go b/pkg/binutils/binaries.go index 3226e95e4..8b48f5a52 100644 --- a/pkg/binutils/binaries.go +++ b/pkg/binutils/binaries.go @@ -223,7 +223,7 @@ func (pbd *pluginBinaryDownloader) UpgradeVM(vmID, vmBin string) error { // check if binary is already present, it should already exist if _, err := os.Stat(binaryPath); errors.Is(err, os.ErrNotExist) { - return errors.New("vm binary does not exist, are you sure this Subnet is ready to upgrade?") + return errors.New("vm binary does not exist, are you sure this blockchain is ready to upgrade?") } // overwrite existing file with new binary diff --git a/pkg/blockchain/helper.go b/pkg/blockchain/helper.go new file mode 100644 index 000000000..7b404c008 --- /dev/null +++ b/pkg/blockchain/helper.go @@ -0,0 +1,143 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package blockchain + +import ( + "encoding/json" + "fmt" + "time" + + "github.com/ava-labs/avalanche-cli/pkg/application" + "github.com/ava-labs/avalanche-cli/pkg/binutils" + "github.com/ava-labs/avalanche-cli/pkg/constants" + "github.com/ava-labs/avalanche-cli/pkg/models" + "github.com/ava-labs/avalanche-cli/pkg/utils" + "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanchego/api/info" + "github.com/ava-labs/avalanchego/network/peer" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/signer" +) + +func GetAggregatorExtraPeers( + app *application.Avalanche, + clusterName string, + extraURIs []string, +) ([]info.Peer, error) { + uris, err := GetAggregatorNetworkUris(app, clusterName) + if err != nil { + return nil, err + } + uris = append(uris, extraURIs...) + urisSet := set.Of(uris...) + uris = urisSet.List() + return UrisToPeers(uris) +} + +func GetAggregatorNetworkUris(app *application.Avalanche, clusterName string) ([]string, error) { + aggregatorExtraPeerEndpointsUris := []string{} + if clusterName != "" { + clustersConfig, err := app.LoadClustersConfig() + if err != nil { + return nil, err + } + clusterConfig := clustersConfig.Clusters[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 { + aggregatorExtraPeerEndpointsUris = append(aggregatorExtraPeerEndpointsUris, nodeInfo.Uri) + } + } else { // remote cluster case + hostIDs := utils.Filter(clusterConfig.GetCloudIDs(), clusterConfig.IsAvalancheGoHost) + for _, hostID := range hostIDs { + if nodeConfig, err := app.LoadClusterNodeConfig(hostID); err != nil { + return nil, err + } else { + aggregatorExtraPeerEndpointsUris = append(aggregatorExtraPeerEndpointsUris, fmt.Sprintf("http://%s:%d", nodeConfig.ElasticIP, constants.AvalancheGoAPIPort)) + } + } + } + } + return aggregatorExtraPeerEndpointsUris, nil +} + +func UrisToPeers(uris []string) ([]info.Peer, error) { + peers := []info.Peer{} + ctx, cancel := utils.GetANRContext() + defer cancel() + for _, uri := range uris { + client := info.NewClient(uri) + nodeID, _, err := client.GetNodeID(ctx) + if err != nil { + return nil, err + } + ip, err := client.GetNodeIP(ctx) + if err != nil { + return nil, err + } + peers = append(peers, info.Peer{ + Info: peer.Info{ + ID: nodeID, + PublicIP: ip, + }, + }) + } + return peers, nil +} + +func ConvertToBLSProofOfPossession(publicKey, proofOfPossesion string) (signer.ProofOfPossession, error) { + type jsonProofOfPossession struct { + PublicKey string + ProofOfPossession string + } + jsonPop := jsonProofOfPossession{ + PublicKey: publicKey, + ProofOfPossession: proofOfPossesion, + } + popBytes, err := json.Marshal(jsonPop) + if err != nil { + return signer.ProofOfPossession{}, err + } + pop := &signer.ProofOfPossession{} + err = pop.UnmarshalJSON(popBytes) + if err != nil { + return signer.ProofOfPossession{}, err + } + return *pop, nil +} + +func UpdatePChainHeight( + title string, +) error { + _, err := ux.TimedProgressBar( + 40*time.Second, + title, + 0, + ) + if err != nil { + return err + } + fmt.Println() + return nil +} + +func GetBlockchainTimestamp(network models.Network) (time.Time, error) { + ctx, cancel := utils.GetAPIContext() + defer cancel() + platformCli := platformvm.NewClient(network.Endpoint) + return platformCli.GetTimestamp(ctx) +} diff --git a/pkg/blockchain/prompts.go b/pkg/blockchain/prompts.go new file mode 100644 index 000000000..841777641 --- /dev/null +++ b/pkg/blockchain/prompts.go @@ -0,0 +1,59 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package blockchain + +import ( + "github.com/ava-labs/avalanche-cli/pkg/application" + "github.com/ava-labs/avalanche-cli/pkg/models" + "github.com/ava-labs/avalanche-cli/pkg/prompts" + "github.com/ava-labs/avalanche-cli/pkg/ux" +) + +func PromptValidatorBalance(app *application.Avalanche, availableBalance float64, prompt string) (float64, error) { + ux.Logger.PrintToUser("Validator's balance is used to pay for continuous fee to the P-Chain") + ux.Logger.PrintToUser("When this Balance reaches 0, the validator will be considered inactive and will no longer participate in validating the L1") + return app.Prompt.CaptureValidatorBalance(prompt, availableBalance, 0) +} + +func GetKeyForChangeOwner(app *application.Avalanche, 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?" + + const ( + getFromStored = "Get address from an existing stored key (created from avalanche key create or avalanche key import)" + custom = "Custom" + ) + + listOptions := []string{getFromStored, custom} + listDecision, err := app.Prompt.CaptureList(changeAddrPrompt, listOptions) + if err != nil { + return "", err + } + + var key string + + switch listDecision { + case getFromStored: + key, err = prompts.CaptureKeyAddress( + app.Prompt, + "be set as a change owner for leftover AVAX", + app.GetKeyDir(), + app.GetKey, + network, + prompts.PChainFormat, + ) + if err != nil { + return "", err + } + case custom: + addrPrompt := "Enter change address (P-chain format)" + changeAddr, err := app.Prompt.CaptureAddress(addrPrompt) + if err != nil { + return "", err + } + key = changeAddr.String() + } + if err != nil { + return "", err + } + return key, nil +} diff --git a/pkg/cloud/aws/aws.go b/pkg/cloud/aws/aws.go index cdb46e19e..a6af3a234 100644 --- a/pkg/cloud/aws/aws.go +++ b/pkg/cloud/aws/aws.go @@ -635,7 +635,7 @@ func (c *AwsCloud) IsInstanceTypeSupported(instanceType string) (bool, error) { return slices.Contains(supportedInstanceTypes, instanceType), nil } -// GetRootVolume returns a volume IDs attached to the given which is used as a root volume +// GetRootVolumeID returns a volume IDs attached to the given which is used as a root volume func (c *AwsCloud) GetRootVolumeID(instanceID string) (string, error) { describeInstanceOutput, err := c.ec2Client.DescribeInstances(c.ctx, &ec2.DescribeInstancesInput{ InstanceIds: []string{instanceID}, diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 7dcc3c987..2ea3ee098 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -264,8 +264,8 @@ const ( MetricsNumRegions = "num-region" MetricsNodeCreateCommand = "avalanche node create" MetricsNodeDevnetWizCommand = "avalanche node devnet wiz" - MetricsSubnetDeployCommand = "avalanche subnet deploy" - MetricsSubnetCreateCommand = "avalanche subnet create" + MetricsSubnetDeployCommand = "avalanche blockchain deploy" + MetricsSubnetCreateCommand = "avalanche blockchain create" SubnetType = "subnet type" PrecompileType = "precompile type" CustomAirdrop = "custom-airdrop" @@ -328,9 +328,15 @@ const ( ICTTVersion = "8012c2a90638c1b777622e6427dbe4a88e329539" // ICM - ICMVersion = "v1.0.0" - DefaultICMMessengerAddress = "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf" - MainnetCChainICMRegistryAddress = "0x7C43605E14F391720e1b37E49C78C4b03A488d98" - FujiCChainICMRegistryAddress = "0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228" - ValidatorUptimeDeductible = uint64(10) // seconds to make sure all L1 validators would agree on uptime + ICMVersion = "v1.0.0" + DefaultICMMessengerAddress = "0x253b2784c75e510dD0fF1da844684a1aC0aa5fcf" + MainnetCChainICMRegistryAddress = "0x7C43605E14F391720e1b37E49C78C4b03A488d98" + FujiCChainICMRegistryAddress = "0xF86Cb19Ad8405AEFa7d09C778215D2Cb6eBfB228" + ValidatorUptimeDeductible = uint64(10) // seconds to make sure all L1 validators would agree on uptime + PoSL1MinimumStakeDurationSeconds = 100 + + // Aggregator + DefaultAggregatorLogLevel = "Debug" + SignatureAggregatorLogName = "signature-aggregator" + MaxL1TotalWeightChange = 0.2 ) diff --git a/pkg/contract/chain.go b/pkg/contract/chain.go index 3bd9a3b71..1e8515717 100644 --- a/pkg/contract/chain.go +++ b/pkg/contract/chain.go @@ -33,6 +33,7 @@ type ChainSpec struct { BlockchainID string blockchainIDFlagEnabled bool blockchainIDFlagName string + OnlySOV bool } const ( @@ -205,19 +206,9 @@ func GetBlockchainEndpoints( wsEndpoint = sc.Networks[networkName].WSEndpoints[0] } } - if rpcEndpoint == "" { - switch { - case chainSpec.CChain: - rpcEndpoint = network.CChainEndpoint() - wsEndpoint = network.CChainWSEndpoint() - case network.Kind == models.Local: - blockchainID, err := GetBlockchainID(app, network, chainSpec) - if err != nil { - return "", "", err - } - rpcEndpoint = network.BlockchainEndpoint(blockchainID.String()) - wsEndpoint = network.BlockchainWSEndpoint(blockchainID.String()) - } + if rpcEndpoint == "" && chainSpec.CChain { + rpcEndpoint = network.CChainEndpoint() + wsEndpoint = network.CChainWSEndpoint() } blockchainDesc, err := GetBlockchainDesc(chainSpec) if err != nil { @@ -399,7 +390,7 @@ func PromptChain( blockchainNames []string ) if chainSpec.blockchainNameFlagEnabled { - blockchainNames, err = app.GetBlockchainNamesOnNetwork(network) + blockchainNames, err = app.GetBlockchainNamesOnNetwork(network, chainSpec.OnlySOV) if err != nil { return false, err } @@ -418,10 +409,13 @@ func PromptChain( return cancel, err } if blockchainID != "" { - // map from alias to blockchain ID (or identity) - chainID, err := utils.GetChainID(network.Endpoint, blockchainID) + chainID, err := ids.FromString(blockchainID) if err != nil { - return cancel, err + // map from alias to blockchain ID (or identity) + chainID, err = utils.GetChainID(network.Endpoint, blockchainID) + if err != nil { + return cancel, err + } } blockchainID = chainID.String() } diff --git a/pkg/contract/contract.go b/pkg/contract/contract.go index cfc879593..84e1ac82c 100644 --- a/pkg/contract/contract.go +++ b/pkg/contract/contract.go @@ -13,8 +13,8 @@ import ( "strings" "github.com/ava-labs/avalanche-cli/pkg/evm" - "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/core/types" @@ -252,7 +252,7 @@ func ParseSpec( } if event { for i := range inputsMaps { - if utils.Belongs(indexedFields, i) { + if sdkUtils.Belongs(indexedFields, i) { inputsMaps[i]["indexed"] = true } } @@ -326,7 +326,6 @@ func TxToMethod( txOpts.Value = payment tx, err := contract.Transact(txOpts, methodName, params...) if err != nil { - ux.Logger.PrintToUser("error on \"%s\": %s", description, err) trace, traceCallErr := DebugTraceCall( rpcURL, privateKey, @@ -340,11 +339,9 @@ func TxToMethod( ux.Logger.PrintToUser("Verify --debug flag value when calling 'blockchain create'") return tx, nil, err } - errorFromSignature, err := evm.GetErrorFromTrace(trace, errorSignatureToError) - if err != nil && !errors.Is(err, evm.ErrUnknownErrorSelector) { - ux.Logger.RedXToUser("failure traying to match error selector on trace: %s", err) - } - if errorFromSignature != nil { + if errorFromSignature, err := evm.GetErrorFromTrace(trace, errorSignatureToError); err != nil && !errors.Is(err, evm.ErrUnknownErrorSelector) { + ux.Logger.RedXToUser("failed to match error selector on trace: %s", err) + } else if errorFromSignature != nil { return tx, nil, errorFromSignature } else { ux.Logger.PrintToUser("error trace for %s error:", description) @@ -432,6 +429,18 @@ func TxToMethodWithWarpMessage( return tx, receipt, nil } +func printFailedReceiptStatusMessage( + rpcURL string, + description string, + tx *types.Transaction, +) { + ux.Logger.PrintToUser("Failed receipt status for %s error on %s, tx hash %s", + description, + rpcURL, + tx.Hash(), + ) +} + func handleFailedReceiptStatus( rpcURL string, description string, @@ -444,24 +453,19 @@ func handleFailedReceiptStatus( tx.Hash().String(), ) if err != nil { - ux.Logger.PrintToUser( - "Could not get debug trace for %s error on %s, tx hash %s: %s", - description, - rpcURL, - tx.Hash(), - err, - ) + printFailedReceiptStatusMessage(rpcURL, description, tx) + ux.Logger.PrintToUser("Could not get debug trace: %s", err) ux.Logger.PrintToUser("Verify --debug flag value when calling 'blockchain create'") return tx, receipt, err } - errorFromSignature, err := evm.GetErrorFromTrace(trace, errorSignatureToError) - if err != nil && !errors.Is(err, evm.ErrUnknownErrorSelector) { - ux.Logger.RedXToUser("failure traying to match error selector on trace: %s", err) - } - if errorFromSignature != nil { + if errorFromSignature, err := evm.GetErrorFromTrace(trace, errorSignatureToError); err != nil && !errors.Is(err, evm.ErrUnknownErrorSelector) { + printFailedReceiptStatusMessage(rpcURL, description, tx) + ux.Logger.RedXToUser("failed to match error selector on trace: %s", err) + } else if errorFromSignature != nil { return tx, receipt, errorFromSignature } else { - ux.Logger.PrintToUser("error trace for %s error:", description) + printFailedReceiptStatusMessage(rpcURL, description, tx) + ux.Logger.PrintToUser("error trace:") ux.Logger.PrintToUser("%#v", trace) } return tx, receipt, ErrFailedReceiptStatus diff --git a/pkg/evm/evm.go b/pkg/evm/evm.go index 38fa7affe..b9ed0537c 100644 --- a/pkg/evm/evm.go +++ b/pkg/evm/evm.go @@ -77,6 +77,17 @@ func GetContractBytecode( return code, err } +func GetPrivateKeyBalance( + client ethclient.Client, + privateKey string, +) (*big.Int, error) { + addr, err := utils.PrivateKeyToAddress(privateKey) + if err != nil { + return nil, err + } + return GetAddressBalance(client, addr.Hex()) +} + func GetAddressBalance( client ethclient.Client, addressStr string, @@ -649,38 +660,17 @@ func SetupProposerVM( if err != nil { return err } - return IssueTxsToActivateProposerVMFork(client, chainID, privKey) -} - -func IssueTxsToActivateProposerVMFork( - client ethclient.Client, - chainID *big.Int, - privKey *ecdsa.PrivateKey, -) error { var errorList []error - var err error for i := 0; i < repeatsOnFailure; i++ { - ctx, cancel := utils.GetAPILargeContext() - defer cancel() - err = issueTxsToActivateProposerVMFork(client, ctx, chainID, privKey) + err = issueTxsToActivateProposerVMFork(client, chainID, privKey) if err == nil { break } - err = fmt.Errorf( - "failure issuing txs to activate proposer VM fork for client %#v: %w", - client, - err, - ) + err = fmt.Errorf("failure issuing tx to activate proposer VM: %w", err) errorList = append(errorList, err) time.Sleep(sleepBetweenRepeats) } - // this means that on the last try there is error - // print out all previous errors - if err != nil { - for _, indivError := range errorList { - ux.Logger.RedXToUser("%s", indivError) - } - } + utils.PrintUnreportedErrors(errorList, err, ux.Logger.RedXToUser) return err } @@ -692,7 +682,6 @@ func IssueTxsToActivateProposerVMFork( // BuildBlockWithContext. func issueTxsToActivateProposerVMFork( client ethclient.Client, - ctx context.Context, chainID *big.Int, fundedKey *ecdsa.PrivateKey, ) error { @@ -701,25 +690,26 @@ func issueTxsToActivateProposerVMFork( gasPrice := big.NewInt(params.MinGasPrice) txSigner := types.LatestSignerForChainID(chainID) for i := 0; i < numTriggerTxs; i++ { + ctx, cancel := utils.GetTimedContext(1 * time.Minute) + defer cancel() prevBlockNumber, err := client.BlockNumber(ctx) if err != nil { - return err + return fmt.Errorf("client.BlockNumber failure at step %d: %w", i, err) } nonce, err := client.NonceAt(ctx, addr, nil) if err != nil { - return err + return fmt.Errorf("client.NonceAt failure at step %d: %w", i, err) } - tx := types.NewTransaction( - nonce, addr, common.Big1, params.TxGas, gasPrice, nil) + tx := types.NewTransaction(nonce, addr, common.Big1, params.TxGas, gasPrice, nil) triggerTx, err := types.SignTx(tx, txSigner, fundedKey) if err != nil { - return err + return fmt.Errorf("types.SignTx failure at step %d: %w", i, err) } if err := client.SendTransaction(ctx, triggerTx); err != nil { - return err + return fmt.Errorf("client.SendTransaction failure at step %d: %w", i, err) } if err := WaitForNewBlock(client, ctx, prevBlockNumber, 0, 0); err != nil { - return err + return fmt.Errorf("WaitForNewBlock failure at step %d: %w", i, err) } } return nil @@ -739,7 +729,7 @@ func WaitForNewBlock( totalDuration = 10 * time.Second } steps := totalDuration / stepDuration - for seconds := 0; seconds < int(steps); seconds++ { + for step := 0; step < int(steps); step++ { blockNumber, err := client.BlockNumber(ctx) if err != nil { return err @@ -749,7 +739,7 @@ func WaitForNewBlock( } time.Sleep(stepDuration) } - return fmt.Errorf("new block not produced in %f seconds", totalDuration.Seconds()) + return fmt.Errorf("no new block produced in %f seconds", totalDuration.Seconds()) } func ExtractWarpMessageFromReceipt( diff --git a/pkg/localnet/localnet.go b/pkg/localnet/localnet.go index f03dfc3d7..1e5352ba8 100644 --- a/pkg/localnet/localnet.go +++ b/pkg/localnet/localnet.go @@ -33,7 +33,13 @@ func GetEndpoint() (string, error) { } func GetClusterInfo() (*rpcpb.ClusterInfo, error) { - cli, err := binutils.NewGRPCClient( + return GetClusterInfoWithEndpoint(binutils.LocalNetworkGRPCServerEndpoint) +} + +func GetClusterInfoWithEndpoint(grpcServerEndpoint string) (*rpcpb.ClusterInfo, error) { + cli, err := binutils.NewGRPCClientWithEndpoint( + grpcServerEndpoint, + binutils.WithAvoidRPCVersionCheck(true), binutils.WithDialTimeout(constants.FastGRPCDialTimeout), ) if err != nil { diff --git a/pkg/localnet/output.go b/pkg/localnet/output.go index c04463f53..cf754f1a7 100644 --- a/pkg/localnet/output.go +++ b/pkg/localnet/output.go @@ -9,11 +9,12 @@ import ( "golang.org/x/exp/maps" "github.com/ava-labs/avalanche-cli/pkg/application" + "github.com/ava-labs/avalanche-cli/pkg/binutils" "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanche-cli/pkg/utils" + "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-network-runner/rpcpb" "github.com/jedib0t/go-pretty/v6/table" - "github.com/jedib0t/go-pretty/v6/text" ) // PrintLocalNetworkEndpoints prints the endpoints coming from the status call @@ -34,9 +35,16 @@ func PrintEndpoints( printFunc("") } } - if err := PrintNetworkEndpoints(printFunc, clusterInfo); err != nil { + if err := PrintNetworkEndpoints("Primary Nodes", printFunc, clusterInfo); err != nil { return err } + clusterInfo, err = GetClusterInfoWithEndpoint(binutils.LocalClusterGRPCServerEndpoint) + if err == nil { + printFunc("") + if err := PrintNetworkEndpoints("L1 Nodes", printFunc, clusterInfo); err != nil { + return err + } + } return nil } @@ -57,14 +65,10 @@ func PrintSubnetEndpoints( if nodeInfo == nil { return fmt.Errorf("unexpected nil nodeInfo") } - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true + t := ux.DefaultTable(fmt.Sprintf("%s RPC URLs", chainInfo.ChainName), nil) t.SetColumnConfigs([]table.ColumnConfig{ {Number: 1, AutoMerge: true}, }) - t.SetTitle(fmt.Sprintf("%s RPC URLs", chainInfo.ChainName)) blockchainIDURL := fmt.Sprintf("%s/ext/bc/%s/rpc", (*nodeInfo).GetUri(), chainInfo.ChainId) sc, err := app.LoadSidecar(chainInfo.ChainName) if err == nil { @@ -87,20 +91,16 @@ func PrintSubnetEndpoints( } func PrintNetworkEndpoints( + title string, printFunc func(msg string, args ...interface{}), clusterInfo *rpcpb.ClusterInfo, ) error { - t := table.NewWriter() - t.Style().Title.Align = text.AlignCenter - t.Style().Title.Format = text.FormatUpper - t.Style().Options.SeparateRows = true - t.SetTitle("Nodes") header := table.Row{"Name", "Node ID", "Localhost Endpoint"} insideCodespace := utils.InsideCodespace() if insideCodespace { header = append(header, "Codespace Endpoint") } - t.AppendHeader(header) + t := ux.DefaultTable(title, header) nodeNames := clusterInfo.NodeNames sort.Strings(nodeNames) nodeInfos := map[string]*rpcpb.NodeInfo{} diff --git a/pkg/models/host.go b/pkg/models/host.go index d275f54fc..dccf6238e 100644 --- a/pkg/models/host.go +++ b/pkg/models/host.go @@ -343,7 +343,7 @@ func (h *Host) FileExists(path string) (bool, error) { return true, nil } -// CreateTemp creates a temporary file on the remote server. +// CreateTempFile creates a temporary file on the remote server. func (h *Host) CreateTempFile() (string, error) { if !h.Connected() { if err := h.Connect(0); err != nil { diff --git a/pkg/models/network.go b/pkg/models/network.go index 7d513c21b..a36894c3b 100644 --- a/pkg/models/network.go +++ b/pkg/models/network.go @@ -8,10 +8,10 @@ import ( "os" "strings" + "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/utils" + sdkNetwork "github.com/ava-labs/avalanche-cli/sdk/network" "github.com/ava-labs/avalanchego/api/info" - - "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanchego/genesis" avagoconstants "github.com/ava-labs/avalanchego/utils/constants" ) @@ -226,6 +226,20 @@ func (n *Network) BootstrappingContext() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), timeout) } +func (n Network) SDKNetwork() sdkNetwork.Network { + switch n.Kind { + case Fuji: + return sdkNetwork.FujiNetwork() + case Mainnet: + return sdkNetwork.MainnetNetwork() + case Local: + return sdkNetwork.NewNetwork(sdkNetwork.Devnet, n.ID, n.Endpoint) + case Devnet: + return sdkNetwork.NewNetwork(sdkNetwork.Devnet, n.ID, n.Endpoint) + } + return sdkNetwork.UndefinedNetwork +} + // GetNetworkFromCluster gets the network that a cluster is on func GetNetworkFromCluster(clusterConfig ClusterConfig) Network { network := clusterConfig.Network diff --git a/pkg/networkoptions/network_options.go b/pkg/networkoptions/network_options.go index 56da0b06d..80c986168 100644 --- a/pkg/networkoptions/network_options.go +++ b/pkg/networkoptions/network_options.go @@ -31,6 +31,29 @@ const ( Cluster ) +var ( + DefaultSupportedNetworkOptions = []NetworkOption{ + Local, + Devnet, + Fuji, + Mainnet, + } + NonLocalSupportedNetworkOptions = []NetworkOption{ + Devnet, + Fuji, + Mainnet, + } + NonMainnetSupportedNetworkOptions = []NetworkOption{ + Local, + Devnet, + Fuji, + } + LocalClusterSupportedNetworkOptions = []NetworkOption{ + Local, + Cluster, + } +) + func (n NetworkOption) String() string { switch n { case Mainnet: @@ -51,6 +74,8 @@ func NetworkOptionFromString(s string) NetworkOption { switch { case s == "Mainnet": return Mainnet + case s == "Fuji": + return Fuji case s == "Fuji Testnet": return Fuji case s == "Local Network": @@ -207,7 +232,7 @@ func GetNetworkFromCmdLineFlags( supportedNetworkOptionsStrs = strings.Join(utils.Map(supportedNetworkOptions, func(s NetworkOption) string { return s.String() }), ", ") filteredSupportedNetworkOptionsStrs = strings.Join(utils.Map(filteredSupportedNetworkOptions, func(s NetworkOption) string { return s.String() }), ", ") if len(filteredSupportedNetworkOptions) == 0 { - return models.UndefinedNetwork, fmt.Errorf("no supported deployed networks available on subnet %q. please deploy to one of: [%s]", subnetName, supportedNetworkOptionsStrs) + return models.UndefinedNetwork, fmt.Errorf("no supported deployed networks available on blockchain %q. please deploy to one of: [%s]", subnetName, supportedNetworkOptionsStrs) } supportedNetworkOptions = filteredSupportedNetworkOptions } @@ -259,7 +284,7 @@ func GetNetworkFromCmdLineFlags( if len(scDevnetEndpoints) != 0 { endpointsMsg = fmt.Sprintf(". valid devnet endpoints: [%s]", strings.Join(scDevnetEndpoints, ", ")) } - errMsg = fmt.Errorf("network flag %s is not available on subnet %s. use one of %s or made a deploy for that network%s%s", networkFlagsMap[networkOption], subnetName, supportedNetworksFlags, clustersMsg, endpointsMsg) + errMsg = fmt.Errorf("network flag %s is not available on blockchain %s. use one of %s or made a deploy for that network%s%s", networkFlagsMap[networkOption], subnetName, supportedNetworksFlags, clustersMsg, endpointsMsg) } return models.UndefinedNetwork, errMsg } @@ -339,7 +364,7 @@ func GetNetworkFromCmdLineFlags( if subnetName != "" && networkFlags.ClusterName != "" { if _, err := utils.GetIndexInSlice(scClusterNames, networkFlags.ClusterName); err != nil { - return models.UndefinedNetwork, fmt.Errorf("subnet %s has not been deployed to cluster %s", subnetName, networkFlags.ClusterName) + return models.UndefinedNetwork, fmt.Errorf("blockchain %s has not been deployed to cluster %s", subnetName, networkFlags.ClusterName) } } diff --git a/pkg/node/helper.go b/pkg/node/helper.go index c598c3230..8d749d3c7 100644 --- a/pkg/node/helper.go +++ b/pkg/node/helper.go @@ -7,6 +7,8 @@ import ( "encoding/json" "errors" "fmt" + "os" + "path/filepath" "regexp" "sort" "strconv" @@ -24,8 +26,12 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/pkg/vm" + "github.com/ava-labs/avalanche-cli/sdk/network" + "github.com/ava-labs/avalanche-cli/sdk/publicarchive" + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" "github.com/ava-labs/avalanche-network-runner/rpcpb" "github.com/ava-labs/avalanchego/api/info" + "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" ) @@ -104,7 +110,7 @@ func CheckHostsAreRPCCompatible(app *application.Avalanche, hosts []*models.Host case models.SubnetEvm: ux.Logger.PrintToUser("To modify your Subnet-EVM version: https://docs.avax.network/build/subnet/upgrade/upgrade-subnet-vm") case models.CustomVM: - ux.Logger.PrintToUser("To modify your Custom VM binary: avalanche subnet upgrade vm %s --config", subnetName) + ux.Logger.PrintToUser("To modify your Custom VM binary: avalanche blockchain upgrade vm %s --config", subnetName) } ux.Logger.PrintToUser("Yoy can use \"avalanche node upgrade\" to upgrade Avalanche Go and/or Subnet-EVM to their latest versions") return fmt.Errorf("the Avalanche Go version of node(s) %s is incompatible with VM RPC version of %s", incompatibleNodes, subnetName) @@ -113,7 +119,7 @@ func CheckHostsAreRPCCompatible(app *application.Avalanche, hosts []*models.Host } func getRPCIncompatibleNodes(app *application.Avalanche, hosts []*models.Host, subnetName string) ([]string, error) { - ux.Logger.PrintToUser("Checking compatibility of node(s) avalanche go RPC protocol version with Subnet EVM RPC of subnet %s ...", subnetName) + ux.Logger.PrintToUser("Checking compatibility of node(s) avalanche go RPC protocol version with Subnet EVM RPC of blockchain %s ...", subnetName) sc, err := app.LoadSidecar(subnetName) if err != nil { return nil, err @@ -191,7 +197,7 @@ func getPublicEndpoints( publicNodes = clusterConfig.Nodes } publicTrackers := utils.Filter(trackers, func(tracker *models.Host) bool { - return utils.Belongs(publicNodes, tracker.GetCloudID()) + return sdkUtils.Belongs(publicNodes, tracker.GetCloudID()) }) endpoints := utils.Map(publicTrackers, func(tracker *models.Host) string { return GetAvalancheGoEndpoint(tracker.IP) @@ -413,7 +419,7 @@ func promptAvalancheGoVersionChoice(app *application.Avalanche, latestReleaseVer if err == nil { break } - ux.Logger.PrintToUser(fmt.Sprintf("no subnet named %s found", useAvalanchegoVersionFromSubnet)) + ux.Logger.PrintToUser(fmt.Sprintf("no blockchain named as %s found", useAvalanchegoVersionFromSubnet)) } return AvalancheGoVersionSettings{UseAvalanchegoVersionFromSubnet: useAvalanchegoVersionFromSubnet}, nil } @@ -423,7 +429,7 @@ func GetLatestAvagoVersionForRPC(app *application.Avalanche, configuredRPCVersio desiredAvagoVersion, err := vm.GetLatestAvalancheGoByProtocolVersion( app, configuredRPCVersion, constants.AvalancheGoCompatibilityURL) if errors.Is(err, vm.ErrNoAvagoVersion) { - ux.Logger.PrintToUser("No Avago version found for subnet. Defaulting to latest pre-release version") + ux.Logger.PrintToUser("No Avalanchego version found for blockchain. Defaulting to latest pre-release version") return latestPreReleaseVersion, nil } if err != nil { @@ -555,3 +561,75 @@ func GetNodeData(endpoint string) ( "0x" + hex.EncodeToString(proofOfPossession.ProofOfPossession[:]), nil } + +func DownloadPublicArchive( + clusterNetwork models.Network, + rootDir string, + nodeNames []string, +) error { + // only fuji is supported for now + if clusterNetwork.Kind != models.Fuji { + return fmt.Errorf("unsupported network: %s", clusterNetwork.Name()) + } + network := network.FujiNetwork() + ux.Logger.Info("downloading public archive for network %s", clusterNetwork.Name()) + publicArcDownloader, err := publicarchive.NewDownloader(network, logging.NewLogger("public-archive-downloader", logging.NewWrappedCore(logging.Off, os.Stdout, logging.JSON.ConsoleEncoder()))) // off as we run inside of the spinner + if err != nil { + return fmt.Errorf("failed to create public archive downloader for network %s: %w", clusterNetwork.Name(), err) + } + + if err := publicArcDownloader.Download(); err != nil { + return fmt.Errorf("failed to download public archive: %w", err) + } + defer publicArcDownloader.CleanUp() + if path, err := publicArcDownloader.GetFilePath(); err != nil { + return fmt.Errorf("failed to get downloaded file path: %w", err) + } else { + ux.Logger.Info("public archive downloaded to %s", path) + } + + wg := sync.WaitGroup{} + mu := sync.Mutex{} + var firstErr error + + for _, nodeName := range nodeNames { + target := filepath.Join(rootDir, nodeName, "db") + ux.Logger.Info("unpacking public archive to %s", target) + + // Skip if target already exists + if _, err := os.Stat(target); err == nil { + ux.Logger.Info("data folder already exists at %s. Skipping...", target) + continue + } + wg.Add(1) + go func(target string) { + defer wg.Done() + + if err := publicArcDownloader.UnpackTo(target); err != nil { + // Capture the first error encountered + mu.Lock() + if firstErr == nil { + firstErr = fmt.Errorf("failed to unpack public archive: %w", err) + _ = cleanUpClusterNodeData(rootDir, nodeNames) + } + mu.Unlock() + } + }(target) + } + wg.Wait() + + if firstErr != nil { + return firstErr + } + ux.Logger.PrintToUser("Public archive unpacked to: %s", rootDir) + return nil +} + +func cleanUpClusterNodeData(rootDir string, nodesNames []string) error { + for _, nodeName := range nodesNames { + if err := os.RemoveAll(filepath.Join(rootDir, nodeName)); err != nil { + return err + } + } + return nil +} diff --git a/pkg/node/local.go b/pkg/node/local.go index 9f169d302..0e1e6e1e5 100644 --- a/pkg/node/local.go +++ b/pkg/node/local.go @@ -103,7 +103,7 @@ func TrackSubnetWithLocalMachine( networkInfo := sc.Networks[network.Name()] rpcEndpoints := []string{} for _, nodeInfo := range status.ClusterInfo.NodeInfos { - ux.Logger.PrintToUser("Restarting node %s to track subnet", nodeInfo.Name) + ux.Logger.PrintToUser("Restarting node %s to track newly deployed network", nodeInfo.Name) if err := LocalNodeTrackSubnet( ctx, cli, @@ -124,7 +124,7 @@ func TrackSubnetWithLocalMachine( } ux.Logger.PrintToUser("Waiting for blockchain %s to be bootstrapped", blockchainName) if err := WaitBootstrapped(ctx, cli, blockchainID.String()); err != nil { - return fmt.Errorf("failure waiting for local cluster %s bootstrapping", blockchainName) + return fmt.Errorf("failure waiting for local cluster %s bootstrapping: %w", blockchainName, err) } for _, rpcURL := range rpcEndpoints { ux.Logger.PrintToUser("Waiting for rpc %s to be available", rpcURL) @@ -284,6 +284,7 @@ func StartLocalNode( } nodeConfig[config.NetworkAllowPrivateIPsKey] = true nodeConfig[config.IndexEnabledKey] = false + nodeConfig[config.IndexAllowIncompleteKey] = true nodeConfigBytes, err := json.Marshal(nodeConfig) if err != nil { @@ -338,7 +339,7 @@ func StartLocalNode( case network.Kind == models.Local: clusterInfo, err := localnet.GetClusterInfo() if err != nil { - return fmt.Errorf("failure trying to connect to local network: %w", err) + return fmt.Errorf("failed to connect to local network: %w", err) } rootDataDir := clusterInfo.RootDataDir networkJSONPath := filepath.Join(rootDataDir, "network.json") @@ -426,6 +427,14 @@ func StartLocalNode( ux.Logger.PrintToUser("Starting local avalanchego node using root: %s ...", rootDir) spinSession := ux.NewUserSpinner() spinner := spinSession.SpinToUser("Booting Network. Wait until healthy...") + // preseed nodes data from public archive. ignore errors + nodeNames := []string{} + for i := 1; i <= int(numNodes); i++ { + nodeNames = append(nodeNames, fmt.Sprintf("node%d", i)) + } + err := DownloadPublicArchive(network, rootDir, nodeNames) + ux.Logger.Info("seeding public archive data finished with error: %v. Ignored if any", err) + if _, err := cli.Start(ctx, avalancheGoBinPath, anrOpts...); err != nil { ux.SpinFailWithError(spinner, "", err) _ = DestroyLocalNode(app, clusterName) @@ -441,7 +450,7 @@ func StartLocalNode( ux.Logger.PrintToUser("Waiting for P-Chain to be bootstrapped") if err := WaitBootstrapped(ctx, cli, "P"); err != nil { - return fmt.Errorf("failure waiting for local cluster P-Chain bootstrapping") + return fmt.Errorf("failure waiting for local cluster P-Chain bootstrapping: %w", err) } ux.Logger.GreenCheckmarkToUser("Avalanchego started and ready to use from %s", rootDir) @@ -489,6 +498,9 @@ func UpsizeLocalNode( nodeConfig = map[string]interface{}{} } nodeConfig[config.NetworkAllowPrivateIPsKey] = true + if network.Kind == models.Fuji { + nodeConfig[config.IndexEnabledKey] = false // disable index for Fuji + } nodeConfigBytes, err := json.Marshal(nodeConfig) if err != nil { return "", err @@ -499,7 +511,7 @@ func UpsizeLocalNode( if network.Kind == models.Local { clusterInfo, err := localnet.GetClusterInfo() if err != nil { - return "", fmt.Errorf("failure trying to connect to local network: %w", err) + return "", fmt.Errorf("failed to connect to local network: %w", err) } rootDataDir := clusterInfo.RootDataDir networkJSONPath := filepath.Join(rootDataDir, "network.json") @@ -585,6 +597,8 @@ func UpsizeLocalNode( spinSession := ux.NewUserSpinner() spinner := spinSession.SpinToUser("Creating new node with name %s on local machine", newNodeName) + err = DownloadPublicArchive(network, rootDir, []string{newNodeName}) + ux.Logger.Info("seeding public archive data finished with error: %v. Ignored if any", err) // add new local node if _, err := cli.AddNode(ctx, newNodeName, avalancheGoBinPath, anrOpts...); err != nil { ux.SpinFailWithError(spinner, "", err) @@ -592,7 +606,7 @@ func UpsizeLocalNode( } ux.Logger.Info("Waiting for node: %s to be bootstrapping P-Chain", newNodeName) if err := WaitBootstrapped(ctx, cli, "P"); err != nil { - return newNodeName, fmt.Errorf("failure waiting for local cluster P-Chain bootstrapping") + return newNodeName, fmt.Errorf("failure waiting for local cluster P-Chain bootstrapping: %w", err) } ux.Logger.Info("Waiting for node: %s to be healthy", newNodeName) _, err = subnet.WaitForHealthy(ctx, cli) @@ -617,7 +631,7 @@ func UpsizeLocalNode( // wait until cluster is healthy ux.Logger.Info("Waiting for node: %s to be bootstrapping %s", newNodeName, blockchainName) if err := WaitBootstrapped(ctx, cli, blockchainID.String()); err != nil { - return newNodeName, fmt.Errorf("failure waiting for local cluster blockchain bootstrapping") + return newNodeName, fmt.Errorf("failure waiting for local cluster blockchain bootstrapping: %w", err) } spinner = spinSession.SpinToUser("Waiting for blockchain to be healthy") clusterInfo, err := subnet.WaitForHealthy(ctx, cli) @@ -757,7 +771,10 @@ func listLocalClusters(app *application.Avalanche, clusterNamesToInclude []strin return localClusters, nil } -func DestroyCurrentIfLocalNetwork(app *application.Avalanche) error { +// ConnectedToLocalNetwork returns true if a local cluster is running +// and it is connected to a local network. +// It also returns the name of the cluster that is connected to the local network +func ConnectedToLocalNetwork(app *application.Avalanche) (bool, string, error) { ctx, cancel := utils.GetANRContext() defer cancel() currentlyRunningRootDir := "" @@ -775,58 +792,43 @@ func DestroyCurrentIfLocalNetwork(app *application.Avalanche) error { } } if currentlyRunningRootDir == "" { - return nil + return false, "", nil } localClusters, err := listLocalClusters(app, nil) if err != nil { - return fmt.Errorf("failed to list local clusters: %w", err) + return false, "", fmt.Errorf("failed to list local clusters: %w", err) } for clusterName, rootDir := range localClusters { clusterConf, err := app.GetClusterConfig(clusterName) if err != nil { - return fmt.Errorf("failed to get cluster config: %w", err) + return false, "", fmt.Errorf("failed to get cluster config: %w", err) } network := models.ConvertClusterToNetwork(clusterConf.Network) if rootDir == currentlyRunningRootDir && network.Kind == models.Local { - _ = DestroyLocalNode(app, clusterName) + return true, clusterName, nil } } - return nil + return false, "", nil } -func StopCurrentIfLocalNetwork(app *application.Avalanche) error { - ctx, cancel := utils.GetANRContext() - defer cancel() - currentlyRunningRootDir := "" - cli, _ := binutils.NewGRPCClientWithEndpoint( // ignore error as ANR might be not running - binutils.LocalClusterGRPCServerEndpoint, - binutils.WithAvoidRPCVersionCheck(true), - binutils.WithDialTimeout(constants.FastGRPCDialTimeout), - ) - if cli != nil { - status, _ := cli.Status(ctx) // ignore error as ANR might be not running - if status != nil && status.ClusterInfo != nil { - if status.ClusterInfo.RootDataDir != "" { - currentlyRunningRootDir = status.ClusterInfo.RootDataDir - } - } +func DestroyLocalNetworkConnectedCluster(app *application.Avalanche) error { + isLocal, clusterName, err := ConnectedToLocalNetwork(app) + if err != nil { + return err } - if currentlyRunningRootDir == "" { - return nil + if isLocal { + _ = DestroyLocalNode(app, clusterName) } - localClusters, err := listLocalClusters(app, nil) + return nil +} + +func StopLocalNetworkConnectedCluster(app *application.Avalanche) error { + isLocal, _, err := ConnectedToLocalNetwork(app) if err != nil { - return fmt.Errorf("failed to list local clusters: %w", err) + return err } - for clusterName, rootDir := range localClusters { - clusterConf, err := app.GetClusterConfig(clusterName) - if err != nil { - return fmt.Errorf("failed to get cluster config: %w", err) - } - network := models.ConvertClusterToNetwork(clusterConf.Network) - if rootDir == currentlyRunningRootDir && network.Kind == models.Local { - return StopLocalNode(app) - } + if isLocal { + return StopLocalNode(app) } return nil } diff --git a/pkg/node/sync.go b/pkg/node/sync.go index 8116fdcf1..524716190 100644 --- a/pkg/node/sync.go +++ b/pkg/node/sync.go @@ -140,7 +140,7 @@ func trackSubnet( } wg.Wait() if wgResults.HasErrors() { - return fmt.Errorf("failed to track subnet for node(s) %s", wgResults.GetErrorHostMap()) + return fmt.Errorf("failed to track network for node(s) %s", wgResults.GetErrorHostMap()) } // update slice of subnets synced by the cluster diff --git a/pkg/plugins/avago_config.go b/pkg/plugins/avago_config.go index 41b2c8b57..630aedb3c 100644 --- a/pkg/plugins/avago_config.go +++ b/pkg/plugins/avago_config.go @@ -53,7 +53,7 @@ func EditConfigFile( if subnetAvagoConfigFile != "" { subnetAvagoConfigFileBytes, err := os.ReadFile(subnetAvagoConfigFile) if err != nil && !errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("failed to load extra flags from subnet avago config file %s: %w", subnetAvagoConfigFile, err) + return fmt.Errorf("failed to load extra flags from blockchain avalanchego config file %s: %w", subnetAvagoConfigFile, err) } var subnetAvagoConfig map[string]interface{} if err := json.Unmarshal(subnetAvagoConfigFileBytes, &subnetAvagoConfig); err != nil { @@ -61,7 +61,7 @@ func EditConfigFile( } for k, v := range subnetAvagoConfig { if k == "track-subnets" || k == "whitelisted-subnets" { - ux.Logger.PrintToUser("ignoring configuration setting for %q, a subnet's avago conf should not change it", k) + ux.Logger.PrintToUser("ignoring configuration setting for %q, a blockchain avalanchego config file should not change it", k) continue } avagoConfig[k] = v diff --git a/pkg/prompts/prompts.go b/pkg/prompts/prompts.go index b4285b155..21dd69bf2 100644 --- a/pkg/prompts/prompts.go +++ b/pkg/prompts/prompts.go @@ -11,8 +11,6 @@ import ( "strings" "time" - "github.com/ava-labs/avalanchego/utils/units" - "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/key" "github.com/ava-labs/avalanche-cli/pkg/models" @@ -110,8 +108,8 @@ type Prompter interface { CaptureDate(promptStr string) (time.Time, error) CaptureNodeID(promptStr string) (ids.NodeID, error) CaptureID(promptStr string) (ids.ID, error) - CaptureWeight(promptStr string) (uint64, error) - CaptureValidatorBalance(promptStr string, availableBalance uint64, minBalance float64) (uint64, error) + CaptureWeight(promptStr string, validator func(uint64) error) (uint64, error) + CaptureValidatorBalance(promptStr string, availableBalance float64, minBalance float64) (float64, error) CapturePositiveInt(promptStr string, comparators []Comparator) (int, error) CaptureInt(promptStr string, validator func(int) error) (int, error) CaptureUint8(promptStr string) (uint8, error) @@ -303,12 +301,12 @@ func (*realPrompter) CaptureNodeID(promptStr string) (ids.NodeID, error) { return ids.NodeIDFromString(nodeIDStr) } -// CaptureValidatorBalance captures balance in nanoAVAX +// CaptureValidatorBalance captures balance in AVAX func (*realPrompter) CaptureValidatorBalance( promptStr string, - availableBalance uint64, + availableBalance float64, minBalance float64, -) (uint64, error) { +) (float64, error) { prompt := promptui.Prompt{ Label: promptStr, Validate: validateValidatorBalanceFunc(availableBalance, minBalance), @@ -323,13 +321,22 @@ func (*realPrompter) CaptureValidatorBalance( return 0, err } - return uint64(amountFloat * float64(units.Avax)), nil + return amountFloat, nil } -func (*realPrompter) CaptureWeight(promptStr string) (uint64, error) { +func (*realPrompter) CaptureWeight(promptStr string, validator func(uint64) error) (uint64, error) { prompt := promptui.Prompt{ - Label: promptStr, - Validate: validateWeight, + Label: promptStr, + Validate: func(input string) error { + if err := validateWeight(input); err != nil { + return err + } + val, err := strconv.ParseUint(input, 10, 64) + if err != nil { + return err + } + return validator(val) + }, } amountStr, err := prompt.Run() @@ -885,11 +892,11 @@ func contains[T comparable](list []T, element T) bool { func CheckSubnetAuthKeys(walletKeys []string, subnetAuthKeys []string, controlKeys []string, threshold uint32) error { for _, walletKey := range walletKeys { if slices.Contains(controlKeys, walletKey) && !slices.Contains(subnetAuthKeys, walletKey) { - return fmt.Errorf("wallet key %s is a subnet control key so it must be included in subnet auth keys", walletKey) + return fmt.Errorf("wallet key %s is a control key so it must be included in auth keys", walletKey) } } if len(subnetAuthKeys) != int(threshold) { - return fmt.Errorf("number of given subnet auth differs from the threshold") + return fmt.Errorf("number of given auth keys differs from the threshold") } for _, subnetAuthKey := range subnetAuthKeys { found := false @@ -900,7 +907,7 @@ func CheckSubnetAuthKeys(walletKeys []string, subnetAuthKeys []string, controlKe } } if !found { - return fmt.Errorf("subnet auth key %s does not belong to control keys", subnetAuthKey) + return fmt.Errorf("auth key %s does not belong to control keys", subnetAuthKey) } } return nil @@ -917,7 +924,7 @@ func GetSubnetAuthKeys(prompt Prompter, walletKeys []string, controlKeys []strin filteredControlKeys = append(filteredControlKeys, controlKeys...) for _, walletKey := range walletKeys { if slices.Contains(controlKeys, walletKey) { - ux.Logger.PrintToUser("Adding wallet key %s to the tx subnet auth keys as it is a subnet control key", walletKey) + ux.Logger.PrintToUser("Adding wallet key %s to the tx auth keys as it is a control key", walletKey) subnetAuthKeys = append(subnetAuthKeys, walletKey) index, err := utils.GetIndexInSlice(filteredControlKeys, walletKey) if err != nil { @@ -928,7 +935,7 @@ func GetSubnetAuthKeys(prompt Prompter, walletKeys []string, controlKeys []strin } for len(subnetAuthKeys) != int(threshold) { subnetAuthKey, err := prompt.CaptureList( - "Choose a subnet auth key", + "Choose an auth key", filteredControlKeys, ) if err != nil { @@ -1045,7 +1052,7 @@ func PromptChain( return false, false, false, false, "", blockchainID, nil } if subnetOption == notListedOption { - ux.Logger.PrintToUser("Please import the subnet first, using the `avalanche subnet import` command suite") + ux.Logger.PrintToUser("Please import the blockchain first, using the `avalanche blockchain import` command suite") return true, false, false, false, "", "", nil } switch subnetOption { diff --git a/pkg/prompts/validations.go b/pkg/prompts/validations.go index 28dec477b..144befeee 100644 --- a/pkg/prompts/validations.go +++ b/pkg/prompts/validations.go @@ -149,7 +149,7 @@ func validateWeight(input string) error { return nil } -func validateValidatorBalanceFunc(availableBalance uint64, minBalance float64) func(string) error { +func validateValidatorBalanceFunc(availableBalance float64, minBalance float64) func(string) error { return func(input string) error { val, err := strconv.ParseFloat(input, 64) if err != nil { @@ -159,10 +159,10 @@ func validateValidatorBalanceFunc(availableBalance uint64, minBalance float64) f return fmt.Errorf("entered value has to be greater than 0 AVAX") } if val < minBalance { - return fmt.Errorf("validator balance must be at least %2f AVAX", minBalance) + return fmt.Errorf("validator balance must be at least %.2f AVAX", minBalance) } - if val > float64(availableBalance) { - return fmt.Errorf("current balance of %d is not sufficient for validator balance to be %2f AVAX", availableBalance, val) + if val > availableBalance { + return fmt.Errorf("current balance of %.2f is not sufficient for validator balance to be %.2f AVAX", availableBalance, val) } return nil } diff --git a/pkg/ssh/ssh.go b/pkg/ssh/ssh.go index 0cbecc127..807b8fb2e 100644 --- a/pkg/ssh/ssh.go +++ b/pkg/ssh/ssh.go @@ -672,7 +672,7 @@ func RunSSHCreatePlugin(host *models.Host, sc models.Sidecar) error { // RunSSHMergeSubnetNodeConfig merges subnet node config to the node config on the remote host func mergeSubnetNodeConfig(host *models.Host, subnetNodeConfigPath string) error { if subnetNodeConfigPath == "" { - return fmt.Errorf("subnet node config path is empty") + return fmt.Errorf("node config path is empty") } remoteNodeConfigBytes, err := host.ReadFileBytes(remoteconfig.GetRemoteAvalancheNodeConfig(), constants.SSHFileOpsTimeout) if err != nil { @@ -684,11 +684,11 @@ func mergeSubnetNodeConfig(host *models.Host, subnetNodeConfigPath string) error } subnetNodeConfigBytes, err := os.ReadFile(subnetNodeConfigPath) if err != nil { - return fmt.Errorf("error reading subnet node config: %w", err) + return fmt.Errorf("error reading node config: %w", err) } var subnetNodeConfig map[string]interface{} if err := json.Unmarshal(subnetNodeConfigBytes, &subnetNodeConfig); err != nil { - return fmt.Errorf("error unmarshalling subnet node config: %w", err) + return fmt.Errorf("error unmarshalling node config: %w", err) } maps.Copy(remoteNodeConfig, subnetNodeConfig) // merge remote config into local subnet config. subnetNodeConfig takes precedence mergedNodeConfigBytes, err := json.MarshalIndent(remoteNodeConfig, "", " ") @@ -729,14 +729,14 @@ func RunSSHSyncSubnetData(app *application.Avalanche, host *models.Host, network if app.AvagoSubnetConfigExists(subnetName) { subnetConfig, err := app.LoadRawAvagoSubnetConfig(subnetName) if err != nil { - return fmt.Errorf("error loading subnet config: %w", err) + return fmt.Errorf("error loading blockchain config: %w", err) } subnetConfigPath := filepath.Join(constants.CloudNodeConfigPath, "subnets", subnetIDStr+".json") if err := host.MkdirAll(filepath.Dir(subnetConfigPath), constants.SSHDirOpsTimeout); err != nil { return err } if err := host.UploadBytes(subnetConfig, subnetConfigPath, constants.SSHFileOpsTimeout); err != nil { - return fmt.Errorf("error uploading subnet config to %s: %w", subnetConfigPath, err) + return fmt.Errorf("error uploading blockchain config to %s: %w", subnetConfigPath, err) } } // end subnet config @@ -824,7 +824,7 @@ func RunSSHCheckAvalancheGoVersion(host *models.Host) ([]byte, error) { // RunSSHCheckBootstrapped checks if node is bootstrapped to primary network func RunSSHCheckBootstrapped(host *models.Host) ([]byte, error) { // Craft and send the HTTP POST request - requestBody := "{\"jsonrpc\":\"2.0\", \"id\":1,\"method\" :\"info.isBootstrapped\", \"params\": {\"chain\":\"X\"}}" + requestBody := "{\"jsonrpc\":\"2.0\", \"id\":1,\"method\" :\"info.isBootstrapped\", \"params\": {\"chain\":\"P\"}}" return PostOverSSH(host, "", requestBody) } diff --git a/pkg/subnet/deploy_status.go b/pkg/subnet/deploy_status.go index eecc8538c..879c4774d 100644 --- a/pkg/subnet/deploy_status.go +++ b/pkg/subnet/deploy_status.go @@ -27,7 +27,7 @@ func GetLocallyDeployedSubnetsFromFile(app *application.Avalanche) ([]string, er sc, err := app.LoadSidecar(subnetDir.Name()) if err == os.ErrNotExist { // don't fail on missing sidecar file, just warn - ux.Logger.PrintToUser("warning: inconsistent subnet directory. No sidecar file found for subnet %s", subnetDir.Name()) + ux.Logger.PrintToUser("warning: inconsistent subnet directory. No sidecar file found for blockchain %s", subnetDir.Name()) continue } if err != nil { diff --git a/pkg/subnet/errors.go b/pkg/subnet/errors.go index 512caf2a9..9cc4084d4 100644 --- a/pkg/subnet/errors.go +++ b/pkg/subnet/errors.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "regexp" + "slices" "strings" "github.com/ava-labs/avalanche-cli/pkg/ux" @@ -120,11 +121,5 @@ func removeTimestamp(s string) string { // if an error has already been found, we should not print it again func alreadyFound(s string, found []string) bool { log := removeTimestamp(s) - for _, f := range found { - // this is a pretty strict requirement, but probably justified - if f == log { - return true - } - } - return false + return slices.Contains(found, log) } diff --git a/pkg/subnet/helpers.go b/pkg/subnet/helpers.go index 332602b68..97e84dfeb 100644 --- a/pkg/subnet/helpers.go +++ b/pkg/subnet/helpers.go @@ -83,7 +83,7 @@ func ValidateSubnetNameAndGetChains(app *application.Avalanche, args []string) ( // this should not be necessary but some bright guy might just be creating // the genesis by hand or something... if err := checkInvalidSubnetNames(args[0]); err != nil { - return nil, fmt.Errorf("subnet name %s is invalid: %w", args[0], err) + return nil, fmt.Errorf("blockchain name %s is invalid: %w", args[0], err) } // Check subnet exists // TODO create a file that lists chains by subnet for fast querying @@ -93,7 +93,7 @@ func ValidateSubnetNameAndGetChains(app *application.Avalanche, args []string) ( } if len(chains) == 0 { - return nil, errors.New("Invalid subnet " + args[0]) + return nil, errors.New("Invalid blockchain " + args[0]) } return chains, nil diff --git a/pkg/subnet/public.go b/pkg/subnet/public.go index f25207686..cf20865bf 100644 --- a/pkg/subnet/public.go +++ b/pkg/subnet/public.go @@ -40,7 +40,7 @@ import ( const showFees = true -var ErrNoSubnetAuthKeysInWallet = errors.New("auth wallet does not contain subnet auth keys") +var ErrNoSubnetAuthKeysInWallet = errors.New("auth wallet does not contain auth keys") type PublicDeployer struct { LocalDeployer @@ -81,7 +81,7 @@ func (d *PublicDeployer) AddValidatorNonSOV( } subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return false, nil, nil, fmt.Errorf("failure parsing subnet auth keys: %w", err) + return false, nil, nil, fmt.Errorf("failure parsing auth keys: %w", err) } validator := &txs.SubnetValidator{ Validator: txs.Validator{ @@ -225,7 +225,7 @@ func (d *PublicDeployer) TransferSubnetOwnership( } subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return false, nil, nil, fmt.Errorf("failure parsing subnet auth keys: %w", err) + return false, nil, nil, fmt.Errorf("failure parsing auth keys: %w", err) } showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "TransferSubnetOwnership transaction") @@ -326,7 +326,7 @@ func (d *PublicDeployer) RemoveValidator( } subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return false, nil, nil, fmt.Errorf("failure parsing subnet auth keys: %w", err) + return false, nil, nil, fmt.Errorf("failure parsing auth keys: %w", err) } showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "tx hash") @@ -396,7 +396,7 @@ func (d *PublicDeployer) DeploySubnet( if err != nil { return ids.Empty, err } - ux.Logger.PrintToUser("Subnet has been created with ID: %s", subnetID.String()) + ux.Logger.PrintToUser("Blockchain has been created with ID: %s", subnetID.String()) time.Sleep(2 * time.Second) return subnetID, nil } @@ -428,7 +428,7 @@ func (d *PublicDeployer) DeployBlockchain( subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return false, ids.Empty, nil, nil, fmt.Errorf("failure parsing subnet auth keys: %w", err) + return false, ids.Empty, nil, nil, fmt.Errorf("failure parsing auth keys: %w", err) } showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "CreateChain transaction") @@ -472,7 +472,7 @@ func (d *PublicDeployer) ConvertL1( subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return false, ids.Empty, nil, nil, fmt.Errorf("failure parsing subnet auth keys: %w", err) + return false, ids.Empty, nil, nil, fmt.Errorf("failure parsing auth keys: %w", err) } showLedgerSignatureMsg(d.kc.UsesLedger, d.kc.HasOnlyOneKey(), "ConvertSubnetToL1Tx") @@ -544,7 +544,10 @@ func (d *PublicDeployer) Commit( repeats = 3 sleepBetweenRepeats = 2 * time.Second ) - var issueTxErr error + var ( + issueTxErr error + errors []error + ) wallet, err := d.loadCacheWallet() if err != nil { return ids.Empty, err @@ -565,12 +568,13 @@ func (d *PublicDeployer) Commit( } else { issueTxErr = fmt.Errorf("error issuing tx with ID %s: %w", tx.ID(), issueTxErr) } - ux.Logger.RedXToUser("%s", issueTxErr) + errors = append(errors, issueTxErr) time.Sleep(sleepBetweenRepeats) } if issueTxErr != nil { d.CleanCacheWallet() } + utils.PrintUnreportedErrors(errors, issueTxErr, ux.Logger.PrintToUser) return tx.ID(), issueTxErr } @@ -585,7 +589,7 @@ func (d *PublicDeployer) Sign( } subnetAuthKeys, err := address.ParseToIDs(subnetAuthKeysStrs) if err != nil { - return fmt.Errorf("failure parsing subnet auth keys: %w", err) + return fmt.Errorf("failure parsing auth keys: %w", err) } if ok := d.checkWalletHasSubnetAuthAddresses(subnetAuthKeys); !ok { return ErrNoSubnetAuthKeysInWallet diff --git a/pkg/txutils/info.go b/pkg/txutils/info.go index 4cd48b8d1..30bdae4da 100644 --- a/pkg/txutils/info.go +++ b/pkg/txutils/info.go @@ -111,13 +111,3 @@ func GetOwners(network models.Network, subnetID ids.ID) (bool, []string, uint32, } return isPermissioned, controlKeysStrs, threshold, nil } - -func GetValidatorPChainBalanceValidationID(network models.Network, validationID ids.ID) (uint64, error) { - pClient := platformvm.NewClient(network.Endpoint) - ctx := context.Background() - validatorResponse, _, err := pClient.GetL1Validator(ctx, validationID) - if err != nil { - return 0, err - } - return validatorResponse.Balance, nil -} diff --git a/pkg/utils/common.go b/pkg/utils/common.go index 26218b47e..5fd2ede67 100644 --- a/pkg/utils/common.go +++ b/pkg/utils/common.go @@ -27,6 +27,7 @@ import ( "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/txs" "github.com/ava-labs/subnet-evm/core" @@ -77,17 +78,22 @@ func SplitKeyValueStringToMap(str string, delimiter string) (map[string]string, // Context for ANR network operations func GetANRContext() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), constants.ANRRequestTimeout) + return GetTimedContext(constants.ANRRequestTimeout) } // Context for API requests func GetAPIContext() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), constants.APIRequestTimeout) + return GetTimedContext(constants.APIRequestTimeout) } // Context for API requests with large timeout func GetAPILargeContext() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), constants.APIRequestLargeTimeout) + return GetTimedContext(constants.APIRequestLargeTimeout) +} + +// Timed Context +func GetTimedContext(timeout time.Duration) (context.Context, context.CancelFunc) { + return context.WithTimeout(context.Background(), timeout) } func GetRealFilePath(path string) string { @@ -116,15 +122,6 @@ func Find[T any](input []T, f func(T) bool) *T { return nil } -func Belongs[T comparable](input []T, elem T) bool { - for _, e := range input { - if e == elem { - return true - } - } - return false -} - func RemoveFromSlice[T comparable](input []T, toRemove T) []T { output := make([]T, 0, len(input)) for _, e := range input { @@ -572,3 +569,55 @@ func IsValidSemanticVersion(version string, component string) bool { } return true } + +// PrintUnreportedErrors takes a list of errors obtained by a routine, and the main error +// it is going to report, and prints to the user the unreported errors only, +// avoiding duplications +func PrintUnreportedErrors( + errors []error, + returnedError error, + print func(string, ...interface{}), +) { + if returnedError == nil { + return + } + errSet := set.Set[string]{} + errSet.Add(returnedError.Error()) + for _, err := range errors { + if !errSet.Contains(err.Error()) { + print(err.Error()) + errSet.Add(err.Error()) + } + } +} + +func NewLogger( + logName string, + logLevelStr string, + defaultLogLevelStr string, + logDir string, + logToStdout bool, + print func(string, ...interface{}), +) (logging.Logger, error) { + logLevel, err := logging.ToLevel(logLevelStr) + if err != nil { + if logLevelStr != "" { + print("undefined logLevel %s. Setting %s log to %s", logLevelStr, logName, defaultLogLevelStr) + } + logLevel, err = logging.ToLevel(defaultLogLevelStr) + if err != nil { + return logging.NoLog{}, err + } + } + logConfig := logging.Config{ + RotatingWriterConfig: logging.RotatingWriterConfig{ + Directory: logDir, + }, + LogLevel: logLevel, + } + if logToStdout { + logConfig.DisplayLevel = logLevel + } + logFactory := logging.NewFactory(logConfig) + return logFactory.Make(logName) +} diff --git a/pkg/utils/file.go b/pkg/utils/file.go index 6d5a3c4a7..a3521d92a 100644 --- a/pkg/utils/file.go +++ b/pkg/utils/file.go @@ -97,7 +97,7 @@ func WriteStringToFile(filePath string, data string) error { return os.WriteFile(filePath, []byte(data), constants.WriteReadReadPerms) } -// Size returns the size of a file or directory. +// SizeInKB returns the size of a file or directory. func SizeInKB(path string) (int64, error) { var size int64 err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { diff --git a/pkg/utils/keys.go b/pkg/utils/keys.go index ff362a795..753953d93 100644 --- a/pkg/utils/keys.go +++ b/pkg/utils/keys.go @@ -9,6 +9,9 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/vms/platformvm" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" ) func GetKeyNames(keyDir string, addEwoq bool) ([]string, error) { @@ -52,3 +55,11 @@ func GetNetworkBalance(addressList []ids.ShortID, networkEndpoint string) (uint6 } return uint64(bal.Balance), nil } + +func PrivateKeyToAddress(privateKey string) (common.Address, error) { + pk, err := crypto.HexToECDSA(privateKey) + if err != nil { + return common.Address{}, err + } + return crypto.PubkeyToAddress(pk.PublicKey), nil +} diff --git a/pkg/utils/strings.go b/pkg/utils/strings.go index ad78d1377..501cd9170 100644 --- a/pkg/utils/strings.go +++ b/pkg/utils/strings.go @@ -23,7 +23,7 @@ func SplitComaSeparatedInt(s string) []int { }) } -// SplitString split string with a rune comma ignore quoted +// SplitStringWithQuotes split string with a rune comma ignore quoted func SplitStringWithQuotes(str string, r rune) []string { quoted := false return strings.FieldsFunc(str, func(r1 rune) bool { diff --git a/pkg/ux/table.go b/pkg/ux/table.go new file mode 100644 index 000000000..736f3e9be --- /dev/null +++ b/pkg/ux/table.go @@ -0,0 +1,20 @@ +// Copyright (C) 2022, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package ux + +import ( + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" +) + +func DefaultTable(title string, header table.Row) table.Writer { + t := table.NewWriter() + t.Style().Title.Align = text.AlignCenter + t.Style().Title.Format = text.FormatUpper + t.Style().Options.SeparateRows = true + t.SetTitle(title) + if header != nil { + t.AppendHeader(header) + } + return t +} diff --git a/pkg/validatormanager/registration.go b/pkg/validatormanager/registration.go index 7a675330d..3de8134d9 100644 --- a/pkg/validatormanager/registration.go +++ b/pkg/validatormanager/registration.go @@ -16,7 +16,8 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/sdk/interchain" - validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" + "github.com/ava-labs/avalanche-cli/sdk/validator" + "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/proto/pb/platformvm" @@ -84,7 +85,7 @@ func InitializeValidatorRegistrationPoSNative( managerAddress, stakeAmount, "initialize validator registration with stake", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "initializeValidatorRegistration((bytes,bytes,uint64,(uint32,[address]),(uint32,[address])),uint16,uint64)", validatorRegistrationInput, delegationFeeBips, @@ -140,7 +141,7 @@ func InitializeValidatorRegistrationPoA( managerAddress, big.NewInt(0), "initialize validator registration", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "initializeValidatorRegistration((bytes,bytes,uint64,(uint32,[address]),(uint32,[address])),uint64)", validatorRegistrationInput, weight, @@ -150,7 +151,7 @@ func InitializeValidatorRegistrationPoA( func GetSubnetValidatorRegistrationMessage( rpcURL string, network models.Network, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, aggregatorQuorumPercentage uint64, aggregatorAllowPrivateIPs bool, aggregatorExtraPeerEndpoints []info.Peer, @@ -171,7 +172,7 @@ func GetSubnetValidatorRegistrationMessage( err error ) if alreadyInitialized { - validationID, err = GetRegisteredValidator( + validationID, err = validator.GetRegisteredValidator( rpcURL, managerAddress, nodeID, @@ -222,7 +223,7 @@ func GetSubnetValidatorRegistrationMessage( } signatureAggregator, err := interchain.NewSignatureAggregator( network, - aggregatorLogLevel, + aggregatorLogger, subnetID, aggregatorQuorumPercentage, aggregatorAllowPrivateIPs, @@ -235,27 +236,6 @@ func GetSubnetValidatorRegistrationMessage( return signedMessage, validationID, err } -func GetRegisteredValidator( - rpcURL string, - managerAddress common.Address, - nodeID ids.NodeID, -) (ids.ID, error) { - out, err := contract.CallToMethod( - rpcURL, - managerAddress, - "registeredValidators(bytes)->(bytes32)", - nodeID[:], - ) - if err != nil { - return ids.Empty, err - } - validatorID, b := out[0].([32]byte) - if !b { - return ids.Empty, fmt.Errorf("error at registeredValidators call, expected [32]byte, got %T", out[0]) - } - return validatorID, nil -} - func GetValidatorWeight( rpcURL string, managerAddress common.Address, @@ -280,7 +260,7 @@ func GetValidatorWeight( func GetPChainSubnetValidatorRegistrationWarpMessage( network models.Network, rpcURL string, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, aggregatorQuorumPercentage uint64, aggregatorAllowPrivateIPs bool, aggregatorExtraPeerEndpoints []info.Peer, @@ -309,7 +289,7 @@ func GetPChainSubnetValidatorRegistrationWarpMessage( } signatureAggregator, err := interchain.NewSignatureAggregator( network, - aggregatorLogLevel, + aggregatorLogger, subnetID, aggregatorQuorumPercentage, aggregatorAllowPrivateIPs, @@ -342,7 +322,7 @@ func CompleteValidatorRegistration( subnetValidatorRegistrationSignedMessage, big.NewInt(0), "complete validator registration", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "completeValidatorRegistration(uint32)", uint32(0), ) @@ -362,7 +342,7 @@ func InitValidatorRegistration( weight uint64, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, initWithPos bool, delegationFee uint16, stakeDuration time.Duration, @@ -384,13 +364,13 @@ func InitValidatorRegistration( if err != nil { return nil, ids.Empty, err } - managerAddress := common.HexToAddress(validatorManagerSDK.ProxyContractAddress) + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) alreadyInitialized := false if initWithPos { ux.Logger.PrintLineSeparator() - ux.Logger.PrintToUser("Initializing a validator registration with PoS validator manager") - ux.Logger.PrintToUser("Using rpcURL: %s", rpcURL) - ux.Logger.PrintToUser("NodeID: %s staking %s for %ds", nodeID.String(), stakeAmount, uint64(stakeDuration.Seconds())) + ux.Logger.PrintToUser("Initializing validator registration with PoS validator manager") + ux.Logger.PrintToUser("Using RPC URL: %s", rpcURL) + ux.Logger.PrintToUser("NodeID: %s staking %s tokens", nodeID.String(), stakeAmount) ux.Logger.PrintLineSeparator() tx, _, err := InitializeValidatorRegistrationPoSNative( rpcURL, @@ -406,14 +386,14 @@ func InitValidatorRegistration( stakeAmount, ) if err != nil { - if !errors.Is(err, validatorManagerSDK.ErrNodeAlreadyRegistered) { + if !errors.Is(err, validatormanager.ErrNodeAlreadyRegistered) { return nil, ids.Empty, evm.TransactionError(tx, err, "failure initializing validator registration") } - ux.Logger.PrintToUser("the validator registration was already initialized. Proceeding to the next step") + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The validator registration was already initialized. Proceeding to the next step")) alreadyInitialized = true } } else { - managerAddress = common.HexToAddress(validatorManagerSDK.ProxyContractAddress) + managerAddress = common.HexToAddress(validatormanager.ProxyContractAddress) tx, _, err := InitializeValidatorRegistrationPoA( rpcURL, managerAddress, @@ -426,19 +406,15 @@ func InitValidatorRegistration( weight, ) if err != nil { - if !errors.Is(err, validatorManagerSDK.ErrNodeAlreadyRegistered) { + if !errors.Is(err, validatormanager.ErrNodeAlreadyRegistered) { return nil, ids.Empty, evm.TransactionError(tx, err, "failure initializing validator registration") } - ux.Logger.PrintToUser("the validator registration was already initialized. Proceeding to the next step") + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The validator registration was already initialized. Proceeding to the next step")) alreadyInitialized = true } } - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } if initWithPos { - validationID, err := GetRegisteredValidator(rpcURL, managerAddress, nodeID) + validationID, err := validator.GetRegisteredValidator(rpcURL, managerAddress, nodeID) if err != nil { ux.Logger.PrintToUser("Error getting validation ID") return nil, ids.Empty, err @@ -448,13 +424,15 @@ func InitValidatorRegistration( ux.Logger.PrintToUser("Error getting validator weight") return nil, ids.Empty, err } + } else { + // Print validator weight for POA only + ux.Logger.PrintToUser(fmt.Sprintf("Validator weight: %d", weight)) } - ux.Logger.PrintToUser(fmt.Sprintf("Validator weight: %d", weight)) return GetSubnetValidatorRegistrationMessage( rpcURL, network, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, @@ -480,7 +458,7 @@ func FinishValidatorRegistration( validationID ids.ID, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, ) error { subnetID, err := contract.GetSubnetID( app, @@ -490,15 +468,11 @@ func FinishValidatorRegistration( if err != nil { return err } - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } - managerAddress := common.HexToAddress(validatorManagerSDK.ProxyContractAddress) + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) signedMessage, err := GetPChainSubnetValidatorRegistrationWarpMessage( network, rpcURL, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, @@ -513,7 +487,7 @@ func FinishValidatorRegistration( rpcURL, privateKey, ); err != nil { - return err + ux.Logger.RedXToUser("failure setting proposer VM on L1: %w", err) } tx, _, err := CompleteValidatorRegistration( rpcURL, @@ -522,7 +496,11 @@ func FinishValidatorRegistration( signedMessage, ) if err != nil { - return evm.TransactionError(tx, err, "failure completing validator registration") + if !errors.Is(err, validatormanager.ErrInvalidValidationID) { + return evm.TransactionError(tx, err, "failure completing validator registration") + } else { + return fmt.Errorf("the Validator was already fully registered on the Manager") + } } return nil } diff --git a/pkg/validatormanager/removal.go b/pkg/validatormanager/removal.go index 0fcb492f6..db253cd07 100644 --- a/pkg/validatormanager/removal.go +++ b/pkg/validatormanager/removal.go @@ -5,6 +5,7 @@ package validatormanager import ( _ "embed" "errors" + "fmt" "math/big" "github.com/ava-labs/avalanche-cli/pkg/application" @@ -14,7 +15,8 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/avalanche-cli/sdk/interchain" - validatorManagerSDK "github.com/ava-labs/avalanche-cli/sdk/validatormanager" + "github.com/ava-labs/avalanche-cli/sdk/validator" + "github.com/ava-labs/avalanche-cli/sdk/validatormanager" "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" @@ -43,7 +45,7 @@ func InitializeValidatorRemoval( managerAddress, big.NewInt(0), "force POS validator removal", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "forceInitializeEndValidation(bytes32,bool,uint32)", validationID, false, // no uptime proof if force @@ -58,7 +60,7 @@ func InitializeValidatorRemoval( uptimeProofSignedMessage, big.NewInt(0), "POS validator removal with uptime proof", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "initializeEndValidation(bytes32,bool,uint32)", validationID, true, // submit uptime proof @@ -72,7 +74,7 @@ func InitializeValidatorRemoval( managerAddress, big.NewInt(0), "POA validator removal initialization", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "initializeEndValidation(bytes32)", validationID, ) @@ -80,7 +82,7 @@ func InitializeValidatorRemoval( func GetUptimeProofMessage( network models.Network, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, aggregatorQuorumPercentage uint64, aggregatorExtraPeerEndpoints []info.Peer, subnetID ids.ID, @@ -106,7 +108,7 @@ func GetUptimeProofMessage( } signatureAggregator, err := interchain.NewSignatureAggregator( network, - aggregatorLogLevel, + aggregatorLogger, subnetID, aggregatorQuorumPercentage, true, // allow private peers @@ -120,7 +122,7 @@ func GetUptimeProofMessage( func GetSubnetValidatorWeightMessage( network models.Network, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, aggregatorQuorumPercentage uint64, aggregatorAllowPrivateIPs bool, aggregatorExtraPeerEndpoints []info.Peer, @@ -156,7 +158,7 @@ func GetSubnetValidatorWeightMessage( } signatureAggregator, err := interchain.NewSignatureAggregator( network, - aggregatorLogLevel, + aggregatorLogger, subnetID, aggregatorQuorumPercentage, aggregatorAllowPrivateIPs, @@ -177,7 +179,7 @@ func InitValidatorRemoval( nodeID ids.NodeID, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, initWithPos bool, uptimeSec uint64, force bool, @@ -198,8 +200,8 @@ func InitValidatorRemoval( if err != nil { return nil, ids.Empty, err } - managerAddress := common.HexToAddress(validatorManagerSDK.ProxyContractAddress) - validationID, err := GetRegisteredValidator( + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) + validationID, err := validator.GetRegisteredValidator( rpcURL, managerAddress, nodeID, @@ -207,16 +209,12 @@ func InitValidatorRemoval( if err != nil { return nil, ids.Empty, err } - - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel + if validationID == ids.Empty { + return nil, ids.Empty, fmt.Errorf("node %s is not a L1 validator", nodeID) } + signedUptimeProof := &warp.Message{} if initWithPos { - if err != nil { - return nil, ids.Empty, evm.TransactionError(nil, err, "failure getting uptime data") - } if uptimeSec == 0 { uptimeSec, err = utils.GetL1ValidatorUptimeSeconds(rpcURL, nodeID) if err != nil { @@ -226,7 +224,7 @@ func InitValidatorRemoval( ux.Logger.PrintToUser("Using uptime: %ds", uptimeSec) signedUptimeProof, err = GetUptimeProofMessage( network, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorExtraPeerEndpoints, subnetID, @@ -248,16 +246,16 @@ func InitValidatorRemoval( force, ) if err != nil { - if !errors.Is(err, validatorManagerSDK.ErrInvalidValidatorStatus) { + if !errors.Is(err, validatormanager.ErrInvalidValidatorStatus) { return nil, ids.Empty, evm.TransactionError(tx, err, "failure initializing validator removal") } - ux.Logger.PrintToUser("the validator removal process was already initialized. Proceeding to the next step") + ux.Logger.PrintToUser(logging.LightBlue.Wrap("The validator removal process was already initialized. Proceeding to the next step")) } nonce := uint64(1) signedMsg, err := GetSubnetValidatorWeightMessage( network, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, @@ -284,7 +282,7 @@ func CompleteValidatorRemoval( subnetValidatorRegistrationSignedMessage, big.NewInt(0), "complete poa validator removal", - validatorManagerSDK.ErrorSignatureToError, + validatormanager.ErrorSignatureToError, "completeEndValidation(uint32)", uint32(0), ) @@ -299,9 +297,9 @@ func FinishValidatorRemoval( validationID ids.ID, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, ) error { - managerAddress := common.HexToAddress(validatorManagerSDK.ProxyContractAddress) + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) subnetID, err := contract.GetSubnetID( app, network, @@ -310,14 +308,10 @@ func FinishValidatorRemoval( if err != nil { return err } - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } signedMessage, err := GetPChainSubnetValidatorRegistrationWarpMessage( network, rpcURL, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, @@ -332,7 +326,7 @@ func FinishValidatorRemoval( rpcURL, privateKey, ); err != nil { - return err + ux.Logger.RedXToUser("failure setting proposer VM on L1: %w", err) } tx, _, err := CompleteValidatorRemoval( rpcURL, diff --git a/pkg/validatormanager/validatormanager.go b/pkg/validatormanager/validatormanager.go index fa9e1e0b5..a157b216d 100644 --- a/pkg/validatormanager/validatormanager.go +++ b/pkg/validatormanager/validatormanager.go @@ -16,10 +16,6 @@ import ( "github.com/ethereum/go-ethereum/common" ) -const ( - defaultAggregatorLogLevel = logging.Off -) - //go:embed deployed_poa_validator_manager_bytecode.txt var deployedPoAValidatorManagerBytecode []byte @@ -112,13 +108,15 @@ func SetupPoA( privateKey string, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, ) error { - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } - return subnet.InitializeProofOfAuthority(network, privateKey, aggregatorExtraPeerEndpoints, aggregatorAllowPrivatePeers, aggregatorLogLevel) + return subnet.InitializeProofOfAuthority( + network, + privateKey, + aggregatorExtraPeerEndpoints, + aggregatorAllowPrivatePeers, + aggregatorLogger, + ) } // setups PoA manager after a successful execution of @@ -132,18 +130,14 @@ func SetupPoS( privateKey string, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevelStr string, + aggregatorLogger logging.Logger, posParams validatorManagerSDK.PoSParams, ) error { - aggregatorLogLevel, err := logging.ToLevel(aggregatorLogLevelStr) - if err != nil { - aggregatorLogLevel = defaultAggregatorLogLevel - } return subnet.InitializeProofOfStake(network, privateKey, aggregatorExtraPeerEndpoints, aggregatorAllowPrivatePeers, - aggregatorLogLevel, + aggregatorLogger, posParams, ) } diff --git a/pkg/vm/allowlist.go b/pkg/vm/allowlist.go index 2a74c900d..72ac4ff5d 100644 --- a/pkg/vm/allowlist.go +++ b/pkg/vm/allowlist.go @@ -11,8 +11,9 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/application" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" - + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ethereum/go-ethereum/common" "github.com/olekukonko/tablewriter" "golang.org/x/mod/semver" @@ -59,11 +60,11 @@ func getNewAddresses( } for _, address := range addresses { switch { - case utils.Belongs(allowList.AdminAddresses, address): + case sdkUtils.Belongs(allowList.AdminAddresses, address): ux.Logger.RedXToUser(address.Hex() + " is already allowed as admin role") - case utils.Belongs(allowList.ManagerAddresses, address): + case sdkUtils.Belongs(allowList.ManagerAddresses, address): ux.Logger.RedXToUser(address.Hex() + " is already allowed as manager role") - case utils.Belongs(allowList.EnabledAddresses, address): + case sdkUtils.Belongs(allowList.EnabledAddresses, address): ux.Logger.RedXToUser(address.Hex() + " is already allowed as enabled role") default: newAddresses = append(newAddresses, address) diff --git a/pkg/vm/create_custom.go b/pkg/vm/create_custom.go index a49e6a2a5..f6e65ac1a 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -28,7 +28,7 @@ func CreateCustomSidecar( tokenSymbol string, sovereign bool, ) (*models.Sidecar, error) { - ux.Logger.PrintToUser("creating custom VM subnet %s", subnetName) + ux.Logger.PrintToUser("creating custom VM blockchain %s", subnetName) if sc == nil { sc = &models.Sidecar{} diff --git a/pkg/vm/descriptors.go b/pkg/vm/descriptors.go index 188cc2a7d..810ad3e6e 100644 --- a/pkg/vm/descriptors.go +++ b/pkg/vm/descriptors.go @@ -12,7 +12,7 @@ func getTokenSymbol(app *application.Avalanche, subnetEVMTokenSymbol string) (st if subnetEVMTokenSymbol != "" { return subnetEVMTokenSymbol, nil } - ux.Logger.PrintToUser("Select a symbol for your subnet's native token") + ux.Logger.PrintToUser("Select a symbol for your blockchain native token") tokenSymbol, err := app.Prompt.CaptureString("Token symbol") if err != nil { return "", err diff --git a/pkg/vm/evm_prompts.go b/pkg/vm/evm_prompts.go index 1eb7839f6..253311ea9 100644 --- a/pkg/vm/evm_prompts.go +++ b/pkg/vm/evm_prompts.go @@ -132,7 +132,7 @@ func PromptVMType( ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Subnet-EVM is an EVM-compatible virtual machine that supports smart contract development in Solidity. This VM is an out-of-the-box solution for Blockchain deployers who want a dApp development experience that is nearly identical to Ethereum, without having to manage or create a custom virtual machine. For more information, please visit: https://github.com/ava-labs/subnet-evm") ux.Logger.PrintToUser("") - ux.Logger.PrintToUser("Custom VMs are virtual machines created using SDKs such as Precompile-EVM, HyperSDK, Rust-SDK. For more information please visit: https://docs.avax.network/learn/avalanche/virtual-machines.") + ux.Logger.PrintToUser("Custom VMs are virtual machines created using SDKs such as Precompile-EVM, HyperSDK, Rust-SDK. For more information please visit: https://docs.avax.network/protocol/virtual-machines.") continue } break diff --git a/pkg/vm/precompiles.go b/pkg/vm/precompiles.go index fbd79bdab..6360f698a 100644 --- a/pkg/vm/precompiles.go +++ b/pkg/vm/precompiles.go @@ -4,7 +4,7 @@ package vm import ( - "github.com/ava-labs/avalanche-cli/pkg/utils" + sdkUtils "github.com/ava-labs/avalanche-cli/sdk/utils" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/allowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/deployerallowlist" @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/subnet-evm/precompile/contracts/txallowlist" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ava-labs/subnet-evm/precompile/precompileconfig" + "github.com/ethereum/go-ethereum/common" ) @@ -151,19 +152,19 @@ func addAddressToAllowed( ) allowlist.AllowListConfig { address := common.HexToAddress(addressStr) allowed := false - if utils.Belongs( + if sdkUtils.Belongs( allowListConfig.AdminAddresses, address, ) { allowed = true } - if utils.Belongs( + if sdkUtils.Belongs( allowListConfig.ManagerAddresses, address, ) { allowed = true } - if utils.Belongs( + if sdkUtils.Belongs( allowListConfig.EnabledAddresses, address, ) { diff --git a/sdk/SDK.md b/sdk/SDK.md new file mode 100644 index 000000000..9a88726d6 --- /dev/null +++ b/sdk/SDK.md @@ -0,0 +1,537 @@ +# SDK Documentation + +## Table of Contents + +- [blockchain](#blockchain) +- [constants](#constants) +- [interchain](#interchain) +- [key](#key) +- [keychain](#keychain) +- [ledger](#ledger) +- [multisig](#multisig) +- [network](#network) +- [publicarchive](#publicarchive) +- [utils](#utils) +- [validator](#validator) +- [validatormanager](#validatormanager) +- [vm](#vm) +- [wallet](#wallet) + +--- + +## blockchain + +### Functions + +#### New + +```go +func New(subnetParams *SubnetParams) (*Subnet, error) +``` + +#### TestSubnetDeploy + +```go +func TestSubnetDeploy(t *testing.T) +``` + +#### TestSubnetDeployLedger + +```go +func TestSubnetDeployLedger(t *testing.T) +``` + +#### TestSubnetDeployMultiSig + +```go +func TestSubnetDeployMultiSig(t *testing.T) +``` + +#### createEvmGenesis + +```go +func createEvmGenesis( + subnetEVMParams *SubnetEVMParams, +) ([]byte, error) +``` + +#### getDefaultSubnetEVMGenesis + +```go +func getDefaultSubnetEVMGenesis() (SubnetParams) +``` + +#### vmID + +```go +func vmID(vmName string) (ids.ID, error) +``` + +--- + +## constants + +### Functions + +--- + +## interchain + +### Functions + +#### NewSignatureAggregator + +```go +func NewSignatureAggregator( + network models.Network, + logger logging.Logger, + subnetID ids.ID, + quorumPercentage uint64, + allowPrivatePeers bool, + extraPeerEndpoints []info.Peer, +) (*SignatureAggregator, error) +``` + +#### TestSignatureAggregator + +```go +func TestSignatureAggregator(t *testing.T) +``` + +#### createAppRequestNetwork + +```go +func createAppRequestNetwork( + network models.Network, + logger logging.Logger, + registerer prometheus.Registerer, + allowPrivatePeers bool, + extraPeerEndpoints []info.Peer, +) (peers.AppRequestNetwork, error) +``` + +#### initSignatureAggregator + +```go +func initSignatureAggregator( + network peers.AppRequestNetwork, + logger logging.Logger, + registerer prometheus.Registerer, + subnetID ids.ID, + quorumPercentage uint64, +) (*SignatureAggregator, error) +``` + +#### instantiateAggregator + +```go +func instantiateAggregator(t *testing.T) ( + *SignatureAggregator, + *mocks.MockAppRequestNetwork, + error, +) +``` + +--- + +## key + +### Functions + +#### LoadSoft + +```go +func LoadSoft(keyPath string) (*SoftKey, error) +``` + +#### LoadSoftFromBytes + +```go +func LoadSoftFromBytes(kb []byte) (*SoftKey, error) +``` + +#### LoadSoftOrCreate + +```go +func LoadSoftOrCreate(keyPath string) (*SoftKey, error) +``` + +#### NewSoft + +```go +func NewSoft(opts ...SOpOption) (*SoftKey, error) +``` + +#### SortTransferableInputsWithSigners + +```go +func SortTransferableInputsWithSigners(ins []*avax.TransferableInput, signers [][]ids.ShortID) +``` + +#### TestNewKey + +```go +func TestNewKey(t *testing.T) +``` + +#### TestNewKeyEwoq + +```go +func TestNewKeyEwoq(t *testing.T) +``` + +#### WithPrivateKey + +```go +func WithPrivateKey(privKey *secp256k1.PrivateKey) (SOpOption) +``` + +#### WithPrivateKeyEncoded + +```go +func WithPrivateKeyEncoded(privKey string) (SOpOption) +``` + +#### checkKeyFileEnd + +```go +func checkKeyFileEnd(r io.ByteReader) (error) +``` + +#### decodePrivateKey + +```go +func decodePrivateKey(enc string) (*secp256k1.PrivateKey, error) +``` + +#### encodePrivateKey + +```go +func encodePrivateKey(pk *secp256k1.PrivateKey) (string, error) +``` + +#### readASCII + +```go +func readASCII(buf []byte, r io.ByteReader) (n int, err error) +``` + +--- + +## keychain + +### Functions + +#### NewKeychain + +```go +func NewKeychain( + network network.Network, + keyPath string, + ledgerInfo *LedgerParams, +) (*Keychain, error) +``` + +--- + +## ledger + +### Functions + +#### New + +```go +func New() (*LedgerDevice, error) +``` + +--- + +## multisig + +### Functions + +#### GetOwners + +```go +func GetOwners(network network.Network, subnetID ids.ID) ([]ids.ShortID, uint32, error) +``` + +#### New + +```go +func New(pChainTx *txs.Tx) (*Multisig) +``` + +--- + +## network + +### Functions + +#### FujiNetwork + +```go +func FujiNetwork() (Network) +``` + +#### MainnetNetwork + +```go +func MainnetNetwork() (Network) +``` + +#### NetworkFromNetworkID + +```go +func NetworkFromNetworkID(networkID uint32) (Network) +``` + +#### NewNetwork + +```go +func NewNetwork(kind NetworkKind, id uint32, endpoint string) (Network) +``` + +--- + +## publicarchive + +### Functions + +#### NewDownloader + +```go +func NewDownloader( + network network.Network, + logger logging.Logger, +) (Downloader, error) +``` + +#### TestDownloader_Download + +```go +func TestDownloader_Download(t *testing.T) +``` + +#### TestDownloader_EndToEnd + +```go +func TestDownloader_EndToEnd(t *testing.T) +``` + +#### TestDownloader_UnpackTo + +```go +func TestDownloader_UnpackTo(t *testing.T) +``` + +#### TestNewDownloader + +```go +func TestNewDownloader(t *testing.T) +``` + +#### TestNewGetter + +```go +func TestNewGetter(t *testing.T) +``` + +#### newGetter + +```go +func newGetter(endpoint string, target string) (Getter, error) +``` + +--- + +## utils + +### Functions + +#### DirExists + +```go +func DirExists(dirName string) (bool) +``` + +#### ExpandHome + +```go +func ExpandHome(path string) (string) +``` + +#### FileExists + +```go +func FileExists(filename string) (bool) +``` + +#### GetAPIContext + +```go +func GetAPIContext() (context.Context, context.CancelFunc) +``` + +#### GetAPILargeContext + +```go +func GetAPILargeContext() (context.Context, context.CancelFunc) +``` + +#### TestAppendSlices + +```go +func TestAppendSlices(t *testing.T) +``` + +#### TestExpandHome + +```go +func TestExpandHome(t *testing.T) +``` + +#### TestRetry + +```go +func TestRetry(t *testing.T) +``` + +#### Uint32Sort + +```go +func Uint32Sort(arr []uint32) +``` + +#### mockFunction + +```go +func mockFunction() (interface) +``` + +--- + +## validator + +### Functions + +#### GetRegisteredValidator + +```go +func GetRegisteredValidator( + rpcURL string, + managerAddress common.Address, + nodeID ids.NodeID, +) (ids.ID, error) +``` + +#### GetTotalWeight + +```go +func GetTotalWeight(net network.Network, subnetID ids.ID) (uint64, error) +``` + +#### GetValidationID + +```go +func GetValidationID(rpcURL string, nodeID ids.NodeID) (ids.ID, error) +``` + +#### GetValidatorBalance + +```go +func GetValidatorBalance(net network.Network, validationID ids.ID) (uint64, error) +``` + +#### GetValidatorInfo + +```go +func GetValidatorInfo(net network.Network, validationID ids.ID) (platformvm.L1Validator, error) +``` + +#### IsValidator + +```go +func IsValidator(net network.Network, subnetID ids.ID, nodeID ids.NodeID) (bool, error) +``` + +--- + +## validatormanager + +### Functions + +#### GetPChainSubnetConversionWarpMessage + +```go +func GetPChainSubnetConversionWarpMessage( + network models.Network, + aggregatorLogger logging.Logger, + aggregatorQuorumPercentage uint64, + aggregatorAllowPrivateIPs bool, + aggregatorExtraPeerEndpoints []info.Peer, + subnetID ids.ID, + managerBlockchainID ids.ID, + managerAddress common.Address, + convertSubnetValidators []*txs.ConvertSubnetToL1Validator, +) (*warp.Message, error) +``` + +#### InitializeValidatorsSet + +```go +func InitializeValidatorsSet( + rpcURL string, + managerAddress common.Address, + privateKey string, + subnetID ids.ID, + managerBlockchainID ids.ID, + convertSubnetValidators []*txs.ConvertSubnetToL1Validator, + subnetConversionSignedMessage *warp.Message, +) (*types.Transaction, *types.Receipt, error) +``` + +#### PoAValidatorManagerInitialize + +```go +func PoAValidatorManagerInitialize( + rpcURL string, + managerAddress common.Address, + privateKey string, + subnetID ids.ID, + ownerAddress common.Address, +) (*types.Transaction, *types.Receipt, error) +``` + +#### PoSValidatorManagerInitialize + +```go +func PoSValidatorManagerInitialize( + rpcURL string, + managerAddress common.Address, + privateKey string, + subnetID [32]byte, + posParams PoSParams, +) (*types.Transaction, *types.Receipt, error) +``` + +--- + +## vm + +### Functions + +--- + +## wallet + +### Functions + +#### New + +```go +func New(ctx context.Context, uri string, avaxKeychain avagokeychain.Keychain, config primary.WalletConfig) (Wallet, error) +``` + +--- + diff --git a/sdk/blockchain/blockchain.go b/sdk/blockchain/blockchain.go index 50bede649..892ce6bd9 100644 --- a/sdk/blockchain/blockchain.go +++ b/sdk/blockchain/blockchain.go @@ -346,7 +346,7 @@ func (c *Subnet) InitializeProofOfAuthority( privateKey string, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, ) error { if c.SubnetID == ids.Empty { return fmt.Errorf("unable to initialize Proof of Authority: %w", errMissingSubnetID) @@ -372,7 +372,7 @@ func (c *Subnet) InitializeProofOfAuthority( c.RPC, privateKey, ); err != nil { - return err + ux.Logger.RedXToUser("failure setting proposer VM on L1: %w", err) } managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) @@ -392,7 +392,7 @@ func (c *Subnet) InitializeProofOfAuthority( subnetConversionSignedMessage, err := validatormanager.GetPChainSubnetConversionWarpMessage( network, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, @@ -426,14 +426,14 @@ func (c *Subnet) InitializeProofOfStake( privateKey string, aggregatorExtraPeerEndpoints []info.Peer, aggregatorAllowPrivatePeers bool, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, posParams validatormanager.PoSParams, ) error { if err := evm.SetupProposerVM( c.RPC, privateKey, ); err != nil { - return err + ux.Logger.RedXToUser("failure setting proposer VM on L1: %w", err) } managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) tx, _, err := validatormanager.PoSValidatorManagerInitialize( @@ -451,7 +451,7 @@ func (c *Subnet) InitializeProofOfStake( } subnetConversionSignedMessage, err := validatormanager.GetPChainSubnetConversionWarpMessage( network, - aggregatorLogLevel, + aggregatorLogger, 0, aggregatorAllowPrivatePeers, aggregatorExtraPeerEndpoints, diff --git a/sdk/blockchain/deploy_subnet.go b/sdk/blockchain/deploy_subnet.go index d1cc58873..b80060c18 100644 --- a/sdk/blockchain/deploy_subnet.go +++ b/sdk/blockchain/deploy_subnet.go @@ -59,7 +59,7 @@ func (c *Subnet) CreateBlockchainTx(wallet wallet.Wallet) (*multisig.Multisig, e return nil, fmt.Errorf("vm ID is not provided") } if c.Name == "" { - return nil, fmt.Errorf("subnet name is not provided") + return nil, fmt.Errorf("blockchain name is not provided") } wallet.SetSubnetAuthMultisig(c.DeployInfo.SubnetAuthKeys) diff --git a/sdk/constants/constants.go b/sdk/constants/constants.go index d985e24b1..571651361 100644 --- a/sdk/constants/constants.go +++ b/sdk/constants/constants.go @@ -10,5 +10,6 @@ const ( APIRequestLargeTimeout = 2 * time.Minute // node - WriteReadUserOnlyPerms = 0o600 + UserOnlyWriteReadPerms = 0o600 + UserOnlyWriteReadExecPerms = 0o700 ) diff --git a/sdk/interchain/signature-aggregator.go b/sdk/interchain/signature-aggregator.go index 85764b84e..b5853ea53 100644 --- a/sdk/interchain/signature-aggregator.go +++ b/sdk/interchain/signature-aggregator.go @@ -5,13 +5,10 @@ package interchain import ( "encoding/hex" "fmt" - "os" - "time" "github.com/ava-labs/icm-services/signature-aggregator/aggregator" "github.com/ava-labs/icm-services/signature-aggregator/metrics" - "github.com/ava-labs/avalanche-cli/pkg/constants" "github.com/ava-labs/avalanche-cli/pkg/models" "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" @@ -49,13 +46,13 @@ type SignatureAggregator struct { // - error: An error if the creation of the AppRequestNetwork failed. func createAppRequestNetwork( network models.Network, - logLevel logging.Level, + logger logging.Logger, registerer prometheus.Registerer, allowPrivatePeers bool, extraPeerEndpoints []info.Peer, ) (peers.AppRequestNetwork, error) { peerNetwork, err := peers.NewNetwork( - logLevel, + logger, registerer, nil, extraPeerEndpoints, @@ -89,7 +86,6 @@ func initSignatureAggregator( registerer prometheus.Registerer, subnetID ids.ID, quorumPercentage uint64, - etnaTime time.Time, ) (*SignatureAggregator, error) { sa := &SignatureAggregator{} // set quorum percentage @@ -118,7 +114,6 @@ func initSignatureAggregator( messageCreator, DefaultSignatureCacheSize, metricsInstance, - etnaTime, ) if err != nil { return nil, fmt.Errorf("failed to create signature aggregator: %w", err) @@ -138,27 +133,18 @@ func initSignatureAggregator( // Returns a new signature aggregator instance, or an error if creation fails. func NewSignatureAggregator( network models.Network, - logLevel logging.Level, + logger logging.Logger, subnetID ids.ID, quorumPercentage uint64, allowPrivatePeers bool, extraPeerEndpoints []info.Peer, ) (*SignatureAggregator, error) { registerer := prometheus.NewRegistry() - peerNetwork, err := createAppRequestNetwork(network, logLevel, registerer, allowPrivatePeers, extraPeerEndpoints) + peerNetwork, err := createAppRequestNetwork(network, logger, registerer, allowPrivatePeers, extraPeerEndpoints) if err != nil { return nil, err } - logger := logging.NewLogger( - "init-aggregator", - logging.NewWrappedCore( - logLevel, - os.Stdout, - logging.JSON.ConsoleEncoder(), - ), - ) - etnaTime := constants.EtnaActivationTime[network.ID] - return initSignatureAggregator(peerNetwork, logger, registerer, subnetID, quorumPercentage, etnaTime) + return initSignatureAggregator(peerNetwork, logger, registerer, subnetID, quorumPercentage) } // AggregateSignatures aggregates signatures for a given message and justification. diff --git a/sdk/interchain/signature-aggregator_test.go b/sdk/interchain/signature-aggregator_test.go index ef373c8ce..a70507ad0 100644 --- a/sdk/interchain/signature-aggregator_test.go +++ b/sdk/interchain/signature-aggregator_test.go @@ -4,7 +4,6 @@ package interchain import ( "testing" - "time" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/logging" @@ -30,7 +29,6 @@ func instantiateAggregator(t *testing.T) ( prometheus.DefaultRegisterer, subnetID, DefaultQuorumPercentage, - time.Time{}, ) require.Equal(t, err, nil) return aggregator, mockNetwork, err diff --git a/sdk/key/soft_key.go b/sdk/key/soft_key.go index 9729748be..588e66a9b 100644 --- a/sdk/key/soft_key.go +++ b/sdk/key/soft_key.go @@ -280,7 +280,7 @@ func (m *SoftKey) PrivKeyHex() string { // Saves the private key to disk with hex encoding. func (m *SoftKey) Save(p string) error { - return os.WriteFile(p, []byte(m.PrivKeyHex()), constants.WriteReadUserOnlyPerms) + return os.WriteFile(p, []byte(m.PrivKeyHex()), constants.UserOnlyWriteReadPerms) } func (m *SoftKey) P(networkHRP string) (string, error) { diff --git a/sdk/publicarchive/README.md b/sdk/publicarchive/README.md new file mode 100644 index 000000000..84675ee04 --- /dev/null +++ b/sdk/publicarchive/README.md @@ -0,0 +1,55 @@ +# Public Archive Downloader SDK + +This Go package provides a utility to download and extract tar archives from public URLs. It's tailored for downloading Avalanche network archives but can be adapted for other use cases. + + +## Features + +* Downloads files from predefined URLs. +* Tracks download progress and logs status updates. +* Safely unpacks .tar archives to a target directory. +* Includes security checks to prevent path traversal and manage large files. + +## Usage example + +``` +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved +// See the file LICENSE for licensing terms. + +``` +package main + +import ( + "fmt" + "os" + + "github.com/ava-labs/avalanche-cli/sdk/network" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/your-repo-name/publicarchive" +) + +func main() { + // Initialize the downloader + downloader, err := publicarchive.NewDownloader(network.FujiNetwork(), logging.Debug) + if err != nil { + fmt.Printf("Failed to create downloader: %v\n", err) + os.Exit(1) + } + + // Start downloading + if err := downloader.Download(); err != nil { + fmt.Printf("Download failed: %v\n", err) + os.Exit(1) + } + + // Specify the target directory for unpacking + targetDir := "./extracted_files" + if err := downloader.UnpackTo(targetDir); err != nil { + fmt.Printf("Failed to unpack archive: %v\n", err) + os.Exit(1) + } + + fmt.Printf("Files successfully unpacked to %s\n", targetDir) +} +``` diff --git a/sdk/publicarchive/downloader.go b/sdk/publicarchive/downloader.go new file mode 100644 index 000000000..016738f04 --- /dev/null +++ b/sdk/publicarchive/downloader.go @@ -0,0 +1,262 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package publicarchive + +import ( + "archive/tar" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/ava-labs/avalanche-cli/sdk/constants" + "github.com/ava-labs/avalanche-cli/sdk/network" + avagoConstants "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/cavaliergopher/grab/v3" + "go.uber.org/zap" +) + +const ( + updateInterval = 500 * time.Millisecond + maxFileSize = 10 * 1024 * 1024 * 1024 // 10GB per file + // public archive + PChainArchiveFuji = "https://avalanchego-public-database.avax-test.network/testnet/p-chain/avalanchego/data-tar/latest.tar" +) + +type Getter struct { + client *grab.Client + request *grab.Request + size int64 + bytesComplete int64 + mutex *sync.RWMutex +} + +type Downloader struct { + getter Getter + logger logging.Logger + currentOp *sync.Mutex +} + +// newGetter returns a new Getter +func newGetter(endpoint string, target string) (Getter, error) { + if request, err := grab.NewRequest(target, endpoint); err != nil { + return Getter{}, err + } else { + return Getter{ + client: grab.NewClient(), + request: request, + size: 0, + bytesComplete: 0, + mutex: &sync.RWMutex{}, + }, nil + } +} + +// NewDownloader returns a new Downloader +// network: the network to download from ( fuji only). +// target: the path to download to +// logLevel: the log level +func NewDownloader( + network network.Network, + logger logging.Logger, +) (Downloader, error) { + tmpFile, err := os.CreateTemp("", "avalanche-cli-public-archive-*") + if err != nil { + return Downloader{}, err + } + + switch network.ID { + case avagoConstants.FujiID: + if getter, err := newGetter(PChainArchiveFuji, tmpFile.Name()); err != nil { + return Downloader{}, err + } else { + return Downloader{ + getter: getter, + logger: logger, + currentOp: &sync.Mutex{}, + }, nil + } + default: + return Downloader{}, fmt.Errorf("unsupported network ID: %d. Fuji only supported", network.ID) + } +} + +func (d Downloader) Download() error { + d.logger.Info("Download started from", zap.String("url", d.getter.request.URL().String())) + + d.currentOp.Lock() + defer d.currentOp.Unlock() + + resp := d.getter.client.Do(d.getter.request) + d.setDownloadSize(resp.Size()) + d.logger.Debug("Download response received", + zap.String("status", resp.HTTPResponse.Status)) + t := time.NewTicker(updateInterval) + defer t.Stop() + + done := make(chan struct{}) + go func() { + defer close(done) + for { + select { + case <-t.C: + d.setBytesComplete(resp.BytesComplete()) + d.logger.Info("Download progress", + zap.Int64("bytesComplete", d.GetBytesComplete()), + zap.Int64("size", d.GetDownloadSize())) + case <-resp.Done: + return + } + } + }() + <-resp.Done // Wait for the download to finish + t.Stop() // Stop the ticker + <-done + + // check for errors + if err := resp.Err(); err != nil { + d.logger.Error("Download failed", zap.Error(err)) + return err + } + + d.logger.Info("Download saved to", zap.String("path", d.getter.request.Filename)) + return nil +} + +func (d Downloader) UnpackTo(targetDir string) error { + d.currentOp.Lock() + defer d.currentOp.Unlock() + // prepare destination path + if err := os.MkdirAll(targetDir, constants.UserOnlyWriteReadExecPerms); err != nil { + d.logger.Error("Failed to create target directory", zap.Error(err)) + return err + } + tarFile, err := os.Open(d.getter.request.Filename) + if err != nil { + d.logger.Error("Failed to open tar file", zap.Error(err)) + return fmt.Errorf("failed to open tar file: %w", err) + } + defer tarFile.Close() + + tarReader := tar.NewReader(io.LimitReader(tarFile, maxFileSize)) + extractedSize := int64(0) + for { + // codeql [security] suppressed reason: This usage is safe in this context. + header, err := tarReader.Next() + if err == io.EOF { + d.logger.Debug("End of archive reached") + break // End of archive + } + if err != nil { + d.logger.Error("Failed to read tar archive", zap.Error(err)) + return fmt.Errorf("error reading tar archive: %w", err) + } + + relPath, err := filepath.Rel(targetDir, filepath.Join(targetDir, filepath.Clean(header.Name))) + if err != nil || strings.HasPrefix(relPath, "..") { + d.logger.Error("Invalid file path", zap.String("path", header.Name)) + return fmt.Errorf("invalid file path: %s", header.Name) + } + targetPath := filepath.Join(targetDir, relPath) + + // security checks + if extractedSize+header.Size > maxFileSize { + d.logger.Error("File too large", zap.String("path", header.Name), zap.Int64("size", header.Size)) + return fmt.Errorf("file too large: %s", header.Name) + } + if strings.Contains(header.Name, "..") { + d.logger.Error("Invalid file path", zap.String("path", header.Name)) + return fmt.Errorf("invalid file path: %s", header.Name) + } + // end of security checks + + switch header.Typeflag { + case tar.TypeDir: + d.logger.Debug("Creating directory", zap.String("path", targetPath)) + if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil { + d.logger.Error("Failed to create directory", zap.Error(err)) + return fmt.Errorf("failed to create directory: %w", err) + } + case tar.TypeReg: + d.logger.Debug("Ensure parent directory exists for ", zap.String("path", targetPath)) + if err := os.MkdirAll(filepath.Dir(targetPath), os.FileMode(0o755)); err != nil { + d.logger.Error("Failed to create parent directory for file", zap.Error(err)) + return fmt.Errorf("failed to create parent directory for file: %w", err) + } + d.logger.Debug("Creating file", zap.String("path", targetPath)) + outFile, err := os.Create(targetPath) + if err != nil { + d.logger.Error("Failed to create file", zap.Error(err)) + return fmt.Errorf("failed to create file: %w", err) + } + defer outFile.Close() + copied, err := io.CopyN(outFile, tarReader, header.Size) + if err != nil { + d.logger.Error("Failed to write file", zap.Error(err)) + return fmt.Errorf("failed to write file: %w", err) + } + if copied < header.Size { + d.logger.Error("Incomplete file write", zap.String("path", targetPath)) + return fmt.Errorf("incomplete file write for %s", targetPath) + } + extractedSize += header.Size + d.logger.Debug("Written bytes", zap.Int64("bytes", extractedSize)) + default: + d.logger.Debug("Skipping file", zap.String("path", targetPath)) + } + } + d.logger.Info("Download unpacked to", zap.String("path", targetDir)) + return nil +} + +// IsEmpty returns true if the Downloader is empty and not initialized +func (d Downloader) IsEmpty() bool { + return d.getter.client == nil +} + +// IsComplete returns true if the download is complete +func (d Downloader) IsComplete() bool { + return d.GetBytesComplete() == d.GetDownloadSize() +} + +func (d Downloader) GetFilePath() (string, error) { + if !d.IsComplete() { + return "", fmt.Errorf("download is not completed") + } + return d.getter.request.Filename, nil +} + +// GetDownloadSize returns the size of the download +func (d Downloader) GetDownloadSize() int64 { + d.getter.mutex.RLock() + defer d.getter.mutex.RUnlock() + return d.getter.size +} + +func (d Downloader) setDownloadSize(size int64) { + d.getter.mutex.Lock() + defer d.getter.mutex.Unlock() + d.getter.size = size +} + +// GetCurrentProgress returns the current download progress +func (d Downloader) GetBytesComplete() int64 { + d.getter.mutex.RLock() + defer d.getter.mutex.RUnlock() + return d.getter.bytesComplete +} + +func (d Downloader) setBytesComplete(progress int64) { + d.getter.mutex.Lock() + defer d.getter.mutex.Unlock() + d.getter.bytesComplete = progress +} + +func (d Downloader) CleanUp() { + _ = os.Remove(d.getter.request.Filename) +} diff --git a/sdk/publicarchive/downloader_test.go b/sdk/publicarchive/downloader_test.go new file mode 100644 index 000000000..8cb55c86d --- /dev/null +++ b/sdk/publicarchive/downloader_test.go @@ -0,0 +1,172 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package publicarchive + +import ( + "archive/tar" + "bytes" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "sync" + "testing" + + "github.com/cavaliergopher/grab/v3" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanche-cli/sdk/network" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/logging" +) + +func TestNewGetter(t *testing.T) { + endpoint := "http://example.com/file.tar" + target := "/tmp/file.tar" + + getter, err := newGetter(endpoint, target) + require.NoError(t, err, "newGetter should not return an error") + require.NotNil(t, getter.client, "getter client should not be nil") + require.NotNil(t, getter.request, "getter request should not be nil") + require.Equal(t, endpoint, getter.request.URL().String(), "getter request URL should match the input endpoint") +} + +func TestNewDownloader(t *testing.T) { + downloader, err := NewDownloader(network.Network{ID: constants.FujiID}, logging.NewLogger("public-archive-downloader", logging.NewWrappedCore(logging.Info, os.Stdout, logging.JSON.ConsoleEncoder()))) + require.NoError(t, err, "NewDownloader should not return an error") + require.NotNil(t, downloader.logger, "downloader logger should not be nil") + require.NotNil(t, downloader.getter.client, "downloader getter client should not be nil") +} + +func TestDownloader_Download(t *testing.T) { + // Mock server to simulate file download + mockData := []byte("mock file content") + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write(mockData) + })) + defer server.Close() + + // Create a temporary file for download target + tmpFile, err := os.CreateTemp("", "test-download-*") + require.NoError(t, err, "Temporary file creation failed") + defer os.Remove(tmpFile.Name()) + + // Ensure newGetter initializes properly + getter, err := newGetter(server.URL, tmpFile.Name()) + require.NoError(t, err, "Getter initialization failed") + + // Ensure the getter has a valid request + require.NotNil(t, getter.request, "Getter request is nil") + + // Initialize a no-op logger to avoid output + logger := logging.NoLog{} + downloader := Downloader{ + getter: getter, + logger: logger, + currentOp: &sync.Mutex{}, + } + + // Test the Download functionality + err = downloader.Download() + require.NoError(t, err, "Download should not return an error") + + // Validate the downloaded content + content, err := os.ReadFile(tmpFile.Name()) + require.NoError(t, err, "Reading downloaded file should not return an error") + require.Equal(t, mockData, content, "Downloaded file content should match the mock data") +} + +func TestDownloader_UnpackTo(t *testing.T) { + // Create a mock tar file + var buf bytes.Buffer + tarWriter := tar.NewWriter(&buf) + + files := []struct { + Name, Body string + }{ + {"file1.txt", "This is file1"}, + {"dir/file2.txt", "This is file2"}, + } + for _, file := range files { + header := &tar.Header{ + Name: file.Name, + Size: int64(len(file.Body)), + Mode: 0o600, + } + require.NoError(t, tarWriter.WriteHeader(header)) + _, err := tarWriter.Write([]byte(file.Body)) + require.NoError(t, err) + } + require.NoError(t, tarWriter.Close()) + + // Write tar file to a temporary file + tmpTar, err := os.CreateTemp("", "test-tar-*") + require.NoError(t, err) + defer os.Remove(tmpTar.Name()) + _, err = tmpTar.Write(buf.Bytes()) + require.NoError(t, err) + require.NoError(t, tmpTar.Close()) + + targetDir := t.TempDir() + + logger := logging.NoLog{} + downloader := Downloader{ + getter: Getter{ + request: &grab.Request{ + Filename: tmpTar.Name(), + }, + }, + logger: logger, + currentOp: &sync.Mutex{}, + } + + err = downloader.UnpackTo(targetDir) + require.NoError(t, err, "UnpackTo should not return an error") + + // Verify unpacked files + for _, file := range files { + filePath := filepath.Join(targetDir, file.Name) + content, err := os.ReadFile(filePath) + require.NoError(t, err, fmt.Sprintf("Reading file %s should not return an error", file.Name)) + require.Equal(t, file.Body, string(content), fmt.Sprintf("File content for %s should match", file.Name)) + } +} + +func TestDownloader_EndToEnd(t *testing.T) { + // Set up a temporary directory for testing + tmpDir := t.TempDir() + targetDir := filepath.Join(tmpDir, "extracted_files") + + // Configure the test network (Fuji in this case) + net := network.Network{ID: constants.FujiID} + + // Step 1: Create the downloader + downloader, err := NewDownloader(net, logging.NewLogger("public-archive-downloader", logging.NewWrappedCore(logging.Debug, os.Stdout, logging.JSON.ConsoleEncoder()))) + require.NoError(t, err, "Failed to initialize downloader") + + // Step 2: Start the download + t.Log("Starting download...") + err = downloader.Download() + require.NoError(t, err, "Download failed") + + // Step 3: Unpack the downloaded archive + t.Log("Unpacking downloaded archive...") + err = downloader.UnpackTo(targetDir) + require.NoError(t, err, "Failed to unpack archive") + + // Step 4: Validate the extracted files + t.Log("Validating extracted files...") + fileInfo, err := os.Stat(targetDir) + require.NoError(t, err, "Extracted directory does not exist") + require.True(t, fileInfo.IsDir(), "Extracted path is not a directory") + + // Check that at least one file is extracted + extractedFiles, err := os.ReadDir(targetDir) + require.NoError(t, err, "Failed to read extracted directory contents") + require.NotEmpty(t, extractedFiles, "No files extracted from archive") + + // Step 5: Clean up (optional since TempDir handles this automatically) + t.Log("Test completed successfully!") +} diff --git a/sdk/utils/utils.go b/sdk/utils/utils.go index 470705a01..35c4e0542 100644 --- a/sdk/utils/utils.go +++ b/sdk/utils/utils.go @@ -22,6 +22,15 @@ func Unique[T comparable](arr []T) []T { return unique } +func Belongs[T comparable](input []T, elem T) bool { + for _, e := range input { + if e == elem { + return true + } + } + return false +} + func Uint32Sort(arr []uint32) { sort.Slice(arr, func(i, j int) bool { return arr[i] < arr[j] }) } diff --git a/sdk/validator/validator.go b/sdk/validator/validator.go new file mode 100644 index 000000000..0f98d8587 --- /dev/null +++ b/sdk/validator/validator.go @@ -0,0 +1,92 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package validator + +import ( + "fmt" + + "github.com/ava-labs/avalanche-cli/pkg/contract" + "github.com/ava-labs/avalanche-cli/sdk/network" + "github.com/ava-labs/avalanche-cli/sdk/utils" + "github.com/ava-labs/avalanche-cli/sdk/validatormanager" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/vms/platformvm" + "github.com/ava-labs/avalanchego/vms/platformvm/api" + "github.com/ethereum/go-ethereum/common" + "golang.org/x/exp/maps" +) + +func GetTotalWeight(net network.Network, subnetID ids.ID) (uint64, error) { + pClient := platformvm.NewClient(net.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + validators, err := pClient.GetValidatorsAt(ctx, subnetID, api.ProposedHeight) + if err != nil { + return 0, err + } + weight := uint64(0) + for _, vdr := range validators { + weight += vdr.Weight + } + return weight, nil +} + +func IsValidator(net network.Network, subnetID ids.ID, nodeID ids.NodeID) (bool, error) { + pClient := platformvm.NewClient(net.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + validators, err := pClient.GetValidatorsAt(ctx, subnetID, api.ProposedHeight) + if err != nil { + return false, err + } + nodeIDs := maps.Keys(validators) + return utils.Belongs(nodeIDs, nodeID), nil +} + +func GetValidatorBalance(net network.Network, validationID ids.ID) (uint64, error) { + vdrInfo, err := GetValidatorInfo(net, validationID) + if err != nil { + return 0, err + } + return vdrInfo.Balance, nil +} + +func GetValidatorInfo(net network.Network, validationID ids.ID) (platformvm.L1Validator, error) { + pClient := platformvm.NewClient(net.Endpoint) + ctx, cancel := utils.GetAPIContext() + defer cancel() + vdrInfo, _, err := pClient.GetL1Validator(ctx, validationID) + if err != nil { + return platformvm.L1Validator{}, err + } + return vdrInfo, nil +} + +func GetValidationID(rpcURL string, nodeID ids.NodeID) (ids.ID, error) { + managerAddress := common.HexToAddress(validatormanager.ProxyContractAddress) + return GetRegisteredValidator(rpcURL, managerAddress, nodeID) +} + +func GetRegisteredValidator( + rpcURL string, + managerAddress common.Address, + nodeID ids.NodeID, +) (ids.ID, error) { + out, err := contract.CallToMethod( + rpcURL, + managerAddress, + "registeredValidators(bytes)->(bytes32)", + nodeID[:], + ) + if err != nil { + return ids.Empty, err + } + if len(out) == 0 { + return ids.Empty, fmt.Errorf("error at registeredValidators call, no value returned") + } + validatorID, typeIsOk := out[0].([32]byte) + if !typeIsOk { + return ids.Empty, fmt.Errorf("error at registeredValidators call, expected [32]byte, got %T", out[0]) + } + return validatorID, nil +} diff --git a/sdk/validatormanager/root.go b/sdk/validatormanager/root.go index 6e8bc5c2b..e00524fdc 100644 --- a/sdk/validatormanager/root.go +++ b/sdk/validatormanager/root.go @@ -94,6 +94,7 @@ var ( ErrValidatorIneligibleForRewards = fmt.Errorf("validator ineligible for rewards") ErrValidatorNotPoS = fmt.Errorf("validator not PoS") ErrZeroWeightToValueFactor = fmt.Errorf("zero weight to value factor") + ErrInvalidOwner = fmt.Errorf("invalid proxy or validator owner") ErrorSignatureToError = map[string]error{ "InvalidInitialization()": ErrAlreadyInitialized, "InvalidMaximumChurnPercentage(uint8)": ErrInvalidMaximumChurnPercentage, @@ -135,6 +136,8 @@ var ( "ValidatorIneligibleForRewards(bytes32)": ErrValidatorIneligibleForRewards, "ValidatorNotPoS(bytes32)": ErrValidatorNotPoS, "ZeroWeightToValueFactor()": ErrZeroWeightToValueFactor, + "OwnableInvalidOwner(address)": ErrInvalidOwner, + "OwnableUnauthorizedAccount(address)": ErrUnauthorizedOwner, } ) @@ -175,7 +178,7 @@ func (p PoSParams) Verify() error { // [managerAddress], and the initial list of [validators] func GetPChainSubnetConversionWarpMessage( network models.Network, - aggregatorLogLevel logging.Level, + aggregatorLogger logging.Logger, aggregatorQuorumPercentage uint64, aggregatorAllowPrivateIPs bool, aggregatorExtraPeerEndpoints []info.Peer, @@ -223,7 +226,7 @@ func GetPChainSubnetConversionWarpMessage( } signatureAggregator, err := interchain.NewSignatureAggregator( network, - aggregatorLogLevel, + aggregatorLogger, subnetID, aggregatorQuorumPercentage, aggregatorAllowPrivateIPs, diff --git a/tests/e2e/commands/constants.go b/tests/e2e/commands/constants.go index 007a70962..3c03b134b 100644 --- a/tests/e2e/commands/constants.go +++ b/tests/e2e/commands/constants.go @@ -5,7 +5,7 @@ package commands const ( CLIBinary = "./bin/avalanche" - SubnetCmd = "subnet" + SubnetCmd = "blockchain" NetworkCmd = "network" KeyCmd = "key" UpgradeCmd = "upgrade" diff --git a/tests/e2e/commands/subnet.go b/tests/e2e/commands/subnet.go index be680b797..37bce9390 100644 --- a/tests/e2e/commands/subnet.go +++ b/tests/e2e/commands/subnet.go @@ -682,7 +682,7 @@ func SimulateMultisigMainnetDeployNonSOV( "--mainnet", "--control-keys", strings.Join(subnetControlAddrs, ","), - "--subnet-auth-keys", + "--auth-keys", strings.Join(chainCreationAuthAddrs, ","), "--output-tx-path", txPath, @@ -722,7 +722,7 @@ func SimulateMultisigMainnetDeploySOV( bootstrapFilepathFlag + "=" + utils.BootstrapValidatorPath, "--control-keys", strings.Join(subnetControlAddrs, ","), - "--subnet-auth-keys", + "--auth-keys", strings.Join(chainCreationAuthAddrs, ","), "--output-tx-path", txPath, diff --git a/tests/e2e/hardhat/yarn.lock b/tests/e2e/hardhat/yarn.lock index 732b02705..49f4638b5 100644 --- a/tests/e2e/hardhat/yarn.lock +++ b/tests/e2e/hardhat/yarn.lock @@ -2580,7 +2580,7 @@ bn.js@^5.1.3, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@1.20.3: +body-parser@1.20.3, body-parser@^1.16.0: version "1.20.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== @@ -2598,24 +2598,6 @@ body-parser@1.20.3: type-is "~1.6.18" unpipe "1.0.0" -body-parser@^1.16.0: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -8371,13 +8353,6 @@ punycode@^2.1.1: resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.11.0, qs@^6.4.0, qs@^6.7.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - qs@6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" @@ -8385,6 +8360,13 @@ qs@6.13.0: dependencies: side-channel "^1.0.6" +qs@^6.4.0, qs@^6.7.0: + version "6.11.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.3" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" @@ -8429,16 +8411,6 @@ range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - raw-body@2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" diff --git a/tests/e2e/testcases/subnet/non-sov/public/suite.go b/tests/e2e/testcases/subnet/non-sov/public/suite.go index 5b8978639..b15c75c64 100644 --- a/tests/e2e/testcases/subnet/non-sov/public/suite.go +++ b/tests/e2e/testcases/subnet/non-sov/public/suite.go @@ -277,7 +277,7 @@ var _ = ginkgo.Describe("[Public Subnet non SOV]", func() { txPath, false, ) - toMatch = "(?s).+Ledger addresses:(?s).+ " + ledger1Addr + "(?s).+Subnet has been created with ID(?s).+" + //nolint:goconst + toMatch = "(?s).+Ledger addresses:(?s).+ " + ledger1Addr + "(?s).+Blockchain has been created with ID(?s).+" + //nolint:goconst "0 of 2 required Blockchain Creation signatures have been signed\\. Saving tx to disk to enable remaining signing\\.(?s).+" + "Addresses remaining to sign the tx\\s+" + ledger2Addr + "(?s).+" + ledger3Addr + "(?s).+" //nolint:goconst matched, err = regexp.MatchString(toMatch, cliutils.RemoveLineCleanChars(s)) diff --git a/tests/e2e/testcases/validatormanager/suite.go b/tests/e2e/testcases/validatormanager/suite.go index 30e2cfcc1..7b032d994 100644 --- a/tests/e2e/testcases/validatormanager/suite.go +++ b/tests/e2e/testcases/validatormanager/suite.go @@ -213,7 +213,7 @@ var _ = ginkgo.Describe("[Validator Manager POA Set Up]", ginkgo.Ordered, func() BootstrapValidators: avaGoBootstrapValidators, } - err = subnetSDK.InitializeProofOfAuthority(network, k.PrivKeyHex(), extraAggregatorPeers, true, logging.Off) + err = subnetSDK.InitializeProofOfAuthority(network, k.PrivKeyHex(), extraAggregatorPeers, true, logging.NoLog{}) gomega.Expect(err).Should(gomega.BeNil()) }) }) diff --git a/tests/e2e/utils/helpers.go b/tests/e2e/utils/helpers.go index b21c1fdb0..ed00364a0 100644 --- a/tests/e2e/utils/helpers.go +++ b/tests/e2e/utils/helpers.go @@ -332,6 +332,9 @@ func ParseRPCsFromOutput(output string) ([]string, error) { if !strings.Contains(line, "rpc") { continue } + if !strings.Contains(line, "http") { + continue + } startIndex := strings.Index(line, "http") if startIndex == -1 { return nil, fmt.Errorf("no url in RPC URL line: %s", line)