From b416285eb0858bf3cfdc653f3fce4ae252df3b5d Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 29 Nov 2021 15:33:46 +0300 Subject: [PATCH] [#749] neofs-adm: include neofs contracts in a group Signed-off-by: Evgenii Stratonikov --- cmd/neofs-adm/internal/modules/morph/group.go | 73 +++++++++++++++++++ .../internal/modules/morph/initialize.go | 26 ++++--- .../modules/morph/initialize_deploy.go | 25 ++++++- 3 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 cmd/neofs-adm/internal/modules/morph/group.go diff --git a/cmd/neofs-adm/internal/modules/morph/group.go b/cmd/neofs-adm/internal/modules/morph/group.go new file mode 100644 index 000000000..854aa61e7 --- /dev/null +++ b/cmd/neofs-adm/internal/modules/morph/group.go @@ -0,0 +1,73 @@ +package morph + +import ( + "encoding/json" + "fmt" + "path" + + "github.com/nspcc-dev/neo-go/cli/input" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/wallet" + "github.com/spf13/viper" +) + +const contractWalletName = "contract.json" + +func openContractWallet(walletDir string) (*wallet.Wallet, error) { + p := path.Join(walletDir, contractWalletName) + w, err := wallet.NewWalletFromFile(p) + if err != nil { + return nil, fmt.Errorf("can't open wallet: %w", err) + } + + var password string + if key := "credentials.contract"; viper.IsSet(key) { + password = viper.GetString(key) + } else { + prompt := "Password for contract wallet > " + password, err = input.ReadPassword(prompt) + 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) + } + } + + return w, nil +} + +func (c *initializeContext) addManifestGroup(h util.Uint160, cs *contractState) error { + priv := c.ContractWallet.Accounts[0].PrivateKey() + pub := priv.PublicKey() + + sig := priv.Sign(h.BytesBE()) + found := false + + for i := range cs.Manifest.Groups { + if cs.Manifest.Groups[i].PublicKey.Equal(pub) { + cs.Manifest.Groups[i].Signature = sig + found = true + break + } + } + if !found { + cs.Manifest.Groups = append(cs.Manifest.Groups, manifest.Group{ + PublicKey: pub, + Signature: sig, + }) + } + + data, err := json.Marshal(cs.Manifest) + if err != nil { + return err + } + + cs.RawManifest = data + return nil +} diff --git a/cmd/neofs-adm/internal/modules/morph/initialize.go b/cmd/neofs-adm/internal/modules/morph/initialize.go index 04accf7f0..472322038 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize.go @@ -28,6 +28,8 @@ type initializeContext struct { // ConsensusAcc is used for retrieving committee address and verification script. ConsensusAcc *wallet.Account Wallets []*wallet.Wallet + // ContractWallet is a wallet for providing contract group signature. + ContractWallet *wallet.Wallet // Accounts contains simple signature accounts in the same order as in Wallets. Accounts []*wallet.Account Contracts map[string]*contractState @@ -95,6 +97,11 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex return nil, err } + w, err := openContractWallet(walletDir) + if err != nil { + return nil, err + } + c, err := getN3Client(v) if err != nil { return nil, fmt.Errorf("can't create N3 client: %w", err) @@ -144,15 +151,16 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex } initCtx := &initializeContext{ - clientContext: *defaultClientContext(c), - ConsensusAcc: consensusAcc, - CommitteeAcc: committeeAcc, - Wallets: wallets, - Accounts: accounts, - Command: cmd, - Contracts: make(map[string]*contractState), - ContractPath: ctrPath, - Natives: nativeHashes, + clientContext: *defaultClientContext(c), + ConsensusAcc: consensusAcc, + CommitteeAcc: committeeAcc, + ContractWallet: w, + Wallets: wallets, + Accounts: accounts, + Command: cmd, + Contracts: make(map[string]*contractState), + ContractPath: ctrPath, + Natives: nativeHashes, } if needContracts { diff --git a/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go b/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go index c994a929d..529a45b49 100644 --- a/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go +++ b/cmd/neofs-adm/internal/modules/morph/initialize_deploy.go @@ -96,11 +96,20 @@ const ( func (c *initializeContext) deployNNS(method string) error { cs := c.getContract(nnsContract) + h := cs.Hash realCs, err := c.Client.GetContractStateByID(1) - if err == nil && realCs.NEF.Checksum == cs.NEF.Checksum { - c.Command.Println("NNS contract is already deployed.") - return nil + if err == nil { + if realCs.NEF.Checksum == cs.NEF.Checksum { + c.Command.Println("NNS contract is already deployed.") + return nil + } + h = realCs.Hash + } + + err = c.addManifestGroup(h, cs) + if err != nil { + return fmt.Errorf("can't sign manifest group: %v", err) } params := getContractDeployParameters(cs.RawNEF, cs.RawManifest, nil) @@ -220,6 +229,11 @@ func (c *initializeContext) updateContracts() error { } } + err = c.addManifestGroup(ctrHash, alphaCs) + if err != nil { + return fmt.Errorf("can't sign manifest group: %v", err) + } + invokeHash := mgmtHash if method == updateMethodName { invokeHash = ctrHash @@ -322,6 +336,11 @@ func (c *initializeContext) deployContracts() error { continue } + err := c.addManifestGroup(ctrHash, cs) + if err != nil { + return fmt.Errorf("can't sign manifest group: %v", err) + } + invokeHash := mgmtHash params := getContractDeployParameters(cs.RawNEF, cs.RawManifest, c.getContractDeployData(ctrName, keysParam))