adm: Add commands to manipulate with NNS
contract #981
15 changed files with 618 additions and 23 deletions
|
@ -4,8 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"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/morph/constants"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||||
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
parseutil "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/modules/util"
|
||||||
|
@ -13,7 +11,6 @@ import (
|
||||||
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
apechain "git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
policyengine "git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
morph "git.frostfs.info/TrueCloudLab/policy-engine/pkg/morph/policy"
|
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/rpcclient/management"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -86,28 +83,19 @@ func parseChainName(cmd *cobra.Command) apechain.Name {
|
||||||
return apeChainName
|
return apeChainName
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *actor.Actor) {
|
func newPolicyContractInterface(cmd *cobra.Command) (*morph.ContractStorage, *helper.LocalActor) {
|
||||||
v := viper.GetViper()
|
c, err := helper.GetN3Client(viper.GetViper())
|
||||||
c, err := helper.GetN3Client(v)
|
|
||||||
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||||
|
|
||||||
walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
|
ac, err := helper.NewLocalActor(cmd, c)
|
||||||
wallets, err := helper.GetAlphabetWallets(v, walletDir)
|
|
||||||
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
|
|
||||||
|
|
||||||
committeeAcc, err := helper.GetWalletAccount(wallets[0], constants.CommitteeAccountName)
|
|
||||||
commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
|
|
||||||
|
|
||||||
ac, err := helper.NewActor(c, committeeAcc)
|
|
||||||
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
|
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
|
||||||
|
|
||||||
inv := &ac.Invoker
|
|
||||||
var ch util.Uint160
|
var ch util.Uint160
|
||||||
r := management.NewReader(inv)
|
r := management.NewReader(ac.Invoker)
|
||||||
nnsCs, err := r.GetContractByID(1)
|
nnsCs, err := r.GetContractByID(1)
|
||||||
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
||||||
|
|
||||||
ch, err = helper.NNSResolveHash(inv, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
|
ch, err = helper.NNSResolveHash(ac.Invoker, nnsCs.Hash, helper.DomainOf(constants.PolicyContract))
|
||||||
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
|
commonCmd.ExitOnErr(cmd, "unable to resolve policy contract hash: %w", err)
|
||||||
|
|
||||||
return morph.NewContractStorage(ac, ch), ac
|
return morph.NewContractStorage(ac, ch), ac
|
||||||
|
|
|
@ -28,7 +28,10 @@ const (
|
||||||
ContractWalletFilename = "contract.json"
|
ContractWalletFilename = "contract.json"
|
||||||
ContractWalletPasswordKey = "contract"
|
ContractWalletPasswordKey = "contract"
|
||||||
|
|
||||||
FrostfsOpsEmail = "ops@frostfs.info"
|
FrostfsOpsEmail = "ops@frostfs.info"
|
||||||
|
NNSRefreshDefVal = int64(3600)
|
||||||
|
NNSRetryDefVal = int64(600)
|
||||||
|
NNSTtlDefVal = int64(3600)
|
||||||
|
|
||||||
DefaultExpirationTime = 10 * 365 * 24 * time.Hour / time.Second
|
DefaultExpirationTime = 10 * 365 * 24 * time.Hour / time.Second
|
||||||
|
|
||||||
|
|
|
@ -148,12 +148,14 @@ func registerNNS(nnsCs *state.Contract, c *helper.InitializeContext, zone string
|
||||||
|
|
||||||
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
||||||
zone, c.CommitteeAcc.Contract.ScriptHash(),
|
zone, c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
constants.FrostfsOpsEmail, int64(3600), int64(600), int64(constants.DefaultExpirationTime), int64(3600))
|
constants.FrostfsOpsEmail, constants.NNSRefreshDefVal, constants.NNSRetryDefVal,
|
||||||
|
int64(constants.DefaultExpirationTime), constants.NNSTtlDefVal)
|
||||||
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
||||||
domain, c.CommitteeAcc.Contract.ScriptHash(),
|
domain, c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
constants.FrostfsOpsEmail, int64(3600), int64(600), int64(constants.DefaultExpirationTime), int64(3600))
|
constants.FrostfsOpsEmail, constants.NNSRefreshDefVal, constants.NNSRetryDefVal,
|
||||||
|
int64(constants.DefaultExpirationTime), constants.NNSTtlDefVal)
|
||||||
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
||||||
} else {
|
} else {
|
||||||
s, ok, err := c.NNSRegisterDomainScript(nnsCs.Hash, cs.Hash, domain)
|
s, ok, err := c.NNSRegisterDomainScript(nnsCs.Hash, cs.Hash, domain)
|
||||||
|
|
169
cmd/frostfs-adm/internal/modules/morph/helper/actor.go
Normal file
169
cmd/frostfs-adm/internal/modules/morph/helper/actor.go
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"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/morph/constants"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/context"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LocalActor is a kludge, do not use it outside of the morph commands.
|
||||||
|
type LocalActor struct {
|
||||||
|
neoActor *actor.Actor
|
||||||
|
accounts []*wallet.Account
|
||||||
|
Invoker *invoker.Invoker
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLocalActor create LocalActor with accounts form provided wallets.
|
||||||
|
// In case of empty wallets provided created actor with dummy account only for read operation.
|
||||||
|
func NewLocalActor(cmd *cobra.Command, c actor.RPCActor) (*LocalActor, error) {
|
||||||
|
walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
|
||||||
|
var act *actor.Actor
|
||||||
|
var accounts []*wallet.Account
|
||||||
|
if walletDir == "" {
|
||||||
|
account, err := wallet.NewAccount()
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to create dummy account: %w", err)
|
||||||
|
act, err = actor.New(c, []actor.SignerAccount{{
|
||||||
|
Signer: transaction.Signer{
|
||||||
|
Account: account.Contract.ScriptHash(),
|
||||||
|
Scopes: transaction.Global,
|
||||||
|
},
|
||||||
|
Account: account,
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wallets, err := GetAlphabetWallets(viper.GetViper(), walletDir)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
|
||||||
|
|
||||||
|
for _, w := range wallets {
|
||||||
|
acc, err := GetWalletAccount(w, constants.CommitteeAccountName)
|
||||||
|
commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
|
||||||
|
accounts = append(accounts, acc)
|
||||||
|
}
|
||||||
|
act, err = actor.New(c, []actor.SignerAccount{{
|
||||||
|
Signer: transaction.Signer{
|
||||||
|
Account: accounts[0].Contract.ScriptHash(),
|
||||||
|
Scopes: transaction.Global,
|
||||||
|
},
|
||||||
|
Account: accounts[0],
|
||||||
|
}})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &LocalActor{
|
||||||
|
neoActor: act,
|
||||||
|
accounts: accounts,
|
||||||
|
Invoker: &act.Invoker,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error) {
|
||||||
|
tx, err := a.neoActor.MakeCall(contract, method, params...)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint256{}, 0, err
|
||||||
|
}
|
||||||
|
err = a.resign(tx)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint256{}, 0, err
|
||||||
|
}
|
||||||
|
return a.neoActor.Send(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) SendRun(script []byte) (util.Uint256, uint32, error) {
|
||||||
|
tx, err := a.neoActor.MakeRun(script)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint256{}, 0, err
|
||||||
|
}
|
||||||
|
err = a.resign(tx)
|
||||||
|
if err != nil {
|
||||||
|
return util.Uint256{}, 0, err
|
||||||
|
}
|
||||||
|
return a.neoActor.Send(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resign is used to sign tx with committee accounts.
|
||||||
|
// Inside the methods `MakeCall` and `SendRun` of the NeoGO's actor transaction is signing by committee account,
|
||||||
|
// because actor uses committee wallet.
|
||||||
|
// But it is not enough, need to sign with another committee accounts.
|
||||||
|
func (a *LocalActor) resign(tx *transaction.Transaction) error {
|
||||||
|
if len(a.accounts[0].Contract.Parameters) > 1 {
|
||||||
|
// Use parameter context to avoid dealing with signature order.
|
||||||
|
network := a.neoActor.GetNetwork()
|
||||||
|
pc := context.NewParameterContext("", network, tx)
|
||||||
|
h := a.accounts[0].Contract.ScriptHash()
|
||||||
|
for _, acc := range a.accounts {
|
||||||
|
priv := acc.PrivateKey()
|
||||||
|
sign := priv.SignHashable(uint32(network), tx)
|
||||||
|
if err := pc.AddSignature(h, acc.Contract, priv.PublicKey(), sign); err != nil {
|
||||||
|
return fmt.Errorf("can't add signature: %w", err)
|
||||||
|
}
|
||||||
|
if len(pc.Items[h].Signatures) == len(acc.Contract.Parameters) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := pc.GetWitness(h)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("incomplete signature: %w", err)
|
||||||
|
}
|
||||||
|
tx.Scripts[0] = *w
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) {
|
||||||
|
return a.neoActor.Wait(h, vub, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) Sender() util.Uint160 {
|
||||||
|
return a.neoActor.Sender()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) {
|
||||||
|
return a.neoActor.Call(contract, operation, params...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) CallAndExpandIterator(_ util.Uint160, _ string, _ int, _ ...any) (*result.Invoke, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) TerminateSession(_ uuid.UUID) error {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) TraverseIterator(sessionID uuid.UUID, iterator *result.Iterator, num int) ([]stackitem.Item, error) {
|
||||||
|
return a.neoActor.TraverseIterator(sessionID, iterator, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) MakeRun(_ []byte) (*transaction.Transaction, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) MakeUnsignedCall(_ util.Uint160, _ string, _ []transaction.Attribute, _ ...any) (*transaction.Transaction, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) MakeUnsignedRun(_ []byte, _ []transaction.Attribute) (*transaction.Transaction, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LocalActor) MakeCall(_ util.Uint160, _ string, _ ...any) (*transaction.Transaction, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
|
@ -7,7 +7,9 @@ import (
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
||||||
"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/morph/constants"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
"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/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -101,6 +103,16 @@ func GetWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) {
|
||||||
return nil, fmt.Errorf("account for '%s' not found", typ)
|
return nil, fmt.Errorf("account for '%s' not found", typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetComitteAcc(cmd *cobra.Command, v *viper.Viper) *wallet.Account {
|
||||||
|
walletDir := config.ResolveHomePath(viper.GetString(commonflags.AlphabetWalletsFlag))
|
||||||
|
wallets, err := GetAlphabetWallets(v, walletDir)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get alphabet wallets: %w", err)
|
||||||
|
|
||||||
|
committeeAcc, err := GetWalletAccount(wallets[0], constants.CommitteeAccountName)
|
||||||
|
commonCmd.ExitOnErr(cmd, "can't find committee account: %w", err)
|
||||||
|
return committeeAcc
|
||||||
|
}
|
||||||
|
|
||||||
func NNSResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
|
func NNSResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
|
||||||
return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
|
return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -478,7 +478,8 @@ func (c *InitializeContext) EmitUpdateNNSGroupScript(bw *io.BufBinWriter, nnsHas
|
||||||
if isAvail {
|
if isAvail {
|
||||||
emit.AppCall(bw.BinWriter, nnsHash, "register", callflag.All,
|
emit.AppCall(bw.BinWriter, nnsHash, "register", callflag.All,
|
||||||
client.NNSGroupKeyName, c.CommitteeAcc.Contract.ScriptHash(),
|
client.NNSGroupKeyName, c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
constants.FrostfsOpsEmail, int64(3600), int64(600), int64(constants.DefaultExpirationTime), int64(3600))
|
constants.FrostfsOpsEmail, constants.NNSRefreshDefVal, constants.NNSRetryDefVal,
|
||||||
|
int64(constants.DefaultExpirationTime), constants.NNSTtlDefVal)
|
||||||
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +500,8 @@ func (c *InitializeContext) NNSRegisterDomainScript(nnsHash, expectedHash util.U
|
||||||
bw := io.NewBufBinWriter()
|
bw := io.NewBufBinWriter()
|
||||||
emit.AppCall(bw.BinWriter, nnsHash, "register", callflag.All,
|
emit.AppCall(bw.BinWriter, nnsHash, "register", callflag.All,
|
||||||
domain, c.CommitteeAcc.Contract.ScriptHash(),
|
domain, c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
constants.FrostfsOpsEmail, int64(3600), int64(600), int64(constants.DefaultExpirationTime), int64(3600))
|
constants.FrostfsOpsEmail, constants.NNSRefreshDefVal, constants.NNSRetryDefVal,
|
||||||
|
int64(constants.DefaultExpirationTime), constants.NNSTtlDefVal)
|
||||||
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
||||||
|
|
||||||
if bw.Err != nil {
|
if bw.Err != nil {
|
||||||
|
|
|
@ -33,7 +33,8 @@ func setNNS(c *helper.InitializeContext) error {
|
||||||
bw := io.NewBufBinWriter()
|
bw := io.NewBufBinWriter()
|
||||||
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
emit.AppCall(bw.BinWriter, nnsCs.Hash, "register", callflag.All,
|
||||||
"frostfs", c.CommitteeAcc.Contract.ScriptHash(),
|
"frostfs", c.CommitteeAcc.Contract.ScriptHash(),
|
||||||
constants.FrostfsOpsEmail, int64(3600), int64(600), int64(constants.DefaultExpirationTime), int64(3600))
|
constants.FrostfsOpsEmail, constants.NNSRefreshDefVal, constants.NNSRetryDefVal,
|
||||||
|
int64(constants.DefaultExpirationTime), constants.NNSTtlDefVal)
|
||||||
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
emit.Opcodes(bw.BinWriter, opcode.ASSERT)
|
||||||
if err := c.SendCommitteeTx(bw.Bytes(), true); err != nil {
|
if err := c.SendCommitteeTx(bw.Bytes(), true); err != nil {
|
||||||
return fmt.Errorf("can't add domain root to NNS: %w", err)
|
return fmt.Errorf("can't add domain root to NNS: %w", err)
|
||||||
|
|
25
cmd/frostfs-adm/internal/modules/morph/nns/helper.go
Normal file
25
cmd/frostfs-adm/internal/modules/morph/nns/helper.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
client "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/nns"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/helper"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"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 getRPCClient(cmd *cobra.Command) (*client.Contract, *helper.LocalActor, util.Uint160) {
|
||||||
|
v := viper.GetViper()
|
||||||
|
c, err := helper.GetN3Client(v)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to create NEO rpc client: %w", err)
|
||||||
|
|
||||||
|
ac, err := helper.NewLocalActor(cmd, c)
|
||||||
|
commonCmd.ExitOnErr(cmd, "can't create actor: %w", err)
|
||||||
|
|
||||||
|
r := management.NewReader(ac.Invoker)
|
||||||
|
nnsCs, err := r.GetContractByID(1)
|
||||||
|
commonCmd.ExitOnErr(cmd, "can't get NNS contract state: %w", err)
|
||||||
|
return client.New(ac, nnsCs.Hash), ac, nnsCs.Hash
|
||||||
|
}
|
148
cmd/frostfs-adm/internal/modules/morph/nns/record.go
Normal file
148
cmd/frostfs-adm/internal/modules/morph/nns/record.go
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/nns"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initAddRecordCmd() {
|
||||||
|
Cmd.AddCommand(addRecordCmd)
|
||||||
|
addRecordCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
addRecordCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
addRecordCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
addRecordCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
|
||||||
|
addRecordCmd.Flags().String(nnsRecordDataFlag, "", nnsRecordDataFlagDesc)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsNameFlag)
|
||||||
|
_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordTypeFlag)
|
||||||
|
_ = cobra.MarkFlagRequired(addRecordCmd.Flags(), nnsRecordDataFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initGetRecordsCmd() {
|
||||||
|
Cmd.AddCommand(getRecordsCmd)
|
||||||
|
getRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
getRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
getRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
getRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(getRecordsCmd.Flags(), nnsNameFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initDelRecordsCmd() {
|
||||||
|
Cmd.AddCommand(delRecordsCmd)
|
||||||
|
delRecordsCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
delRecordsCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
delRecordsCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
delRecordsCmd.Flags().String(nnsRecordTypeFlag, "", nnsRecordTypeFlagDesc)
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsNameFlag)
|
||||||
|
_ = cobra.MarkFlagRequired(delRecordsCmd.Flags(), nnsRecordTypeFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRecord(cmd *cobra.Command, _ []string) {
|
||||||
|
c, actor, _ := getRPCClient(cmd)
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
data, _ := cmd.Flags().GetString(nnsRecordDataFlag)
|
||||||
|
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||||
|
typ, err := getRecordType(recordType)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
|
||||||
|
h, vub, err := c.AddRecord(name, typ, data)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to add record: %w", err)
|
||||||
|
|
||||||
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
|
_, err = actor.Wait(h, vub, err)
|
||||||
|
commonCmd.ExitOnErr(cmd, "renew domain error: %w", err)
|
||||||
|
cmd.Println("Record added successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRecords(cmd *cobra.Command, _ []string) {
|
||||||
|
c, act, hash := getRPCClient(cmd)
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||||
|
if recordType == "" {
|
||||||
|
sid, r, err := unwrap.SessionIterator(act.Invoker.Call(hash, "getAllRecords", name))
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||||
|
defer func() {
|
||||||
|
_ = act.Invoker.TerminateSession(sid)
|
||||||
|
}()
|
||||||
|
items, err := act.Invoker.TraverseIterator(sid, &r, 0)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||||
|
for len(items) != 0 {
|
||||||
|
for j := range items {
|
||||||
|
rs := items[j].Value().([]stackitem.Item)
|
||||||
|
bs, err := rs[2].TryBytes()
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to parse record state: %w", err)
|
||||||
|
cmd.Printf("%s %s\n",
|
||||||
|
recordTypeToString(nns.RecordType(rs[1].Value().(*big.Int).Int64())),
|
||||||
|
string(bs))
|
||||||
|
}
|
||||||
|
items, err = act.Invoker.TraverseIterator(sid, &r, 0)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
typ, err := getRecordType(recordType)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
|
||||||
|
items, err := c.GetRecords(name, typ)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get records: %w", err)
|
||||||
|
for _, item := range items {
|
||||||
|
record, err := item.TryBytes()
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to parse response: %w", err)
|
||||||
|
cmd.Println(string(record))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delRecords(cmd *cobra.Command, _ []string) {
|
||||||
|
c, actor, _ := getRPCClient(cmd)
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
recordType, _ := cmd.Flags().GetString(nnsRecordTypeFlag)
|
||||||
|
typ, err := getRecordType(recordType)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to parse record type: %w", err)
|
||||||
|
h, vub, err := c.DeleteRecords(name, typ)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to delete records: %w", err)
|
||||||
|
|
||||||
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
|
_, err = actor.Wait(h, vub, err)
|
||||||
|
commonCmd.ExitOnErr(cmd, "delete records error: %w", err)
|
||||||
|
cmd.Println("Records removed successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRecordType(recordType string) (*big.Int, error) {
|
||||||
|
switch strings.ToUpper(recordType) {
|
||||||
|
case "A":
|
||||||
|
return big.NewInt(int64(nns.A)), nil
|
||||||
|
case "CNAME":
|
||||||
|
return big.NewInt(int64(nns.CNAME)), nil
|
||||||
|
case "SOA":
|
||||||
|
return big.NewInt(int64(nns.SOA)), nil
|
||||||
|
case "TXT":
|
||||||
|
return big.NewInt(int64(nns.TXT)), nil
|
||||||
|
case "AAAA":
|
||||||
|
return big.NewInt(int64(nns.AAAA)), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("unsupported record type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordTypeToString(rt nns.RecordType) string {
|
||||||
|
switch rt {
|
||||||
|
case nns.A:
|
||||||
|
return "A"
|
||||||
|
case nns.CNAME:
|
||||||
|
return "CNAME"
|
||||||
|
case nns.SOA:
|
||||||
|
return "SOA"
|
||||||
|
case nns.TXT:
|
||||||
|
return "TXT"
|
||||||
|
case nns.AAAA:
|
||||||
|
return "AAAA"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
44
cmd/frostfs-adm/internal/modules/morph/nns/register.go
Normal file
44
cmd/frostfs-adm/internal/modules/morph/nns/register.go
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initRegisterCmd() {
|
||||||
|
Cmd.AddCommand(registerCmd)
|
||||||
|
registerCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
registerCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
registerCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
registerCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email")
|
||||||
|
registerCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal, "SOA record REFRESH parameter")
|
||||||
|
registerCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal, "SOA record RETRY parameter")
|
||||||
|
registerCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime), "SOA record EXPIRE parameter")
|
||||||
|
registerCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal, "SOA record TTL parameter")
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(registerCmd.Flags(), nnsNameFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerDomain(cmd *cobra.Command, _ []string) {
|
||||||
|
c, actor, _ := getRPCClient(cmd)
|
||||||
|
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
email, _ := cmd.Flags().GetString(nnsEmailFlag)
|
||||||
|
refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag)
|
||||||
|
retry, _ := cmd.Flags().GetInt64(nnsRetryFlag)
|
||||||
|
expire, _ := cmd.Flags().GetInt64(nnsExpireFlag)
|
||||||
|
ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag)
|
||||||
|
|
||||||
|
h, vub, err := c.Register(name, actor.Sender(), email, big.NewInt(refresh),
|
||||||
|
big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl))
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to register domain: %w", err)
|
||||||
|
|
||||||
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
|
_, err = actor.Wait(h, vub, err)
|
||||||
|
commonCmd.ExitOnErr(cmd, "register domain error: %w", err)
|
||||||
|
cmd.Println("Domain registered successfully")
|
||||||
|
}
|
26
cmd/frostfs-adm/internal/modules/morph/nns/renew.go
Normal file
26
cmd/frostfs-adm/internal/modules/morph/nns/renew.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initRenewCmd() {
|
||||||
|
Cmd.AddCommand(renewCmd)
|
||||||
|
renewCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
renewCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
renewCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renewDomain(cmd *cobra.Command, _ []string) {
|
||||||
|
c, actor, _ := getRPCClient(cmd)
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
h, vub, err := c.Renew(name)
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to renew domain: %w", err)
|
||||||
|
|
||||||
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
|
_, err = actor.Wait(h, vub, err)
|
||||||
|
commonCmd.ExitOnErr(cmd, "renew domain error: %w", err)
|
||||||
|
cmd.Println("Domain renewed successfully")
|
||||||
|
}
|
99
cmd/frostfs-adm/internal/modules/morph/nns/root.go
Normal file
99
cmd/frostfs-adm/internal/modules/morph/nns/root.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nnsNameFlag = "name"
|
||||||
|
nnsNameFlagDesc = "Domain name"
|
||||||
|
nnsEmailFlag = "email"
|
||||||
|
nnsRefreshFlag = "refresh"
|
||||||
|
nnsRetryFlag = "retry"
|
||||||
|
nnsExpireFlag = "expire"
|
||||||
|
nnsTTLFlag = "ttl"
|
||||||
|
nnsRecordTypeFlag = "type"
|
||||||
|
nnsRecordTypeFlagDesc = "Domain name service record type(A|CNAME|SOA|TXT)"
|
||||||
|
nnsRecordDataFlag = "data"
|
||||||
|
nnsRecordDataFlagDesc = "Domain name service record data"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Cmd = &cobra.Command{
|
||||||
|
Use: "nns",
|
||||||
|
Short: "Section for Neo Name Service (NNS)",
|
||||||
|
}
|
||||||
|
tokensCmd = &cobra.Command{
|
||||||
|
Use: "tokens",
|
||||||
|
Short: "List all registered domain names",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
},
|
||||||
|
Run: listTokens,
|
||||||
|
}
|
||||||
|
registerCmd = &cobra.Command{
|
||||||
|
Use: "register",
|
||||||
|
Short: "Registers a new domain",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||||
|
},
|
||||||
|
Run: registerDomain,
|
||||||
|
}
|
||||||
|
renewCmd = &cobra.Command{
|
||||||
|
Use: "renew",
|
||||||
|
Short: "Increases domain expiration date",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||||
|
},
|
||||||
|
Run: renewDomain,
|
||||||
|
}
|
||||||
|
updateCmd = &cobra.Command{
|
||||||
|
Use: "update",
|
||||||
|
Short: "Updates soa record",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||||
|
},
|
||||||
|
Run: updateSOA,
|
||||||
|
}
|
||||||
|
addRecordCmd = &cobra.Command{
|
||||||
|
Use: "add-record",
|
||||||
|
Short: "Adds a new record of the specified type to the provided domain",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||||
|
},
|
||||||
|
Run: addRecord,
|
||||||
|
}
|
||||||
|
getRecordsCmd = &cobra.Command{
|
||||||
|
Use: "get-records",
|
||||||
|
Short: "Returns domain record of the specified type",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
},
|
||||||
|
Run: getRecords,
|
||||||
|
}
|
||||||
|
delRecordsCmd = &cobra.Command{
|
||||||
|
Use: "delete-records",
|
||||||
|
Short: "Removes domain records with the specified type",
|
||||||
|
PreRun: func(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = viper.BindPFlag(commonflags.EndpointFlag, cmd.Flags().Lookup(commonflags.EndpointFlag))
|
||||||
|
_ = viper.BindPFlag(commonflags.AlphabetWalletsFlag, cmd.Flags().Lookup(commonflags.AlphabetWalletsFlag))
|
||||||
|
},
|
||||||
|
Run: delRecords,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initTokensCmd()
|
||||||
|
initRegisterCmd()
|
||||||
|
initRenewCmd()
|
||||||
|
initUpdateCmd()
|
||||||
|
initAddRecordCmd()
|
||||||
|
initGetRecordsCmd()
|
||||||
|
initDelRecordsCmd()
|
||||||
|
}
|
24
cmd/frostfs-adm/internal/modules/morph/nns/tokens.go
Normal file
24
cmd/frostfs-adm/internal/modules/morph/nns/tokens.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initTokensCmd() {
|
||||||
|
Cmd.AddCommand(tokensCmd)
|
||||||
|
tokensCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
tokensCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func listTokens(cmd *cobra.Command, _ []string) {
|
||||||
|
c, _, _ := getRPCClient(cmd)
|
||||||
|
it, err := c.Tokens()
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to get tokens: %w", err)
|
||||||
|
for toks, err := it.Next(10); err == nil && len(toks) > 0; toks, err = it.Next(10) {
|
||||||
|
for _, token := range toks {
|
||||||
|
cmd.Println(string(token))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
cmd/frostfs-adm/internal/modules/morph/nns/update.go
Normal file
50
cmd/frostfs-adm/internal/modules/morph/nns/update.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package nns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/commonflags"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/constants"
|
||||||
|
commonCmd "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/internal/common"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initUpdateCmd() {
|
||||||
|
Cmd.AddCommand(updateCmd)
|
||||||
|
updateCmd.Flags().StringP(commonflags.EndpointFlag, commonflags.EndpointFlagShort, "", commonflags.EndpointFlagDesc)
|
||||||
|
updateCmd.Flags().String(commonflags.AlphabetWalletsFlag, "", commonflags.AlphabetWalletsFlagDesc)
|
||||||
|
updateCmd.Flags().String(nnsNameFlag, "", nnsNameFlagDesc)
|
||||||
|
updateCmd.Flags().String(nnsEmailFlag, constants.FrostfsOpsEmail, "Domain owner email")
|
||||||
|
updateCmd.Flags().Int64(nnsRefreshFlag, constants.NNSRefreshDefVal,
|
||||||
|
"The number of seconds between update requests from secondary and slave name servers")
|
||||||
|
updateCmd.Flags().Int64(nnsRetryFlag, constants.NNSRetryDefVal,
|
||||||
|
"The number of seconds the secondary or slave will wait before retrying when the last attempt has failed")
|
||||||
|
updateCmd.Flags().Int64(nnsExpireFlag, int64(constants.DefaultExpirationTime),
|
||||||
|
"The number of seconds a master or slave will wait before considering the data stale "+
|
||||||
|
"if it cannot reach the primary name server")
|
||||||
|
updateCmd.Flags().Int64(nnsTTLFlag, constants.NNSTtlDefVal,
|
||||||
|
"The number of seconds a domain name is cached locally before expiration and return to authoritative "+
|
||||||
|
"nameservers for updated information")
|
||||||
|
|
||||||
|
_ = cobra.MarkFlagRequired(updateCmd.Flags(), nnsNameFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateSOA(cmd *cobra.Command, _ []string) {
|
||||||
|
c, actor, _ := getRPCClient(cmd)
|
||||||
|
|
||||||
|
name, _ := cmd.Flags().GetString(nnsNameFlag)
|
||||||
|
email, _ := cmd.Flags().GetString(nnsEmailFlag)
|
||||||
|
refresh, _ := cmd.Flags().GetInt64(nnsRefreshFlag)
|
||||||
|
retry, _ := cmd.Flags().GetInt64(nnsRetryFlag)
|
||||||
|
expire, _ := cmd.Flags().GetInt64(nnsExpireFlag)
|
||||||
|
ttl, _ := cmd.Flags().GetInt64(nnsTTLFlag)
|
||||||
|
|
||||||
|
h, vub, err := c.UpdateSOA(name, email, big.NewInt(refresh),
|
||||||
|
big.NewInt(retry), big.NewInt(expire), big.NewInt(ttl))
|
||||||
|
commonCmd.ExitOnErr(cmd, "unable to send transaction: %w", err)
|
||||||
|
|
||||||
|
cmd.Println("Waiting for transaction to persist...")
|
||||||
|
_, err = actor.Wait(h, vub, err)
|
||||||
|
commonCmd.ExitOnErr(cmd, "register domain error: %w", err)
|
||||||
|
cmd.Println("SOA records updated successfully")
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/generate"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/generate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/initialize"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/initialize"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/netmap"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/netmap"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/nns"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/node"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/node"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/notary"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/notary"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/policy"
|
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-adm/internal/modules/morph/policy"
|
||||||
|
@ -49,4 +50,5 @@ func init() {
|
||||||
RootCmd.AddCommand(proxy.RemoveAccountCmd)
|
RootCmd.AddCommand(proxy.RemoveAccountCmd)
|
||||||
|
|
||||||
RootCmd.AddCommand(frostfsid.Cmd)
|
RootCmd.AddCommand(frostfsid.Cmd)
|
||||||
|
RootCmd.AddCommand(nns.Cmd)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue