package morph import ( "github.com/spf13/cobra" "github.com/spf13/viper" ) const ( alphabetWalletsFlag = "alphabet-wallets" alphabetWalletsFlagDesc = "Path to alphabet wallets dir" alphabetSizeFlag = "size" endpointFlag = "rpc-endpoint" endpointFlagDesc = "N3 RPC node endpoint" endpointFlagShort = "r" storageWalletFlag = "storage-wallet" storageWalletLabelFlag = "label" storageGasCLIFlag = "initial-gas" storageGasConfigFlag = "storage.initial_gas" contractsInitFlag = "contracts" maxObjectSizeInitFlag = "network.max_object_size" maxObjectSizeCLIFlag = "max-object-size" epochDurationInitFlag = "network.epoch_duration" epochDurationCLIFlag = "epoch-duration" containerFeeInitFlag = "network.fee.container" containerAliasFeeInitFlag = "network.fee.container_alias" containerFeeCLIFlag = "container-fee" containerAliasFeeCLIFlag = "container-alias-fee" candidateFeeInitFlag = "network.fee.candidate" candidateFeeCLIFlag = "candidate-fee" homomorphicHashDisabledInitFlag = "network.homomorphic_hash_disabled" maintenanceModeAllowedInitFlag = "network.maintenance_mode_allowed" homomorphicHashDisabledCLIFlag = "homomorphic-disabled" withdrawFeeInitFlag = "network.fee.withdraw" withdrawFeeCLIFlag = "withdraw-fee" containerDumpFlag = "dump" containerContractFlag = "container-contract" containerIDsFlag = "cid" refillGasAmountFlag = "gas" walletAccountFlag = "account" notaryDepositTillFlag = "till" localDumpFlag = "local-dump" protoConfigPath = "protocol" walletAddressFlag = "wallet-address" ) var ( // RootCmd is a root command of config section. RootCmd = &cobra.Command{ Use: "morph", Short: "Section for morph network configuration commands", } generateAlphabetCmd = &cobra.Command{ Use: "generate-alphabet", Short: "Generate alphabet wallets for consensus nodes of the morph network", PreRun: func(cmd *cobra.Command, _ []string) { // PreRun fixes https://github.com/spf13/viper/issues/233 _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) }, RunE: generateAlphabetCreds, } initCmd = &cobra.Command{ Use: "init", Short: "Initialize side chain network with smart-contracts and network settings", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) _ = viper.BindPFlag(epochDurationInitFlag, cmd.Flags().Lookup(epochDurationCLIFlag)) _ = viper.BindPFlag(maxObjectSizeInitFlag, cmd.Flags().Lookup(maxObjectSizeCLIFlag)) _ = viper.BindPFlag(homomorphicHashDisabledInitFlag, cmd.Flags().Lookup(homomorphicHashDisabledCLIFlag)) _ = viper.BindPFlag(candidateFeeInitFlag, cmd.Flags().Lookup(candidateFeeCLIFlag)) _ = viper.BindPFlag(containerFeeInitFlag, cmd.Flags().Lookup(containerFeeCLIFlag)) _ = viper.BindPFlag(containerAliasFeeInitFlag, cmd.Flags().Lookup(containerAliasFeeCLIFlag)) _ = viper.BindPFlag(withdrawFeeInitFlag, cmd.Flags().Lookup(withdrawFeeCLIFlag)) _ = viper.BindPFlag(protoConfigPath, cmd.Flags().Lookup(protoConfigPath)) }, RunE: initializeSideChainCmd, } generateStorageCmd = &cobra.Command{ Use: "generate-storage-wallet", Short: "Generate storage node wallet for the morph network", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) _ = viper.BindPFlag(storageGasConfigFlag, cmd.Flags().Lookup(storageGasCLIFlag)) }, RunE: generateStorageCreds, } refillGasCmd = &cobra.Command{ Use: "refill-gas", Short: "Refill GAS of storage node's wallet in the morph network", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) _ = viper.BindPFlag(refillGasAmountFlag, cmd.Flags().Lookup(refillGasAmountFlag)) }, RunE: func(cmd *cobra.Command, args []string) error { return refillGas(cmd, refillGasAmountFlag, false) }, } forceNewEpoch = &cobra.Command{ Use: "force-new-epoch", Short: "Create new FrostFS epoch event in the side chain", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: forceNewEpochCmd, } removeNodes = &cobra.Command{ Use: "remove-nodes key1 [key2 [...]]", Short: "Remove storage nodes from the netmap", Long: `Move nodes to the Offline state in the candidates list and tick an epoch to update the netmap`, PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: removeNodesCmd, } setConfig = &cobra.Command{ Use: "set-config key1=val1 [key2=val2 ...]", DisableFlagsInUseLine: true, Short: "Add/update global config value in the FrostFS network", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, Args: cobra.MinimumNArgs(1), RunE: setConfigCmd, } setPolicy = &cobra.Command{ Use: "set-policy [ExecFeeFactor=] [StoragePrice=] [FeePerByte=]", DisableFlagsInUseLine: true, Short: "Set global policy values", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: setPolicyCmd, ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"ExecFeeFactor=", "StoragePrice=", "FeePerByte="}, cobra.ShellCompDirectiveNoSpace }, } dumpPolicy = &cobra.Command{ Use: "dump-policy", Short: "Dump FrostFS policy", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: dumpPolicyCmd, } dumpContractHashesCmd = &cobra.Command{ Use: "dump-hashes", Short: "Dump deployed contract hashes", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: dumpContractHashes, } dumpNetworkConfigCmd = &cobra.Command{ Use: "dump-config", Short: "Dump FrostFS network config", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: dumpNetworkConfig, } dumpBalancesCmd = &cobra.Command{ Use: "dump-balances", Short: "Dump GAS balances", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: dumpBalances, } updateContractsCmd = &cobra.Command{ Use: "update-contracts", Short: "Update FrostFS contracts", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: updateContracts, } dumpContainersCmd = &cobra.Command{ Use: "dump-containers", Short: "Dump FrostFS containers to file", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: dumpContainers, } restoreContainersCmd = &cobra.Command{ Use: "restore-containers", Short: "Restore FrostFS containers from file", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: restoreContainers, } listContainersCmd = &cobra.Command{ Use: "list-containers", Short: "List FrostFS containers", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: listContainers, } depositNotaryCmd = &cobra.Command{ Use: "deposit-notary", Short: "Deposit GAS for notary service", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, RunE: depositNotary, } netmapCandidatesCmd = &cobra.Command{ Use: "netmap-candidates", Short: "List netmap candidates nodes", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) }, Run: listNetmapCandidatesNodes, } proxyAddAccountCmd = &cobra.Command{ Use: "proxy-add-account", Short: "Adds account to proxy contract", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, Run: addProxyAccount, } proxyRemoveAccountCmd = &cobra.Command{ Use: "proxy-remove-account", Short: "Remove from proxy contract", PreRun: func(cmd *cobra.Command, _ []string) { _ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag)) _ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag)) }, Run: removeProxyAccount, } ) func init() { initGenerateAlphabetCmd() initInitCmd() initDeployCmd() initGenerateStorageCmd() initForceNewEpochCmd() initRemoveNodesCmd() initSetPolicyCmd() initDumpPolicyCmd() initDumpContractHashesCmd() initDumpNetworkConfigCmd() initSetConfigCmd() initDumpBalancesCmd() initUpdateContractsCmd() initDumpContainersCmd() initRestoreContainersCmd() initListContainersCmd() initRefillGasCmd() initDepositoryNotaryCmd() initNetmapCandidatesCmd() RootCmd.AddCommand(apeCmd) initAddRuleChainCmd() initRemoveRuleChainCmd() initListRuleChainsCmd() initSetAdminCmd() initGetAdminCmd() initProxyAddAccount() initProxyRemoveAccount() } func initProxyAddAccount() { RootCmd.AddCommand(proxyAddAccountCmd) proxyAddAccountCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) proxyAddAccountCmd.Flags().String(accountAddressFlag, "", "Wallet address string") } func initProxyRemoveAccount() { RootCmd.AddCommand(proxyRemoveAccountCmd) proxyRemoveAccountCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) proxyRemoveAccountCmd.Flags().String(accountAddressFlag, "", "Wallet address string") } func initNetmapCandidatesCmd() { RootCmd.AddCommand(netmapCandidatesCmd) netmapCandidatesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initDepositoryNotaryCmd() { RootCmd.AddCommand(depositNotaryCmd) depositNotaryCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) depositNotaryCmd.Flags().String(storageWalletFlag, "", "Path to storage node wallet") depositNotaryCmd.Flags().String(walletAccountFlag, "", "Wallet account address") depositNotaryCmd.Flags().String(refillGasAmountFlag, "", "Amount of GAS to deposit") depositNotaryCmd.Flags().String(notaryDepositTillFlag, "", "Notary deposit duration in blocks") } func initRefillGasCmd() { RootCmd.AddCommand(refillGasCmd) refillGasCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) refillGasCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) refillGasCmd.Flags().String(storageWalletFlag, "", "Path to storage node wallet") refillGasCmd.Flags().String(walletAddressFlag, "", "Address of wallet") refillGasCmd.Flags().String(refillGasAmountFlag, "", "Additional amount of GAS to transfer") refillGasCmd.MarkFlagsMutuallyExclusive(walletAddressFlag, storageWalletFlag) } func initListContainersCmd() { RootCmd.AddCommand(listContainersCmd) listContainersCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) listContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)") } func initRestoreContainersCmd() { RootCmd.AddCommand(restoreContainersCmd) restoreContainersCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) restoreContainersCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) restoreContainersCmd.Flags().String(containerDumpFlag, "", "File to restore containers from") restoreContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to restore") } func initDumpContainersCmd() { RootCmd.AddCommand(dumpContainersCmd) dumpContainersCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) dumpContainersCmd.Flags().String(containerDumpFlag, "", "File where to save dumped containers") dumpContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)") dumpContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to dump") } func initUpdateContractsCmd() { RootCmd.AddCommand(updateContractsCmd) updateContractsCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) updateContractsCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) updateContractsCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts") _ = updateContractsCmd.MarkFlagRequired(contractsInitFlag) } func initDumpBalancesCmd() { RootCmd.AddCommand(dumpBalancesCmd) dumpBalancesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) dumpBalancesCmd.Flags().BoolP(dumpBalancesStorageFlag, "s", false, "Dump balances of storage nodes from the current netmap") dumpBalancesCmd.Flags().BoolP(dumpBalancesAlphabetFlag, "a", false, "Dump balances of alphabet contracts") dumpBalancesCmd.Flags().BoolP(dumpBalancesProxyFlag, "p", false, "Dump balances of the proxy contract") dumpBalancesCmd.Flags().Bool(dumpBalancesUseScriptHashFlag, false, "Use script-hash format for addresses") } func initSetConfigCmd() { RootCmd.AddCommand(setConfig) setConfig.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) setConfig.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) setConfig.Flags().Bool(forceConfigSet, false, "Force setting not well-known configuration key") setConfig.Flags().String(localDumpFlag, "", "Path to the blocks dump file") } func initDumpNetworkConfigCmd() { RootCmd.AddCommand(dumpNetworkConfigCmd) dumpNetworkConfigCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initDumpContractHashesCmd() { RootCmd.AddCommand(dumpContractHashesCmd) dumpContractHashesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) dumpContractHashesCmd.Flags().String(customZoneFlag, "", "Custom zone to search.") } func initSetPolicyCmd() { RootCmd.AddCommand(setPolicy) setPolicy.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) setPolicy.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) setPolicy.Flags().String(localDumpFlag, "", "Path to the blocks dump file") } func initDumpPolicyCmd() { RootCmd.AddCommand(dumpPolicy) dumpPolicy.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initRemoveNodesCmd() { RootCmd.AddCommand(removeNodes) removeNodes.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) removeNodes.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) removeNodes.Flags().String(localDumpFlag, "", "Path to the blocks dump file") } func initForceNewEpochCmd() { RootCmd.AddCommand(forceNewEpoch) forceNewEpoch.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) forceNewEpoch.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) forceNewEpoch.Flags().String(localDumpFlag, "", "Path to the blocks dump file") } func initGenerateStorageCmd() { RootCmd.AddCommand(generateStorageCmd) generateStorageCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) generateStorageCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) generateStorageCmd.Flags().String(storageWalletFlag, "", "Path to new storage node wallet") generateStorageCmd.Flags().String(storageGasCLIFlag, "", "Initial amount of GAS to transfer") generateStorageCmd.Flags().StringP(storageWalletLabelFlag, "l", "", "Wallet label") } func initInitCmd() { RootCmd.AddCommand(initCmd) initCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) initCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) initCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts") _ = initCmd.MarkFlagRequired(contractsInitFlag) initCmd.Flags().Uint(epochDurationCLIFlag, 240, "Amount of side chain blocks in one FrostFS epoch") initCmd.Flags().Uint(maxObjectSizeCLIFlag, 67108864, "Max single object size in bytes") initCmd.Flags().Bool(homomorphicHashDisabledCLIFlag, false, "Disable object homomorphic hashing") // Defaults are taken from neo-preodolenie. initCmd.Flags().Uint64(containerFeeCLIFlag, 1000, "Container registration fee") initCmd.Flags().Uint64(containerAliasFeeCLIFlag, 500, "Container alias fee") initCmd.Flags().String(protoConfigPath, "", "Path to the consensus node configuration") initCmd.Flags().String(localDumpFlag, "", "Path to the blocks dump file") } func initGenerateAlphabetCmd() { RootCmd.AddCommand(generateAlphabetCmd) generateAlphabetCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) generateAlphabetCmd.Flags().Uint(alphabetSizeFlag, 7, "Amount of alphabet wallets to generate") } func initDeployCmd() { RootCmd.AddCommand(deployCmd) }