From 7ade11922e2d8bfe014ba34125f619c87ffe423f Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Wed, 20 Dec 2023 15:22:17 +0300 Subject: [PATCH] [#834] adm: Refactor `morph` module Signed-off-by: Anton Nikiforov --- .../internal/modules/morph/deploy.go | 4 +- .../internal/modules/morph/initialize.go | 56 +----------- .../internal/modules/morph/n3client.go | 8 +- .../internal/modules/morph/root.go | 57 ++++++------ .../internal/modules/morph/util.go | 86 +++++++++++++++++++ 5 files changed, 120 insertions(+), 91 deletions(-) create mode 100644 cmd/frostfs-adm/internal/modules/morph/util.go diff --git a/cmd/frostfs-adm/internal/modules/morph/deploy.go b/cmd/frostfs-adm/internal/modules/morph/deploy.go index 54b50671..1facd6d1 100644 --- a/cmd/frostfs-adm/internal/modules/morph/deploy.go +++ b/cmd/frostfs-adm/internal/modules/morph/deploy.go @@ -46,10 +46,10 @@ NNS name is taken by stripping '_contract.nef' from the NEF file (similar to fro func init() { ff := deployCmd.Flags() - ff.String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") + ff.String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) _ = deployCmd.MarkFlagFilename(alphabetWalletsFlag) - ff.StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + ff.StringP(endpointFlag, "r", "", endpointFlagDesc) ff.String(contractPathFlag, "", "Path to the contract directory") _ = deployCmd.MarkFlagFilename(contractPathFlag) diff --git a/cmd/frostfs-adm/internal/modules/morph/initialize.go b/cmd/frostfs-adm/internal/modules/morph/initialize.go index 96100ffb..78356e6b 100644 --- a/cmd/frostfs-adm/internal/modules/morph/initialize.go +++ b/cmd/frostfs-adm/internal/modules/morph/initialize.go @@ -4,12 +4,10 @@ import ( "errors" "fmt" "os" - "path/filepath" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring" morphClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" "github.com/nspcc-dev/neo-go/pkg/core/state" @@ -117,15 +115,11 @@ func (c *initializeContext) close() { func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContext, error) { walletDir := config.ResolveHomePath(viper.GetString(alphabetWalletsFlag)) - wallets, err := openAlphabetWallets(v, walletDir) + wallets, err := getAlphabetWallets(v, walletDir) if err != nil { return nil, err } - if len(wallets) > maxAlphabetNodes { - return nil, ErrTooManyAlphabetNodes - } - needContracts := cmd.Name() == "update-contracts" || cmd.Name() == "init" var w *wallet.Wallet @@ -257,54 +251,6 @@ func createWalletAccounts(wallets []*wallet.Wallet) ([]*wallet.Account, error) { return accounts, nil } -func openAlphabetWallets(v *viper.Viper, walletDir string) ([]*wallet.Wallet, error) { - walletFiles, err := os.ReadDir(walletDir) - if err != nil { - return nil, fmt.Errorf("can't read alphabet wallets dir: %w", err) - } - - var size int -loop: - for i := 0; i < len(walletFiles); i++ { - name := innerring.GlagoliticLetter(i).String() + ".json" - for j := range walletFiles { - if walletFiles[j].Name() == name { - size++ - continue loop - } - } - break - } - if size == 0 { - return nil, errors.New("alphabet wallets dir is empty (run `generate-alphabet` command first)") - } - - wallets := make([]*wallet.Wallet, size) - for i := 0; i < size; i++ { - letter := innerring.GlagoliticLetter(i).String() - p := filepath.Join(walletDir, letter+".json") - w, err := wallet.NewWalletFromFile(p) - if err != nil { - return nil, fmt.Errorf("can't open wallet: %w", err) - } - - password, err := config.GetPassword(v, letter) - if err != nil { - return nil, fmt.Errorf("can't fetch password: %w", err) - } - - for i := range w.Accounts { - if err := w.Accounts[i].Decrypt(password, keys.NEP2ScryptParams()); err != nil { - return nil, fmt.Errorf("can't unlock wallet: %w", err) - } - } - - wallets[i] = w - } - - return wallets, nil -} - func (c *initializeContext) awaitTx() error { return c.clientContext.awaitTx(c.Command) } diff --git a/cmd/frostfs-adm/internal/modules/morph/n3client.go b/cmd/frostfs-adm/internal/modules/morph/n3client.go index 3550895c..584bb852 100644 --- a/cmd/frostfs-adm/internal/modules/morph/n3client.go +++ b/cmd/frostfs-adm/internal/modules/morph/n3client.go @@ -73,13 +73,7 @@ func getN3Client(v *viper.Viper) (Client, error) { } func defaultClientContext(c Client, committeeAcc *wallet.Account) (*clientContext, error) { - commAct, err := actor.New(c, []actor.SignerAccount{{ - Signer: transaction.Signer{ - Account: committeeAcc.Contract.ScriptHash(), - Scopes: transaction.Global, - }, - Account: committeeAcc, - }}) + commAct, err := newActor(c, committeeAcc) if err != nil { return nil, err } diff --git a/cmd/frostfs-adm/internal/modules/morph/root.go b/cmd/frostfs-adm/internal/modules/morph/root.go index 707ae733..1a0cd8c8 100644 --- a/cmd/frostfs-adm/internal/modules/morph/root.go +++ b/cmd/frostfs-adm/internal/modules/morph/root.go @@ -7,8 +7,11 @@ import ( 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" @@ -264,12 +267,12 @@ func init() { func initNetmapCandidatesCmd() { RootCmd.AddCommand(netmapCandidatesCmd) - netmapCandidatesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + netmapCandidatesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initDepositoryNotaryCmd() { RootCmd.AddCommand(depositNotaryCmd) - depositNotaryCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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") @@ -278,8 +281,8 @@ func initDepositoryNotaryCmd() { func initRefillGasCmd() { RootCmd.AddCommand(refillGasCmd) - refillGasCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - refillGasCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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") @@ -288,21 +291,21 @@ func initRefillGasCmd() { func initListContainersCmd() { RootCmd.AddCommand(listContainersCmd) - listContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "", "Path to alphabet wallets dir") - restoreContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "r", "", "N3 RPC node endpoint") + 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") @@ -310,15 +313,15 @@ func initDumpContainersCmd() { func initUpdateContractsCmd() { RootCmd.AddCommand(updateContractsCmd) - updateContractsCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - updateContractsCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "r", "", "N3 RPC node endpoint") + 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") @@ -327,53 +330,53 @@ func initDumpBalancesCmd() { func initSetConfigCmd() { RootCmd.AddCommand(setConfig) - setConfig.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - setConfig.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "r", "", "N3 RPC node endpoint") + dumpNetworkConfigCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initDumpContractHashesCmd() { RootCmd.AddCommand(dumpContractHashesCmd) - dumpContractHashesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + dumpContractHashesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) dumpContractHashesCmd.Flags().String(customZoneFlag, "", "Custom zone to search.") } func initSetPolicyCmd() { RootCmd.AddCommand(setPolicy) - setPolicy.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - setPolicy.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "r", "", "N3 RPC node endpoint") + dumpPolicy.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc) } func initRemoveNodesCmd() { RootCmd.AddCommand(removeNodes) - removeNodes.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - removeNodes.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "", "Path to alphabet wallets dir") - forceNewEpoch.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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, "", "Path to alphabet wallets dir") - generateStorageCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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") @@ -381,8 +384,8 @@ func initGenerateStorageCmd() { func initInitCmd() { RootCmd.AddCommand(initCmd) - initCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") - initCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") + 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") @@ -397,7 +400,7 @@ func initInitCmd() { func initGenerateAlphabetCmd() { RootCmd.AddCommand(generateAlphabetCmd) - generateAlphabetCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") + generateAlphabetCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc) generateAlphabetCmd.Flags().Uint(alphabetSizeFlag, 7, "Amount of alphabet wallets to generate") } diff --git a/cmd/frostfs-adm/internal/modules/morph/util.go b/cmd/frostfs-adm/internal/modules/morph/util.go new file mode 100644 index 00000000..8b5489ab --- /dev/null +++ b/cmd/frostfs-adm/internal/modules/morph/util.go @@ -0,0 +1,86 @@ +package morph + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config" + "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" + "github.com/nspcc-dev/neo-go/pkg/wallet" + "github.com/spf13/viper" +) + +func getAlphabetWallets(v *viper.Viper, walletDir string) ([]*wallet.Wallet, error) { + wallets, err := openAlphabetWallets(v, walletDir) + if err != nil { + return nil, err + } + + if len(wallets) > maxAlphabetNodes { + return nil, ErrTooManyAlphabetNodes + } + return wallets, nil +} + +func openAlphabetWallets(v *viper.Viper, walletDir string) ([]*wallet.Wallet, error) { + walletFiles, err := os.ReadDir(walletDir) + if err != nil { + return nil, fmt.Errorf("can't read alphabet wallets dir: %w", err) + } + + var size int +loop: + for i := 0; i < len(walletFiles); i++ { + name := innerring.GlagoliticLetter(i).String() + ".json" + for j := range walletFiles { + if walletFiles[j].Name() == name { + size++ + continue loop + } + } + break + } + if size == 0 { + return nil, errors.New("alphabet wallets dir is empty (run `generate-alphabet` command first)") + } + + wallets := make([]*wallet.Wallet, size) + for i := 0; i < size; i++ { + letter := innerring.GlagoliticLetter(i).String() + p := filepath.Join(walletDir, letter+".json") + w, err := wallet.NewWalletFromFile(p) + if err != nil { + return nil, fmt.Errorf("can't open wallet: %w", err) + } + + password, err := config.GetPassword(v, letter) + if err != nil { + return nil, fmt.Errorf("can't fetch password: %w", err) + } + + for i := range w.Accounts { + if err := w.Accounts[i].Decrypt(password, keys.NEP2ScryptParams()); err != nil { + return nil, fmt.Errorf("can't unlock wallet: %w", err) + } + } + + wallets[i] = w + } + + return wallets, nil +} + +func newActor(c actor.RPCActor, committeeAcc *wallet.Account) (*actor.Actor, error) { + return actor.New(c, []actor.SignerAccount{{ + Signer: transaction.Signer{ + Account: committeeAcc.Contract.ScriptHash(), + Scopes: transaction.Global, + }, + Account: committeeAcc, + }}) +}