[#979] adm: Deploy missing contracts during updating

Make `nnsResolveHash` function to return declared error on `token not
found` fault exception. Catch this error in `deployContracts` method,
and switch to deployment if updating contract is missing.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2021-11-29 13:15:03 +03:00 committed by LeL
parent e8f8e58e90
commit 2f2ca2e0bd
3 changed files with 25 additions and 6 deletions

View file

@ -57,13 +57,13 @@ func initializeSideChainCmd(cmd *cobra.Command, args []string) error {
// 3. Deploy NNS contract. // 3. Deploy NNS contract.
cmd.Println("Stage 3: deploy NNS contract.") cmd.Println("Stage 3: deploy NNS contract.")
if err := initCtx.deployNNS("deploy"); err != nil { if err := initCtx.deployNNS(deployMethodName); err != nil {
return err return err
} }
// 4. Deploy NeoFS contracts. // 4. Deploy NeoFS contracts.
cmd.Println("Stage 4: deploy NeoFS contracts.") cmd.Println("Stage 4: deploy NeoFS contracts.")
if err := initCtx.deployContracts("deploy"); err != nil { if err := initCtx.deployContracts(deployMethodName); err != nil {
return err return err
} }

View file

@ -4,6 +4,7 @@ import (
"archive/tar" "archive/tar"
"compress/gzip" "compress/gzip"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -83,7 +84,10 @@ type contractState struct {
Hash util.Uint160 Hash util.Uint160
} }
const updateMethodName = "update" const (
updateMethodName = "update"
deployMethodName = "deploy"
)
func (c *initializeContext) deployNNS(method string) error { func (c *initializeContext) deployNNS(method string) error {
cs := c.getContract(nnsContract) cs := c.getContract(nnsContract)
@ -214,10 +218,18 @@ func (c *initializeContext) deployContracts(method string) error {
cs := c.Contracts[ctrName] cs := c.Contracts[ctrName]
ctrHash := cs.Hash ctrHash := cs.Hash
methodCur := method // prevent overriding in if-block
if method == updateMethodName { if method == updateMethodName {
ctrHash, err = nnsResolveHash(c.Client, nnsHash, ctrName+".neofs") ctrHash, err = nnsResolveHash(c.Client, nnsHash, ctrName+".neofs")
if err != nil { if err != nil {
return fmt.Errorf("can't resolve hash for contract update: %w", err) if errors.Is(err, errMissingNNSRecord) {
// if contract not found we deploy it instead of update
methodCur = deployMethodName
} else {
return fmt.Errorf("can't resolve hash for contract update: %w", err)
}
} }
} }
if c.isUpdated(ctrHash, cs) { if c.isUpdated(ctrHash, cs) {
@ -226,7 +238,7 @@ func (c *initializeContext) deployContracts(method string) error {
} }
invokeHash := mgmtHash invokeHash := mgmtHash
if method == updateMethodName { if methodCur == updateMethodName {
invokeHash = ctrHash invokeHash = ctrHash
} }
@ -237,7 +249,7 @@ func (c *initializeContext) deployContracts(method string) error {
Scopes: transaction.Global, Scopes: transaction.Global,
} }
res, err := c.Client.InvokeFunction(invokeHash, method, params, []transaction.Signer{signer}) res, err := c.Client.InvokeFunction(invokeHash, methodCur, params, []transaction.Signer{signer})
if err != nil { if err != nil {
return fmt.Errorf("can't deploy %s contract: %w", ctrName, err) return fmt.Errorf("can't deploy %s contract: %w", ctrName, err)
} }

View file

@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
"strings"
nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns" nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns"
"github.com/nspcc-dev/neo-go/pkg/core/native" "github.com/nspcc-dev/neo-go/pkg/core/native"
@ -116,6 +117,9 @@ func (c *initializeContext) nnsRootRegistered(nnsHash util.Uint160) (bool, error
return res.State == vm.HaltState.String(), nil return res.State == vm.HaltState.String(), nil
} }
var errMissingNNSRecord = errors.New("missing NNS record")
// Returns errMissingNNSRecord if invocation fault exception contains "token not found".
func nnsResolveHash(c *client.Client, nnsHash util.Uint160, domain string) (util.Uint160, error) { func nnsResolveHash(c *client.Client, nnsHash util.Uint160, domain string) (util.Uint160, error) {
result, err := c.InvokeFunction(nnsHash, "resolve", []smartcontract.Parameter{ result, err := c.InvokeFunction(nnsHash, "resolve", []smartcontract.Parameter{
{ {
@ -131,6 +135,9 @@ func nnsResolveHash(c *client.Client, nnsHash util.Uint160, domain string) (util
return util.Uint160{}, fmt.Errorf("`resolve`: %w", err) return util.Uint160{}, fmt.Errorf("`resolve`: %w", err)
} }
if result.State != vm.HaltState.String() { if result.State != vm.HaltState.String() {
if strings.Contains(result.FaultException, "token not found") {
return util.Uint160{}, errMissingNNSRecord
}
return util.Uint160{}, fmt.Errorf("invocation failed: %s", result.FaultException) return util.Uint160{}, fmt.Errorf("invocation failed: %s", result.FaultException)
} }
if len(result.Stack) == 0 { if len(result.Stack) == 0 {