[#1711] amd: Cache committee actor in the init context

Also simplify the code using `invoker.Invoker`.

Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
Pavel Karpy 2022-09-05 15:45:38 +03:00 committed by fyrchik
parent 60aa53651b
commit 8e6e89aca3
16 changed files with 172 additions and 244 deletions

View file

@ -13,6 +13,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
@ -55,6 +57,8 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
return err
}
inv := invoker.New(c, nil)
ns, err := getNativeHashes(c)
if err != nil {
return fmt.Errorf("can't fetch the list of native contracts: %w", err)
@ -76,7 +80,7 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err)
}
nmHash, err = nnsResolveHash(c, nnsCs.Hash, netmapContract+".neofs")
nmHash, err = nnsResolveHash(inv, nnsCs.Hash, netmapContract+".neofs")
if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err)
}
@ -87,18 +91,14 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
return err
}
if err := fetchBalances(c, gasHash, irList); err != nil {
if err := fetchBalances(inv, gasHash, irList); err != nil {
return err
}
printBalances(cmd, "Inner ring nodes balances:", irList)
if dumpStorage {
res, err := invokeFunction(c, nmHash, "netmap", []interface{}{}, nil)
if err != nil || res.State != vmstate.Halt.String() || len(res.Stack) == 0 {
return errors.New("can't fetch the list of storage nodes")
}
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if !ok {
arr, err := unwrap.Array(inv.Call(nmHash, "netmap"))
if err != nil {
return errors.New("can't fetch the list of storage nodes")
}
@ -123,20 +123,20 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
snList[i].scriptHash = pub.GetScriptHash()
}
if err := fetchBalances(c, gasHash, snList); err != nil {
if err := fetchBalances(inv, gasHash, snList); err != nil {
return err
}
printBalances(cmd, "\nStorage node balances:", snList)
}
if dumpProxy {
h, err := nnsResolveHash(c, nnsCs.Hash, proxyContract+".neofs")
h, err := nnsResolveHash(inv, nnsCs.Hash, proxyContract+".neofs")
if err != nil {
return fmt.Errorf("can't get hash of the proxy contract: %w", err)
}
proxyList := []accBalancePair{{scriptHash: h}}
if err := fetchBalances(c, gasHash, proxyList); err != nil {
if err := fetchBalances(inv, gasHash, proxyList); err != nil {
return err
}
printBalances(cmd, "\nProxy contract balance:", proxyList)
@ -168,7 +168,7 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
alphaList[i].scriptHash = h
}
if err := fetchBalances(c, gasHash, alphaList); err != nil {
if err := fetchBalances(inv, gasHash, alphaList); err != nil {
return err
}
printBalances(cmd, "\nAlphabet contracts balances:", alphaList)
@ -180,13 +180,15 @@ func dumpBalances(cmd *cobra.Command, _ []string) error {
func fetchIRNodes(c Client, nmHash, desigHash util.Uint160) ([]accBalancePair, error) {
var irList []accBalancePair
inv := invoker.New(c, nil)
if notaryEnabled {
height, err := c.GetBlockCount()
if err != nil {
return nil, fmt.Errorf("can't get block height: %w", err)
}
arr, err := getDesignatedByRole(c, desigHash, noderoles.NeoFSAlphabet, height)
arr, err := getDesignatedByRole(inv, desigHash, noderoles.NeoFSAlphabet, height)
if err != nil {
return nil, errors.New("can't fetch list of IR nodes from the netmap contract")
}
@ -196,27 +198,14 @@ func fetchIRNodes(c Client, nmHash, desigHash util.Uint160) ([]accBalancePair, e
irList[i].scriptHash = arr[i].GetScriptHash()
}
} else {
res, err := invokeFunction(c, nmHash, "innerRingList", []interface{}{}, nil)
if err != nil || res.State != vmstate.Halt.String() || len(res.Stack) == 0 {
arr, err := unwrap.ArrayOfBytes(inv.Call(nmHash, "innerRingList"))
if err != nil {
return nil, errors.New("can't fetch list of IR nodes from the netmap contract")
}
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if !ok || len(arr) == 0 {
return nil, errors.New("can't fetch list of IR nodes: invalid response")
}
irList = make([]accBalancePair, len(arr))
for i := range arr {
node, ok := arr[i].Value().([]stackitem.Item)
if !ok || len(arr) == 0 {
return nil, errors.New("can't fetch list of IR nodes: invalid response")
}
bs, err := node[0].TryBytes()
if err != nil {
return nil, fmt.Errorf("can't fetch list of IR nodes: %w", err)
}
pub, err := keys.NewPublicKeyFromBytes(bs, elliptic.P256())
pub, err := keys.NewPublicKeyFromBytes(arr[i], elliptic.P256())
if err != nil {
return nil, fmt.Errorf("can't parse IR node public key: %w", err)
}
@ -241,7 +230,7 @@ func printBalances(cmd *cobra.Command, prefix string, accounts []accBalancePair)
}
}
func fetchBalances(c Client, gasHash util.Uint160, accounts []accBalancePair) error {
func fetchBalances(c *invoker.Invoker, gasHash util.Uint160, accounts []accBalancePair) error {
w := io.NewBufBinWriter()
for i := range accounts {
emit.AppCall(w.BinWriter, gasHash, "balanceOf", callflag.ReadStates, accounts[i].scriptHash)
@ -250,7 +239,7 @@ func fetchBalances(c Client, gasHash util.Uint160, accounts []accBalancePair) er
panic(w.Err)
}
res, err := c.InvokeScript(w.Bytes(), nil)
res, err := c.Run(w.Bytes())
if err != nil || res.State != vmstate.Halt.String() || len(res.Stack) != len(accounts) {
return errors.New("can't fetch account balances")
}

View file

@ -11,10 +11,11 @@ import (
"text/tabwriter"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -27,26 +28,23 @@ func dumpNetworkConfig(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't create N3 client: %w", err)
}
inv := invoker.New(c, nil)
cs, err := c.GetContractStateByID(1)
if err != nil {
return fmt.Errorf("can't get NNS contract info: %w", err)
}
nmHash, err := nnsResolveHash(c, cs.Hash, netmapContract+".neofs")
nmHash, err := nnsResolveHash(inv, cs.Hash, netmapContract+".neofs")
if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err)
}
res, err := invokeFunction(c, nmHash, "listConfig", nil, nil)
if err != nil || res.State != vmstate.Halt.String() || len(res.Stack) == 0 {
arr, err := unwrap.Array(inv.Call(nmHash, "listConfig"))
if err != nil {
return errors.New("can't fetch list of network config keys from the netmap contract")
}
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if !ok {
return errors.New("invalid ListConfig response from netmap contract")
}
buf := bytes.NewBuffer(nil)
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
@ -111,7 +109,7 @@ func setConfigCmd(cmd *cobra.Command, args []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err)
}
nmHash, err := nnsResolveHash(wCtx.Client, cs.Hash, netmapContract+".neofs")
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, netmapContract+".neofs")
if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err)
}

View file

@ -9,6 +9,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
@ -31,6 +33,8 @@ func dumpContainers(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't create N3 client: %w", err)
}
inv := invoker.New(c, nil)
nnsCs, err := c.GetContractStateByID(1)
if err != nil {
return fmt.Errorf("can't get NNS contract state: %w", err)
@ -42,30 +46,17 @@ func dumpContainers(cmd *cobra.Command, _ []string) error {
ch, err = util.Uint160DecodeStringLE(s)
}
if err != nil {
ch, err = nnsResolveHash(c, nnsCs.Hash, containerContract+".neofs")
ch, err = nnsResolveHash(inv, nnsCs.Hash, containerContract+".neofs")
if err != nil {
return err
}
}
res, err := invokeFunction(c, ch, "list", []interface{}{""}, nil)
cids, err := unwrap.ArrayOfBytes(inv.Call(ch, "list", ""))
if err != nil {
return fmt.Errorf("%w: %v", errInvalidContainerResponse, err)
}
var cids [][]byte
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if !ok {
return fmt.Errorf("%w: not a struct", errInvalidContainerResponse)
}
for _, item := range arr {
id, err := item.TryBytes()
if err != nil {
return fmt.Errorf("%w: %v", errInvalidContainerResponse, err)
}
cids = append(cids, id)
}
isOK, err := getCIDFilterFunc(cmd)
if err != nil {
return err
@ -80,7 +71,7 @@ func dumpContainers(cmd *cobra.Command, _ []string) error {
bw.Reset()
emit.AppCall(bw.BinWriter, ch, "get", callflag.All, id)
emit.AppCall(bw.BinWriter, ch, "eACL", callflag.All, id)
res, err := c.InvokeScript(bw.Bytes(), nil)
res, err := inv.Run(bw.Bytes())
if err != nil {
return fmt.Errorf("can't get container info: %w", err)
}
@ -129,7 +120,7 @@ func restoreContainers(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("can't get NNS contract state: %w", err)
}
ch, err := nnsResolveHash(wCtx.Client, nnsCs.Hash, containerContract+".neofs")
ch, err := nnsResolveHash(wCtx.ReadOnlyInvoker, nnsCs.Hash, containerContract+".neofs")
if err != nil {
return fmt.Errorf("can't fetch container contract hash: %w", err)
}

View file

@ -87,7 +87,7 @@ func deployContractCmd(cmd *cobra.Command, args []string) error {
domain := ctrName + "." + zone
isUpdate, _ := cmd.Flags().GetBool(updateFlag)
if isUpdate {
cs.Hash, err = nnsResolveHash(c.Client, nnsCs.Hash, domain)
cs.Hash, err = nnsResolveHash(c.ReadOnlyInvoker, nnsCs.Hash, domain)
if err != nil {
return fmt.Errorf("can't fetch contract hash from NNS: %w", err)
}

View file

@ -6,10 +6,8 @@ import (
"strings"
"text/tabwriter"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"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/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -17,7 +15,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/nspcc-dev/neofs-contract/nns"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -110,25 +107,9 @@ func dumpContractHashes(cmd *cobra.Command, _ []string) error {
func dumpCustomZoneHashes(cmd *cobra.Command, nnsHash util.Uint160, zone string, c Client) error {
const nnsMaxTokens = 100
inv := invoker.New(c, nil)
// The actual signer is not important here.
account, err := wallet.NewAccount()
if err != nil {
return fmt.Errorf("can't create a temporary account: %w", err)
}
signers := []actor.SignerAccount{{
Signer: transaction.Signer{
Account: account.PrivateKey().GetScriptHash(),
},
Account: account,
}}
a, err := actor.New(c.(*rpcclient.Client), signers)
if err != nil {
return fmt.Errorf("can't get a list of NNS domains: %w", err)
}
arr, err := unwrap.Array(a.CallAndExpandIterator(nnsHash, "tokens", nnsMaxTokens))
arr, err := unwrap.Array(inv.CallAndExpandIterator(nnsHash, "tokens", nnsMaxTokens))
if err != nil {
return fmt.Errorf("can't get a list of NNS domains: %w", err)
}
@ -148,7 +129,7 @@ func dumpCustomZoneHashes(cmd *cobra.Command, nnsHash util.Uint160, zone string,
continue
}
h, err := nnsResolveHash(c, nnsHash, string(bs))
h, err := nnsResolveHash(inv, nnsHash, string(bs))
if err != nil {
continue
}

View file

@ -5,10 +5,10 @@ import (
"fmt"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
@ -24,7 +24,7 @@ func forceNewEpochCmd(cmd *cobra.Command, args []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err)
}
nmHash, err := nnsResolveHash(wCtx.Client, cs.Hash, netmapContract+".neofs")
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, netmapContract+".neofs")
if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err)
}
@ -42,18 +42,13 @@ func forceNewEpochCmd(cmd *cobra.Command, args []string) error {
}
func emitNewEpochCall(bw *io.BufBinWriter, wCtx *initializeContext, nmHash util.Uint160) error {
res, err := invokeFunction(wCtx.Client, nmHash, "epoch", nil, nil)
if err != nil || res.State != vmstate.Halt.String() || len(res.Stack) == 0 {
curr, err := unwrap.Int64(wCtx.ReadOnlyInvoker.Call(nmHash, "epoch"))
if err != nil {
return errors.New("can't fetch current epoch from the netmap contract")
}
bi, err := res.Stack[0].TryInteger()
if err != nil {
return fmt.Errorf("can't parse current epoch: %w", err)
}
newEpoch := bi.Int64() + 1
wCtx.Command.Printf("Current epoch: %s, increase to %d.\n", bi, newEpoch)
newEpoch := curr + 1
wCtx.Command.Printf("Current epoch: %d, increase to %d.\n", curr, newEpoch)
// In NeoFS this is done via Notary contract. Here, however, we can form the
// transaction locally.

View file

@ -183,8 +183,13 @@ func newInitializeContext(cmd *cobra.Command, v *viper.Viper) (*initializeContex
accounts[i] = acc
}
cliCtx, err := defaultClientContext(c, committeeAcc)
if err != nil {
return nil, fmt.Errorf("client context: %w", err)
}
initCtx := &initializeContext{
clientContext: *defaultClientContext(c),
clientContext: *cliCtx,
ConsensusAcc: consensusAcc,
CommitteeAcc: committeeAcc,
ContractWallet: w,
@ -299,7 +304,7 @@ func (c *initializeContext) getSigner(tryGroup bool) transaction.Signer {
return signer
}
groupKey, err := nnsResolveKey(c.Client, nnsCs.Hash, morphClient.NNSGroupKeyName)
groupKey, err := nnsResolveKey(c.ReadOnlyInvoker, nnsCs.Hash, morphClient.NNSGroupKeyName)
if err == nil {
c.groupKey = groupKey
@ -320,12 +325,24 @@ func (c *clientContext) awaitTx(cmd *cobra.Command) error {
}
}
err := awaitTx(cmd, c.Client, c.Hashes)
c.Hashes = c.Hashes[:0]
return err
}
func awaitTx(cmd *cobra.Command, c Client, hashes []util.Uint256) error {
cmd.Println("Waiting for transactions to persist...")
tick := time.NewTicker(c.PollInterval)
// improve TX awaiting process:
// https://github.com/nspcc-dev/neofs-node/issues/1741
const pollInterval = time.Second
const waitDuration = 30 * time.Second
tick := time.NewTicker(pollInterval)
defer tick.Stop()
timer := time.NewTimer(c.WaitDuration)
timer := time.NewTimer(waitDuration)
defer timer.Stop()
at := trigger.Application
@ -333,8 +350,8 @@ func (c *clientContext) awaitTx(cmd *cobra.Command) error {
var retErr error
loop:
for i := range c.Hashes {
res, err := c.Client.GetApplicationLog(c.Hashes[i], &at)
for i := range hashes {
res, err := c.GetApplicationLog(hashes[i], &at)
if err == nil {
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
retErr = fmt.Errorf("tx %d persisted in %s state: %s",
@ -345,7 +362,7 @@ loop:
for {
select {
case <-tick.C:
res, err := c.Client.GetApplicationLog(c.Hashes[i], &at)
res, err := c.GetApplicationLog(hashes[i], &at)
if err == nil {
if retErr == nil && len(res.Executions) > 0 && res.Executions[0].VMState != vmstate.Halt {
retErr = fmt.Errorf("tx %d persisted in %s state: %s",
@ -359,50 +376,34 @@ loop:
}
}
c.Hashes = c.Hashes[:0]
return retErr
}
// sendCommitteeTx creates transaction from script and sends it to RPC.
// Test invocation will be performed and the result will be checked. If tryGroup
// is false, global scope is used for the signer (useful when working with native
// contracts).
// If tryGroup is false, global scope is used for the signer (useful when
// working with native contracts).
func (c *initializeContext) sendCommitteeTx(script []byte, tryGroup bool) error {
sigCount := len(c.CommitteeAcc.Contract.Parameters)
var act *actor.Actor
var err error
signers := make([]actor.SignerAccount, 0, sigCount)
signer := c.getSigner(tryGroup)
for i, w := range c.Wallets {
if i == sigCount {
break
}
acc, err := getWalletAccount(w, committeeAccountName)
if err != nil {
return fmt.Errorf("could not get %s account for %d wallet: %w",
committeeAccountName, i, err)
}
signers = append(signers, actor.SignerAccount{
Signer: signer,
Account: acc,
})
if tryGroup {
act, err = actor.New(c.Client, []actor.SignerAccount{{
Signer: c.getSigner(tryGroup),
Account: c.CommitteeAcc,
}})
} else {
act, err = c.CommitteeAct, nil
}
act, err := actor.New(c.Client, signers)
if err != nil {
return fmt.Errorf("could not create actor: %w", err)
}
txHash, _, err := act.SendTunedRun(script, []transaction.Attribute{{Type: transaction.HighPriority}}, nil)
tx, err := act.MakeUnsignedRun(script, []transaction.Attribute{{Type: transaction.HighPriority}})
if err != nil {
return fmt.Errorf("cound not send transaction: %w", err)
return fmt.Errorf("could not perform test invocation: %w", err)
}
c.Hashes = append(c.Hashes, txHash)
return nil
return c.multiSignAndSend(tx, committeeAccountName)
}
func getWalletAccount(w *wallet.Wallet, typ string) (*wallet.Account, error) {

View file

@ -181,7 +181,7 @@ func (c *initializeContext) updateContracts() error {
// alphabet contracts should be deployed by individual nodes to get different hashes.
for i, acc := range c.Accounts {
ctrHash, err := nnsResolveHash(c.Client, nnsHash, getAlphabetNNSDomain(i))
ctrHash, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, getAlphabetNNSDomain(i))
if err != nil {
return fmt.Errorf("can't resolve hash for contract update: %w", err)
}
@ -219,7 +219,7 @@ func (c *initializeContext) updateContracts() error {
cs := c.getContract(ctrName)
method := updateMethodName
ctrHash, err := nnsResolveHash(c.Client, nnsHash, ctrName+".neofs")
ctrHash, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, ctrName+".neofs")
if err != nil {
if errors.Is(err, errMissingNNSRecord) {
// if contract not found we deploy it instead of update
@ -240,17 +240,9 @@ func (c *initializeContext) updateContracts() error {
}
params := getContractDeployParameters(cs, c.getContractDeployData(ctrName, keysParam))
signer := transaction.Signer{
Account: c.CommitteeAcc.Contract.ScriptHash(),
Scopes: transaction.Global,
}
res, err := invokeFunction(c.Client, invokeHash, method, params, []transaction.Signer{signer})
res, err := c.CommitteeAct.MakeCall(invokeHash, method, params)
if err != nil {
return fmt.Errorf("can't deploy %s contract: %w", ctrName, err)
}
if res.State != vmstate.Halt.String() {
return fmt.Errorf("can't deploy %s contract: %s", ctrName, res.FaultException)
return fmt.Errorf("deploy contract: %w", err)
}
w.WriteBytes(res.Script)
@ -343,18 +335,10 @@ func (c *initializeContext) deployContracts() error {
}
params := getContractDeployParameters(cs, c.getContractDeployData(ctrName, keysParam))
signer := transaction.Signer{
Account: c.CommitteeAcc.Contract.ScriptHash(),
Scopes: transaction.Global,
}
res, err := invokeFunction(c.Client, mgmtHash, deployMethodName, params, []transaction.Signer{signer})
res, err := c.CommitteeAct.MakeCall(mgmtHash, deployMethodName, params...)
if err != nil {
return fmt.Errorf("can't deploy %s contract: %w", ctrName, err)
}
if res.State != vmstate.Halt.String() {
return fmt.Errorf("can't deploy %s contract: %s", ctrName, res.FaultException)
}
if err := c.sendCommitteeTx(res.Script, false); err != nil {
return err

View file

@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/nspcc-dev/neo-go/pkg/core/state"
@ -13,6 +12,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
@ -107,7 +108,7 @@ func (c *initializeContext) emitUpdateNNSGroupScript(bw *io.BufBinWriter, nnsHas
}
if !isAvail {
currentPub, err := nnsResolveKey(c.Client, nnsHash, morphClient.NNSGroupKeyName)
currentPub, err := nnsResolveKey(c.ReadOnlyInvoker, nnsHash, morphClient.NNSGroupKeyName)
if err != nil {
return false, false, err
}
@ -177,7 +178,7 @@ func (c *initializeContext) nnsRegisterDomainScript(nnsHash, expectedHash util.U
return bw.Bytes(), false, nil
}
s, err := nnsResolveHash(c.Client, nnsHash, domain)
s, err := nnsResolveHash(c.ReadOnlyInvoker, nnsHash, domain)
if err != nil {
return nil, false, err
}
@ -203,52 +204,39 @@ func (c *initializeContext) nnsRegisterDomain(nnsHash, expectedHash util.Uint160
}
func (c *initializeContext) nnsRootRegistered(nnsHash util.Uint160, zone string) (bool, error) {
params := []interface{}{"name." + zone}
res, err := invokeFunction(c.Client, nnsHash, "isAvailable", params, nil)
res, err := c.CommitteeAct.Call(nnsHash, "isAvailable", "name."+zone)
if err != nil {
return false, err
}
return res.State == vmstate.Halt.String(), nil
}
var errMissingNNSRecord = errors.New("missing NNS record")
// Returns errMissingNNSRecord if invocation fault exception contains "token not found".
func nnsResolveHash(c Client, nnsHash util.Uint160, domain string) (util.Uint160, error) {
item, err := nnsResolve(c, nnsHash, domain)
func nnsResolveHash(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (util.Uint160, error) {
item, err := nnsResolve(inv, nnsHash, domain)
if err != nil {
return util.Uint160{}, err
}
return parseNNSResolveResult(item)
}
func nnsResolve(c Client, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
result, err := invokeFunction(c, nnsHash, "resolve", []interface{}{domain, int64(nns.TXT)}, nil)
if err != nil {
return nil, fmt.Errorf("`resolve`: %w", err)
}
if result.State != vmstate.Halt.String() {
if strings.Contains(result.FaultException, "token not found") {
return nil, errMissingNNSRecord
}
return nil, fmt.Errorf("invocation failed: %s", result.FaultException)
}
if len(result.Stack) == 0 {
return nil, errors.New("result stack is empty")
}
return result.Stack[len(result.Stack)-1], nil
func nnsResolve(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (stackitem.Item, error) {
return unwrap.Item(inv.Call(nnsHash, "resolve", domain, int64(nns.TXT)))
}
func nnsResolveKey(c Client, nnsHash util.Uint160, domain string) (*keys.PublicKey, error) {
item, err := nnsResolve(c, nnsHash, domain)
func nnsResolveKey(inv *invoker.Invoker, nnsHash util.Uint160, domain string) (*keys.PublicKey, error) {
item, err := nnsResolve(inv, nnsHash, domain)
if err != nil {
return nil, err
}
arr, ok := item.Value().([]stackitem.Item)
if !ok || len(arr) == 0 {
v, ok := item.Value().(stackitem.Null)
if ok {
return nil, errors.New("NNS record is missing")
}
bs, err := arr[0].TryBytes()
bs, err := v.TryBytes()
if err != nil {
return nil, errors.New("malformed response")
}
@ -286,24 +274,16 @@ func parseNNSResolveResult(res stackitem.Item) (util.Uint160, error) {
return util.Uint160{}, errors.New("no valid hashes are found")
}
var errNNSIsAvailableInvalid = errors.New("`isAvailable`: invalid response")
func nnsIsAvailable(c Client, nnsHash util.Uint160, name string) (bool, error) {
switch ct := c.(type) {
case *rpcclient.Client:
return ct.NNSIsAvailable(nnsHash, name)
default:
res, err := invokeFunction(c, nnsHash, "isAvailable", []interface{}{name}, nil)
b, err := unwrap.Bool(invokeFunction(c, nnsHash, "isAvailable", []interface{}{name}, nil))
if err != nil {
return false, err
}
if len(res.Stack) == 0 {
return false, errNNSIsAvailableInvalid
}
b, err := res.Stack[0].TryBool()
if err != nil {
return b, errNNSIsAvailableInvalid
return false, fmt.Errorf("`isAvailable`: invalid response: %w", err)
}
return b, nil
}
}

View file

@ -10,12 +10,11 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
)
// initialAlphabetNEOAmount represents the total amount of GAS distributed between alphabet nodes.
@ -24,16 +23,14 @@ const initialAlphabetNEOAmount = native.NEOTotalSupply
func (c *initializeContext) registerCandidates() error {
neoHash := c.nativeHash(nativenames.Neo)
res, err := invokeFunction(c.Client, neoHash, "getCandidates", nil, nil)
cc, err := unwrap.Array(c.ReadOnlyInvoker.Call(neoHash, "getCandidates"))
if err != nil {
return err
return fmt.Errorf("`getCandidates`: %w", err)
}
if res.State == vmstate.Halt.String() && len(res.Stack) > 0 {
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if ok && len(arr) > 0 {
c.Command.Println("Candidates are already registered.")
return nil
}
if len(cc) > 0 {
c.Command.Println("Candidates are already registered.")
return nil
}
regPrice, err := c.getCandidateRegisterPrice()
@ -75,7 +72,7 @@ func (c *initializeContext) registerCandidates() error {
return fmt.Errorf("can't sign a transaction: %w", err)
}
network, _ := c.Client.GetNetwork()
network := c.CommitteeAct.GetNetwork()
for i := range c.Accounts {
if err := c.Accounts[i].SignTx(network, tx); err != nil {
return fmt.Errorf("can't sign a transaction: %w", err)

View file

@ -43,6 +43,6 @@ func (c *initializeContext) setRolesFinished() (bool, error) {
}
h := c.nativeHash(nativenames.Designation)
pubs, err := getDesignatedByRole(c.Client, h, noderoles.NeoFSAlphabet, height)
pubs, err := getDesignatedByRole(c.ReadOnlyInvoker, h, noderoles.NeoFSAlphabet, height)
return len(pubs) == len(c.Wallets), err
}

View file

@ -24,6 +24,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -32,7 +34,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/viper"
@ -414,16 +415,9 @@ func invokeFunction(c Client, h util.Uint160, method string, parameters []interf
var errGetDesignatedByRoleResponse = errors.New("`getDesignatedByRole`: invalid response")
func getDesignatedByRole(c Client, h util.Uint160, role noderoles.Role, u uint32) (keys.PublicKeys, error) {
res, err := invokeFunction(c, h, "getDesignatedByRole", []interface{}{int64(role), int64(u)}, nil)
func getDesignatedByRole(inv *invoker.Invoker, h util.Uint160, role noderoles.Role, u uint32) (keys.PublicKeys, error) {
arr, err := unwrap.Array(inv.Call(h, "getDesignatedByRole", int64(role), int64(u)))
if err != nil {
return nil, err
}
if res.State != vmstate.Halt.String() || len(res.Stack) == 0 {
return nil, errGetDesignatedByRoleResponse
}
arr, ok := res.Stack[0].Value().([]stackitem.Item)
if !ok {
return nil, errGetDesignatedByRoleResponse
}

View file

@ -14,6 +14,8 @@ import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/network/payload"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"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"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -47,10 +49,10 @@ type Client interface {
}
type clientContext struct {
Client Client
Hashes []util.Uint256
WaitDuration time.Duration
PollInterval time.Duration
Client Client // a raw neo-go client OR a local chain implementation
CommitteeAct *actor.Actor // committee actor with the Global witness scope
ReadOnlyInvoker *invoker.Invoker // R/O contract invoker, does not contain any signer
Hashes []util.Uint256
}
func getN3Client(v *viper.Viper) (Client, error) {
@ -79,12 +81,23 @@ func getN3Client(v *viper.Viper) (Client, error) {
return c, nil
}
func defaultClientContext(c Client) *clientContext {
return &clientContext{
Client: c,
WaitDuration: time.Second * 30,
PollInterval: time.Second,
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,
}})
if err != nil {
return nil, err
}
return &clientContext{
Client: c,
CommitteeAct: commAct,
ReadOnlyInvoker: invoker.New(c, nil),
}, nil
}
func (c *clientContext) sendTx(tx *transaction.Transaction, cmd *cobra.Command, await bool) error {

View file

@ -12,6 +12,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@ -126,8 +127,5 @@ func depositNotary(cmd *cobra.Command, _ []string) error {
return fmt.Errorf("could not send tx: %w", err)
}
cc := defaultClientContext(c)
cc.Hashes = append(cc.Hashes, txHash)
return cc.awaitTx(cmd)
return awaitTx(cmd, c, []util.Uint256{txHash})
}

View file

@ -37,7 +37,7 @@ func removeNodesCmd(cmd *cobra.Command, args []string) error {
return fmt.Errorf("can't get NNS contract info: %w", err)
}
nmHash, err := nnsResolveHash(wCtx.Client, cs.Hash, netmapContract+".neofs")
nmHash, err := nnsResolveHash(wCtx.ReadOnlyInvoker, cs.Hash, netmapContract+".neofs")
if err != nil {
return fmt.Errorf("can't get netmap contract hash: %w", err)
}

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
@ -765,11 +766,6 @@ func testInvokeMethod(key keys.PrivateKey, method string, args ...interface{}) (
return nil, fmt.Errorf("NNS contract resolving: %w", err)
}
subnetHash, err := nnsResolveHash(c, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return nil, fmt.Errorf("subnet hash resolving: %w", err)
}
cosigner := []transaction.Signer{
{
Account: key.PublicKey().GetScriptHash(),
@ -777,7 +773,14 @@ func testInvokeMethod(key keys.PrivateKey, method string, args ...interface{}) (
},
}
res, err := invokeFunction(c, subnetHash, method, args, cosigner)
inv := invoker.New(c, cosigner)
subnetHash, err := nnsResolveHash(inv, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return nil, fmt.Errorf("subnet hash resolving: %w", err)
}
res, err := inv.Call(subnetHash, method, args...)
if err != nil {
return nil, fmt.Errorf("invocation parameters prepararion: %w", err)
}
@ -837,11 +840,6 @@ func invokeNonNotary(c Client, key keys.PrivateKey, method string, args ...inter
return fmt.Errorf("NNS contract resolving: %w", err)
}
subnetHash, err := nnsResolveHash(c, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return fmt.Errorf("subnet hash resolving: %w", err)
}
acc := wallet.NewAccountFromPrivateKey(&key)
cosigner := []transaction.Signer{
@ -858,7 +856,14 @@ func invokeNonNotary(c Client, key keys.PrivateKey, method string, args ...inter
},
}
test, err := invokeFunction(c, subnetHash, method, args, cosigner)
inv := invoker.New(c, cosigner)
subnetHash, err := nnsResolveHash(inv, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return fmt.Errorf("subnet hash resolving: %w", err)
}
test, err := inv.Call(subnetHash, method, args...)
if err != nil {
return fmt.Errorf("test invocation: %w", err)
}
@ -882,11 +887,6 @@ func invokeNotary(c Client, key keys.PrivateKey, method string, notaryHash util.
return fmt.Errorf("NNS contract resolving: %w", err)
}
subnetHash, err := nnsResolveHash(c, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return fmt.Errorf("subnet hash resolving: %w", err)
}
alphabet, err := c.GetCommittee()
if err != nil {
return fmt.Errorf("alphabet list: %w", err)
@ -902,8 +902,15 @@ func invokeNotary(c Client, key keys.PrivateKey, method string, notaryHash util.
return fmt.Errorf("cosigners collecting: %w", err)
}
inv := invoker.New(c, cosigners)
subnetHash, err := nnsResolveHash(inv, nnsCs.Hash, subnetContract+".neofs")
if err != nil {
return fmt.Errorf("subnet hash resolving: %w", err)
}
// make test invocation of the method
test, err := invokeFunction(c, subnetHash, method, args, cosigners)
test, err := inv.Call(subnetHash, method, args...)
if err != nil {
return fmt.Errorf("test invocation: %w", err)
}
@ -974,7 +981,7 @@ func invokeNotary(c Client, key keys.PrivateKey, method string, notaryHash util.
func notaryCosigners(c Client, notaryHash util.Uint160, nnsCs *state.Contract,
key keys.PrivateKey, alphabetAccount util.Uint160) ([]transaction.Signer, error) {
proxyHash, err := nnsResolveHash(c, nnsCs.Hash, proxyContract+".neofs")
proxyHash, err := nnsResolveHash(invoker.New(c, nil), nnsCs.Hash, proxyContract+".neofs")
if err != nil {
return nil, fmt.Errorf("proxy hash resolving: %w", err)
}