adm: Add commands to invoke methods of policy contract #868

Merged
acid-ant merged 2 commits from acid-ant/frostfs-node:bugfix/cmd-invoke-policy into master 2024-09-04 19:51:05 +00:00
8 changed files with 422 additions and 91 deletions

View file

@ -0,0 +1,162 @@
package morph
import (
"bytes"
"encoding/json"
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
const (
namespaceTarget = "namespace"
containerTarget = "container"
jsonFlag = "json"
jsonFlagDesc = "Output rule chains in JSON format"
chainIDFlag = "chain-id"
chainIDDesc = "Rule chain ID"
ruleFlag = "rule"
ruleFlagDesc = "Rule chain in text format"
ruleJSONFlag = "rule-json"
ruleJSONFlagDesc = "Chain rule in JSON format or path to the file"
targetNameFlag = "target-name"
targetNameDesc = "Resource name in APE resource name format"
targetTypeFlag = "target-type"
targetTypeDesc = "Resource type(container/namespace)"
)
var (
apeCmd = &cobra.Command{
Use: "ape",
Short: "Section for APE configuration commands",
}
addRuleChainCmd = &cobra.Command{
Use: "add-rule-chain",
Short: "Add rule chain",
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag))
},
Run: addRuleChain,
}
removeRuleChainCmd = &cobra.Command{
Use: "rm-rule-chain",
Short: "Remove rule chain",
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag))
},
Run: removeRuleChain,
}
listRuleChainsCmd = &cobra.Command{
Use: "list-rule-chains",
Short: "List rule chains",
PreRun: func(cmd *cobra.Command, _ []string) {
_ = viper.BindPFlag(endpointFlag, cmd.Flags().Lookup(endpointFlag))
_ = viper.BindPFlag(alphabetWalletsFlag, cmd.Flags().Lookup(alphabetWalletsFlag))
},
Run: listRuleChains,
}
)
func initAddRuleChainCmd() {
apeCmd.AddCommand(addRuleChainCmd)
addRuleChainCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
addRuleChainCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
addRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
_ = addRuleChainCmd.MarkFlagRequired(targetTypeFlag)
addRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
_ = addRuleChainCmd.MarkFlagRequired(targetNameFlag)
addRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
_ = addRuleChainCmd.MarkFlagRequired(chainIDFlag)
addRuleChainCmd.Flags().String(ruleFlag, "", ruleFlagDesc)
addRuleChainCmd.Flags().String(ruleJSONFlag, "", ruleJSONFlagDesc)
addRuleChainCmd.MarkFlagsMutuallyExclusive(ruleFlag, ruleJSONFlag)
}
func initRemoveRuleChainCmd() {
apeCmd.AddCommand(removeRuleChainCmd)
removeRuleChainCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
removeRuleChainCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
removeRuleChainCmd.Flags().String(targetTypeFlag, "", targetTypeDesc)
_ = removeRuleChainCmd.MarkFlagRequired(targetTypeFlag)
removeRuleChainCmd.Flags().String(targetNameFlag, "", targetNameDesc)
_ = removeRuleChainCmd.MarkFlagRequired(targetNameFlag)
removeRuleChainCmd.Flags().String(chainIDFlag, "", chainIDDesc)
_ = removeRuleChainCmd.MarkFlagRequired(chainIDFlag)
}
func initListRuleChainsCmd() {
apeCmd.AddCommand(listRuleChainsCmd)
listRuleChainsCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
listRuleChainsCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
listRuleChainsCmd.Flags().StringP(targetTypeFlag, "t", "", targetTypeDesc)
_ = listRuleChainsCmd.MarkFlagRequired(targetTypeFlag)
listRuleChainsCmd.Flags().String(targetNameFlag, "", targetNameDesc)
_ = listRuleChainsCmd.MarkFlagRequired(targetNameFlag)
listRuleChainsCmd.Flags().Bool(jsonFlag, false, jsonFlagDesc)
}
func addRuleChain(cmd *cobra.Command, _ []string) {
chain := parseChain(cmd)
target := parseTarget(cmd)
pci, ac := newPolicyContractInterface(cmd)
h, vub, err := pci.AddMorphRuleChain(apechain.Ingress, target, chain)
cmd.Println("Waiting for transaction to persist...")
_, err = ac.Wait(h, vub, err)
commonCmd.ExitOnErr(cmd, "add rule chain error: %w", err)
cmd.Println("Rule chain added successfully")
}
func removeRuleChain(cmd *cobra.Command, _ []string) {
chainID := parseChainID(cmd)
target := parseTarget(cmd)
pci, ac := newPolicyContractInterface(cmd)
h, vub, err := pci.RemoveMorphRuleChain(apechain.Ingress, target, chainID)
cmd.Println("Waiting for transaction to persist...")
_, err = ac.Wait(h, vub, err)
commonCmd.ExitOnErr(cmd, "remove rule chain error: %w", err)
cmd.Println("Rule chain removed successfully")
}
func listRuleChains(cmd *cobra.Command, _ []string) {
target := parseTarget(cmd)
pci, _ := newPolicyContractInterface(cmd)
chains, err := pci.ListMorphRuleChains(apechain.Ingress, target)
commonCmd.ExitOnErr(cmd, "list rule chains error: %w", err)
if len(chains) == 0 {
return
}
toJSON, _ := cmd.Flags().GetBool(jsonFlag)
if toJSON {
prettyJSONFormat(cmd, chains)
} else {
for _, c := range chains {
parseutil.PrintHumanReadableAPEChain(cmd, c)
}
}
}
func prettyJSONFormat(cmd *cobra.Command, chains []*apechain.Chain) {
wr := bytes.NewBufferString("")
data, err := json.Marshal(chains)
if err == nil {
err = json.Indent(wr, data, "", " ")
}
commonCmd.ExitOnErr(cmd, "print rule chain error: %w", err)
cmd.Println(wr)
}

View file

@ -0,0 +1,103 @@
package morph
import (
"encoding/json"
"fmt"
"os"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/config"
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/management"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func parseTarget(cmd *cobra.Command) policyengine.Target {
var targetType policyengine.TargetType
typ, _ := cmd.Flags().GetString(targetTypeFlag)
switch typ {
case namespaceTarget:
targetType = policyengine.Namespace
case containerTarget:
targetType = policyengine.Container
default:
commonCmd.ExitOnErr(cmd, "read target type error: %w", fmt.Errorf("unknown target type"))
}
name, _ := cmd.Flags().GetString(targetNameFlag)
return policyengine.Target{
Name: name,
Type: targetType,
}
}
func parseChainID(cmd *cobra.Command) apechain.ID {
chainID, _ := cmd.Flags().GetString(chainIDFlag)
if chainID == "" {
commonCmd.ExitOnErr(cmd, "read chain id error: %w",
fmt.Errorf("chain id cannot be empty"))
}
return apechain.ID(chainID)
}
func parseChain(cmd *cobra.Command) *apechain.Chain {
chain := new(apechain.Chain)
if ruleStmt, _ := cmd.Flags().GetString(ruleFlag); ruleStmt != "" {
parseErr := parseutil.ParseAPEChain(chain, []string{ruleStmt})
commonCmd.ExitOnErr(cmd, "ape chain parser error: %w", parseErr)
} else if ruleJSON, _ := cmd.Flags().GetString(ruleJSONFlag); ruleJSON != "" {
var rule []byte
if _, err := os.Stat(ruleJSON); err == nil {
rule, err = os.ReadFile(ruleJSON)
commonCmd.ExitOnErr(cmd, "read file error: %w", err)
} else {
rule = []byte(ruleJSON)
if !json.Valid(rule) {
commonCmd.ExitOnErr(cmd, "read raw rule error: %w",
fmt.Errorf("invalid JSON"))
}
}
err := chain.DecodeBytes(rule)
commonCmd.ExitOnErr(cmd, "chain decode error: %w", err)
} else {
commonCmd.ExitOnErr(cmd, "", fmt.Errorf("rule is not passed"))
}
chain.ID = parseChainID(cmd)
return chain
}
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *actor.Actor) {
v := viper.GetViper()
c, err := getN3Client(v)
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
walletDir := config.ResolveHomePath(viper.GetString(alphabetWalletsFlag))
wallets, err := getAlphabetWallets(v, walletDir)
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
committeeAcc, err := getWalletAccount(wallets[0], committeeAccountName)
commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
ac, err := newActor(c, committeeAcc)
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
inv := &ac.Invoker
var ch util.Uint160
r := management.NewReader(inv)
nnsCs, err := r.GetContractByID(1)
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
ch, err = nnsResolveHash(inv, nnsCs.Hash, policyContract+".frostfs")
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
return morph.NewContractStorage(ac, ch), ac
}

View file

@ -46,10 +46,10 @@ NNS name is taken by stripping '_contract.nef' from the NEF file (similar to fro
func init() { func init() {
ff := deployCmd.Flags() ff := deployCmd.Flags()
ff.String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") ff.String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
_ = deployCmd.MarkFlagFilename(alphabetWalletsFlag) _ = deployCmd.MarkFlagFilename(alphabetWalletsFlag)
ff.StringP(endpointFlag, "r", "", "N3 RPC node endpoint") ff.StringP(endpointFlag, "r", "", endpointFlagDesc)
ff.String(contractPathFlag, "", "Path to the contract directory") ff.String(contractPathFlag, "", "Path to the contract directory")
_ = deployCmd.MarkFlagFilename(contractPathFlag) _ = deployCmd.MarkFlagFilename(contractPathFlag)

View file

@ -4,12 +4,10 @@ import (
"errors" "errors"
"fmt" "fmt"
"os" "os"
"path/filepath"
"time" "time"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags" "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/cmd/frostfs-adm/internal/modules/config"
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring"
morphClient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/morph/client" 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/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state" "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) { func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContext, error) {
walletDir := config.ResolveHomePath(viper.GetString(alphabetWalletsFlag)) walletDir := config.ResolveHomePath(viper.GetString(alphabetWalletsFlag))
wallets, err := openAlphabetWallets(v, walletDir) wallets, err := getAlphabetWallets(v, walletDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if len(wallets) > maxAlphabetNodes {
return nil, ErrTooManyAlphabetNodes
}
needContracts := cmd.Name() == "update-contracts" || cmd.Name() == "init" needContracts := cmd.Name() == "update-contracts" || cmd.Name() == "init"
var w *wallet.Wallet var w *wallet.Wallet
@ -257,54 +251,6 @@ func createWalletAccounts(wallets []*wallet.Wallet) ([]*wallet.Account, error) {
return accounts, nil 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 { func (c *initializeContext) awaitTx() error {
return c.clientContext.awaitTx(c.Command) return c.clientContext.awaitTx(c.Command)
} }

View file

@ -73,13 +73,7 @@ func getN3Client(v *viper.Viper) (Client, error) {
} }
func defaultClientContext(c Client, committeeAcc *wallet.Account) (*clientContext, error) { func defaultClientContext(c Client, committeeAcc *wallet.Account) (*clientContext, error) {
commAct, err := actor.New(c, []actor.SignerAccount{{ commAct, err := newActor(c, committeeAcc)
Signer: transaction.Signer{
Account: committeeAcc.Contract.ScriptHash(),
Scopes: transaction.Global,
},
Account: committeeAcc,
}})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -7,8 +7,11 @@ import (
const ( const (
alphabetWalletsFlag = "alphabet-wallets" alphabetWalletsFlag = "alphabet-wallets"
alphabetWalletsFlagDesc = "Path to alphabet wallets dir"
alphabetSizeFlag = "size" alphabetSizeFlag = "size"
endpointFlag = "rpc-endpoint" endpointFlag = "rpc-endpoint"
endpointFlagDesc = "N3 RPC node endpoint"
endpointFlagShort = "r"
storageWalletFlag = "storage-wallet" storageWalletFlag = "storage-wallet"
storageWalletLabelFlag = "label" storageWalletLabelFlag = "label"
storageGasCLIFlag = "initial-gas" storageGasCLIFlag = "initial-gas"
@ -260,16 +263,20 @@ func init() {
initRefillGasCmd() initRefillGasCmd()
initDepositoryNotaryCmd() initDepositoryNotaryCmd()
initNetmapCandidatesCmd() initNetmapCandidatesCmd()
RootCmd.AddCommand(apeCmd)
initAddRuleChainCmd()
initRemoveRuleChainCmd()
initListRuleChainsCmd()
} }
func initNetmapCandidatesCmd() { func initNetmapCandidatesCmd() {
RootCmd.AddCommand(netmapCandidatesCmd) RootCmd.AddCommand(netmapCandidatesCmd)
netmapCandidatesCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") netmapCandidatesCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
} }
func initDepositoryNotaryCmd() { func initDepositoryNotaryCmd() {
RootCmd.AddCommand(depositNotaryCmd) 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(storageWalletFlag, "", "Path to storage node wallet")
depositNotaryCmd.Flags().String(walletAccountFlag, "", "Wallet account address") depositNotaryCmd.Flags().String(walletAccountFlag, "", "Wallet account address")
depositNotaryCmd.Flags().String(refillGasAmountFlag, "", "Amount of GAS to deposit") depositNotaryCmd.Flags().String(refillGasAmountFlag, "", "Amount of GAS to deposit")
@ -278,8 +285,8 @@ func initDepositoryNotaryCmd() {
func initRefillGasCmd() { func initRefillGasCmd() {
RootCmd.AddCommand(refillGasCmd) RootCmd.AddCommand(refillGasCmd)
refillGasCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") refillGasCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
refillGasCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") refillGasCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
refillGasCmd.Flags().String(storageWalletFlag, "", "Path to storage node wallet") refillGasCmd.Flags().String(storageWalletFlag, "", "Path to storage node wallet")
refillGasCmd.Flags().String(walletAddressFlag, "", "Address of wallet") refillGasCmd.Flags().String(walletAddressFlag, "", "Address of wallet")
refillGasCmd.Flags().String(refillGasAmountFlag, "", "Additional amount of GAS to transfer") refillGasCmd.Flags().String(refillGasAmountFlag, "", "Additional amount of GAS to transfer")
@ -288,21 +295,21 @@ func initRefillGasCmd() {
func initListContainersCmd() { func initListContainersCmd() {
RootCmd.AddCommand(listContainersCmd) 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)") listContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)")
} }
func initRestoreContainersCmd() { func initRestoreContainersCmd() {
RootCmd.AddCommand(restoreContainersCmd) RootCmd.AddCommand(restoreContainersCmd)
restoreContainersCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") restoreContainersCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
restoreContainersCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") restoreContainersCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
restoreContainersCmd.Flags().String(containerDumpFlag, "", "File to restore containers from") restoreContainersCmd.Flags().String(containerDumpFlag, "", "File to restore containers from")
restoreContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to restore") restoreContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to restore")
} }
func initDumpContainersCmd() { func initDumpContainersCmd() {
RootCmd.AddCommand(dumpContainersCmd) 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(containerDumpFlag, "", "File where to save dumped containers")
dumpContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)") dumpContainersCmd.Flags().String(containerContractFlag, "", "Container contract hash (for networks without NNS)")
dumpContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to dump") dumpContainersCmd.Flags().StringSlice(containerIDsFlag, nil, "Containers to dump")
@ -310,15 +317,15 @@ func initDumpContainersCmd() {
func initUpdateContractsCmd() { func initUpdateContractsCmd() {
RootCmd.AddCommand(updateContractsCmd) RootCmd.AddCommand(updateContractsCmd)
updateContractsCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") updateContractsCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
updateContractsCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") updateContractsCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
updateContractsCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts") updateContractsCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts")
_ = updateContractsCmd.MarkFlagRequired(contractsInitFlag) _ = updateContractsCmd.MarkFlagRequired(contractsInitFlag)
} }
func initDumpBalancesCmd() { func initDumpBalancesCmd() {
RootCmd.AddCommand(dumpBalancesCmd) 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(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(dumpBalancesAlphabetFlag, "a", false, "Dump balances of alphabet contracts")
dumpBalancesCmd.Flags().BoolP(dumpBalancesProxyFlag, "p", false, "Dump balances of the proxy contract") dumpBalancesCmd.Flags().BoolP(dumpBalancesProxyFlag, "p", false, "Dump balances of the proxy contract")
@ -327,53 +334,53 @@ func initDumpBalancesCmd() {
func initSetConfigCmd() { func initSetConfigCmd() {
RootCmd.AddCommand(setConfig) RootCmd.AddCommand(setConfig)
setConfig.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") setConfig.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
setConfig.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") setConfig.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
setConfig.Flags().Bool(forceConfigSet, false, "Force setting not well-known configuration key") setConfig.Flags().Bool(forceConfigSet, false, "Force setting not well-known configuration key")
setConfig.Flags().String(localDumpFlag, "", "Path to the blocks dump file") setConfig.Flags().String(localDumpFlag, "", "Path to the blocks dump file")
} }
func initDumpNetworkConfigCmd() { func initDumpNetworkConfigCmd() {
RootCmd.AddCommand(dumpNetworkConfigCmd) RootCmd.AddCommand(dumpNetworkConfigCmd)
dumpNetworkConfigCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") dumpNetworkConfigCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
} }
func initDumpContractHashesCmd() { func initDumpContractHashesCmd() {
RootCmd.AddCommand(dumpContractHashesCmd) 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.") dumpContractHashesCmd.Flags().String(customZoneFlag, "", "Custom zone to search.")
} }
func initSetPolicyCmd() { func initSetPolicyCmd() {
RootCmd.AddCommand(setPolicy) RootCmd.AddCommand(setPolicy)
setPolicy.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") setPolicy.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
setPolicy.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") setPolicy.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
setPolicy.Flags().String(localDumpFlag, "", "Path to the blocks dump file") setPolicy.Flags().String(localDumpFlag, "", "Path to the blocks dump file")
} }
func initDumpPolicyCmd() { func initDumpPolicyCmd() {
RootCmd.AddCommand(dumpPolicy) RootCmd.AddCommand(dumpPolicy)
dumpPolicy.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") dumpPolicy.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
} }
func initRemoveNodesCmd() { func initRemoveNodesCmd() {
RootCmd.AddCommand(removeNodes) RootCmd.AddCommand(removeNodes)
removeNodes.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") removeNodes.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
removeNodes.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") removeNodes.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
removeNodes.Flags().String(localDumpFlag, "", "Path to the blocks dump file") removeNodes.Flags().String(localDumpFlag, "", "Path to the blocks dump file")
} }
func initForceNewEpochCmd() { func initForceNewEpochCmd() {
RootCmd.AddCommand(forceNewEpoch) RootCmd.AddCommand(forceNewEpoch)
forceNewEpoch.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") forceNewEpoch.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
forceNewEpoch.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") forceNewEpoch.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
forceNewEpoch.Flags().String(localDumpFlag, "", "Path to the blocks dump file") forceNewEpoch.Flags().String(localDumpFlag, "", "Path to the blocks dump file")
} }
func initGenerateStorageCmd() { func initGenerateStorageCmd() {
RootCmd.AddCommand(generateStorageCmd) RootCmd.AddCommand(generateStorageCmd)
generateStorageCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") generateStorageCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
generateStorageCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") generateStorageCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
generateStorageCmd.Flags().String(storageWalletFlag, "", "Path to new storage node wallet") generateStorageCmd.Flags().String(storageWalletFlag, "", "Path to new storage node wallet")
generateStorageCmd.Flags().String(storageGasCLIFlag, "", "Initial amount of GAS to transfer") generateStorageCmd.Flags().String(storageGasCLIFlag, "", "Initial amount of GAS to transfer")
generateStorageCmd.Flags().StringP(storageWalletLabelFlag, "l", "", "Wallet label") generateStorageCmd.Flags().StringP(storageWalletLabelFlag, "l", "", "Wallet label")
@ -381,8 +388,8 @@ func initGenerateStorageCmd() {
func initInitCmd() { func initInitCmd() {
RootCmd.AddCommand(initCmd) RootCmd.AddCommand(initCmd)
initCmd.Flags().String(alphabetWalletsFlag, "", "Path to alphabet wallets dir") initCmd.Flags().String(alphabetWalletsFlag, "", alphabetWalletsFlagDesc)
initCmd.Flags().StringP(endpointFlag, "r", "", "N3 RPC node endpoint") initCmd.Flags().StringP(endpointFlag, endpointFlagShort, "", endpointFlagDesc)
initCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts") initCmd.Flags().String(contractsInitFlag, "", "Path to archive with compiled FrostFS contracts")
_ = initCmd.MarkFlagRequired(contractsInitFlag) _ = initCmd.MarkFlagRequired(contractsInitFlag)
initCmd.Flags().Uint(epochDurationCLIFlag, 240, "Amount of side chain blocks in one FrostFS epoch") initCmd.Flags().Uint(epochDurationCLIFlag, 240, "Amount of side chain blocks in one FrostFS epoch")
@ -397,7 +404,7 @@ func initInitCmd() {
func initGenerateAlphabetCmd() { func initGenerateAlphabetCmd() {
RootCmd.AddCommand(generateAlphabetCmd) 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") generateAlphabetCmd.Flags().Uint(alphabetSizeFlag, 7, "Amount of alphabet wallets to generate")
} }

View file

@ -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,
}})
}

View file

@ -3,11 +3,13 @@ package util
import ( import (
"errors" "errors"
"fmt" "fmt"
"strconv"
"strings" "strings"
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain" apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native" nativeschema "git.frostfs.info/TrueCloudLab/policy-engine/schema/native"
"github.com/flynn-archive/go-shlex" "github.com/flynn-archive/go-shlex"
"github.com/spf13/cobra"
) )
var ( var (
@ -20,6 +22,37 @@ var (
errUnknownCondObjectType = errors.New("condition object type is not recognized") errUnknownCondObjectType = errors.New("condition object type is not recognized")
) )
// PrintHumanReadableAPEChain print APE chain rules.
func PrintHumanReadableAPEChain(cmd *cobra.Command, chain *apechain.Chain) {
cmd.Println("ChainID: " + string(chain.ID))
cmd.Println("Rules:")
for _, rule := range chain.Rules {
cmd.Println("\tStatus: " + rule.Status.String())
cmd.Println("\tAny: " + strconv.FormatBool(rule.Any))
cmd.Println("\tConditions:")
for _, c := range rule.Condition {
var ot string
switch c.Object {
case apechain.ObjectResource:
ot = "Resource"
case apechain.ObjectRequest:
ot = "Request"
default:
panic("unknown object type")
}
cmd.Println(fmt.Sprintf("\t\t%s %s %s %s", ot, c.Key, c.Op, c.Value))
}
cmd.Println("\tActions:\tInverted:" + strconv.FormatBool(rule.Actions.Inverted))
for _, name := range rule.Actions.Names {
cmd.Println("\t\t" + name)
}
cmd.Println("\tResources:\tInverted:" + strconv.FormatBool(rule.Resources.Inverted))
for _, name := range rule.Resources.Names {
cmd.Println("\t\t" + name)
}
}
}
// ParseAPEChain parses APE chain rules. // ParseAPEChain parses APE chain rules.
func ParseAPEChain(chain *apechain.Chain, rules []string) error { func ParseAPEChain(chain *apechain.Chain, rules []string) error {
if len(rules) == 0 { if len(rules) == 0 {