Merge pull request #2683 from nspcc-dev/historic-cli
Historic calls from CLI
This commit is contained in:
commit
a1ca28446d
5 changed files with 210 additions and 80 deletions
|
@ -602,6 +602,39 @@ func TestContract_TestInvokeScript(t *testing.T) {
|
|||
"--rpc-endpoint", "http://123456789",
|
||||
"--in", goodNef)
|
||||
})
|
||||
t.Run("good", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--in", goodNef)
|
||||
})
|
||||
t.Run("good with hashed signer", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--in", goodNef, "--", util.Uint160{1, 2, 3}.StringLE())
|
||||
})
|
||||
t.Run("good with addressed signer", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--in", goodNef, "--", address.Uint160ToString(util.Uint160{1, 2, 3}))
|
||||
})
|
||||
t.Run("historic, invalid", func(t *testing.T) {
|
||||
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", "bad",
|
||||
"--in", goodNef)
|
||||
})
|
||||
t.Run("historic, index", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", "0",
|
||||
"--in", goodNef)
|
||||
})
|
||||
t.Run("historic, hash", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", e.Chain.GetHeaderHash(0).StringLE(),
|
||||
"--in", goodNef)
|
||||
})
|
||||
}
|
||||
|
||||
func TestComlileAndInvokeFunction(t *testing.T) {
|
||||
|
@ -618,16 +651,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
"--config", "testdata/deploy/neo-go.yml",
|
||||
"--out", nefName, "--manifest", manifestName)
|
||||
|
||||
// Check that it is possible to invoke before deploy.
|
||||
// This doesn't make much sense, because every method has an offset
|
||||
// which is contained in the manifest. This should be either removed or refactored.
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--in", nefName, "--", util.Uint160{1, 2, 3}.StringLE())
|
||||
e.Run(t, "neo-go", "contract", "testinvokescript",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--in", nefName, "--", address.Uint160ToString(util.Uint160{1, 2, 3}))
|
||||
|
||||
tmp := t.TempDir()
|
||||
configPath := filepath.Join(tmp, "config.yaml")
|
||||
cfg := config.Wallet{
|
||||
|
@ -689,11 +712,14 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
|
||||
e.Run(t, cmd...)
|
||||
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte("on create|sub create"), res.Stack[0].Value())
|
||||
checkGetValueOut := func(str string) {
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vmstate.Halt.String(), res.State, res.FaultException)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte(str), res.Stack[0].Value())
|
||||
}
|
||||
checkGetValueOut("on create|sub create")
|
||||
|
||||
// deploy verification contract
|
||||
hVerify := deployVerifyContract(t, e)
|
||||
|
@ -866,6 +892,12 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
})
|
||||
})
|
||||
|
||||
var (
|
||||
hashBeforeUpdate util.Uint256
|
||||
indexBeforeUpdate uint32
|
||||
indexAfterUpdate uint32
|
||||
stateBeforeUpdate util.Uint256
|
||||
)
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
nefName := filepath.Join(tmpDir, "updated.nef")
|
||||
manifestName := filepath.Join(tmpDir, "updated.manifest.json")
|
||||
|
@ -884,6 +916,11 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
rawManifest, err := os.ReadFile(manifestName)
|
||||
require.NoError(t, err)
|
||||
|
||||
indexBeforeUpdate = e.Chain.BlockHeight()
|
||||
hashBeforeUpdate = e.Chain.CurrentHeaderHash()
|
||||
mptBeforeUpdate, err := e.Chain.GetStateRoot(indexBeforeUpdate)
|
||||
require.NoError(t, err)
|
||||
stateBeforeUpdate = mptBeforeUpdate.Root
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
|
@ -895,16 +932,40 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
|||
)
|
||||
e.checkTxPersisted(t, "Sent invocation transaction ")
|
||||
|
||||
indexAfterUpdate = e.Chain.BlockHeight()
|
||||
e.In.WriteString("one\r")
|
||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
h.StringLE(), "getValue")
|
||||
|
||||
res := new(result.Invoke)
|
||||
require.NoError(t, json.Unmarshal(e.Out.Bytes(), res))
|
||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||
require.Len(t, res.Stack, 1)
|
||||
require.Equal(t, []byte("on update|sub update"), res.Stack[0].Value())
|
||||
checkGetValueOut("on update|sub update")
|
||||
})
|
||||
t.Run("historic", func(t *testing.T) {
|
||||
t.Run("bad ref", func(t *testing.T) {
|
||||
e.RunWithError(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", "bad",
|
||||
h.StringLE(), "getValue")
|
||||
})
|
||||
for name, ref := range map[string]string{
|
||||
"by index": strconv.FormatUint(uint64(indexBeforeUpdate), 10),
|
||||
"by block hash": hashBeforeUpdate.StringLE(),
|
||||
"by state hash": stateBeforeUpdate.StringLE(),
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", ref,
|
||||
h.StringLE(), "getValue")
|
||||
})
|
||||
checkGetValueOut("on create|sub create")
|
||||
}
|
||||
t.Run("updated historic", func(t *testing.T) {
|
||||
e.Run(t, "neo-go", "contract", "testinvokefunction",
|
||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||
"--historic", strconv.FormatUint(uint64(indexAfterUpdate), 10),
|
||||
h.StringLE(), "getValue")
|
||||
checkGetValueOut("on update|sub update")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -161,6 +161,7 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
}
|
||||
|
||||
tokenID := mint(t)
|
||||
var hashBeforeTransfer = e.Chain.CurrentHeaderHash()
|
||||
|
||||
// check the balance
|
||||
cmdCheckBalance := []string{"neo-go", "wallet", "nep11", "balance",
|
||||
|
@ -358,6 +359,24 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
// check balance after transfer
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, nftOwnerAddr)
|
||||
|
||||
// historic calls still remember the good old days.
|
||||
cmdOwnerOf = append(cmdOwnerOf, "--historic", hashBeforeTransfer.StringLE())
|
||||
e.Run(t, cmdOwnerOf...)
|
||||
e.checkNextLine(t, nftOwnerAddr)
|
||||
|
||||
cmdTokensOf = append(cmdTokensOf, "--historic", hashBeforeTransfer.StringLE())
|
||||
e.Run(t, cmdTokensOf...)
|
||||
require.Equal(t, hex.EncodeToString(tokenID), e.getNextLine(t))
|
||||
|
||||
cmdTokens = append(cmdTokens, "--historic", hashBeforeTransfer.StringLE())
|
||||
e.Run(t, cmdTokens...)
|
||||
require.Equal(t, hex.EncodeToString(tokenID), e.getNextLine(t))
|
||||
|
||||
// this one is not affected by transfer, but anyway
|
||||
cmdProperties = append(cmdProperties, "--historic", hashBeforeTransfer.StringLE())
|
||||
e.Run(t, cmdProperties...)
|
||||
require.Equal(t, fmt.Sprintf(`{"name":"HASHY %s"}`, base64.StdEncoding.EncodeToString(tokenID)), e.getNextLine(t))
|
||||
}
|
||||
|
||||
func TestNEP11_D_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||
|
|
|
@ -6,10 +6,14 @@ package options
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
|
@ -42,7 +46,14 @@ var RPC = []cli.Flag{
|
|||
},
|
||||
}
|
||||
|
||||
// Historic is a flag for commands that can perform historic invocations.
|
||||
var Historic = cli.StringFlag{
|
||||
Name: "historic",
|
||||
Usage: "Use historic state (height, block hash or state root hash)",
|
||||
}
|
||||
|
||||
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
||||
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
||||
|
||||
// GetNetwork examines Context's flags and returns the appropriate network. It
|
||||
// defaults to PrivNet if no flags are given.
|
||||
|
@ -85,3 +96,35 @@ func GetRPCClient(gctx context.Context, ctx *cli.Context) (*rpcclient.Client, cl
|
|||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// GetInvoker returns an invoker using the given RPC client, context and signers.
|
||||
// It parses "--historic" parameter to adjust it.
|
||||
func GetInvoker(c *rpcclient.Client, ctx *cli.Context, signers []transaction.Signer) (*invoker.Invoker, cli.ExitCoder) {
|
||||
historic := ctx.String("historic")
|
||||
if historic == "" {
|
||||
return invoker.New(c, signers), nil
|
||||
}
|
||||
if index, err := strconv.ParseUint(historic, 10, 32); err == nil {
|
||||
return invoker.NewHistoricAtHeight(uint32(index), c, signers), nil
|
||||
}
|
||||
if u256, err := util.Uint256DecodeStringLE(historic); err == nil {
|
||||
// Might as well be a block hash, but it makes no practical difference.
|
||||
return invoker.NewHistoricWithState(u256, c, signers), nil
|
||||
}
|
||||
return nil, cli.NewExitError(errInvalidHistoric, 1)
|
||||
}
|
||||
|
||||
// GetRPCWithInvoker combines GetRPCClient with GetInvoker for cases where it's
|
||||
// appropriate to do so.
|
||||
func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transaction.Signer) (*rpcclient.Client, *invoker.Invoker, cli.ExitCoder) {
|
||||
c, err := GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
inv, err := GetInvoker(c, ctx, signers)
|
||||
if err != nil {
|
||||
c.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return c, inv, err
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||
"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/rpcclient/management"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
|
@ -110,8 +111,11 @@ func NewCommands() []cli.Command {
|
|||
Name: "in, i",
|
||||
Usage: "Input location of the .nef file that needs to be invoked",
|
||||
},
|
||||
options.Historic,
|
||||
}
|
||||
testInvokeScriptFlags = append(testInvokeScriptFlags, options.RPC...)
|
||||
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
||||
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
||||
invokeFunctionFlags := []cli.Flag{
|
||||
walletFlag,
|
||||
walletConfigFlag,
|
||||
|
@ -213,7 +217,7 @@ func NewCommands() []cli.Command {
|
|||
{
|
||||
Name: "testinvokefunction",
|
||||
Usage: "invoke deployed contract on the blockchain (test mode)",
|
||||
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [signers...]",
|
||||
UsageText: "neo-go contract testinvokefunction -r endpoint [--historic index/hash] scripthash [method] [arguments...] [--] [signers...]",
|
||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||
arguments and signers (sender is not included by default). If no method is given
|
||||
"" is passed to the script, if no arguments are given, an empty array is
|
||||
|
@ -328,12 +332,12 @@ func NewCommands() []cli.Command {
|
|||
`CustomContracts:1011120009070e030d0f0e020d0c06050e030c02:0x1211100009070e030d0f0e020d0c06050e030c02'
|
||||
`,
|
||||
Action: testInvokeFunction,
|
||||
Flags: options.RPC,
|
||||
Flags: testInvokeFunctionFlags,
|
||||
},
|
||||
{
|
||||
Name: "testinvokescript",
|
||||
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
|
||||
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [signers...]",
|
||||
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [--historic index/hash] [signers...]",
|
||||
Description: `Executes given compiled AVM instructions in NEF format with the given set of
|
||||
signers not included sender by default. See testinvokefunction documentation
|
||||
for the details about parameters.
|
||||
|
@ -608,8 +612,9 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
err error
|
||||
exitErr *cli.ExitError
|
||||
operation string
|
||||
params = make([]smartcontract.Parameter, 0)
|
||||
params []interface{}
|
||||
paramsStart = 1
|
||||
scParams []smartcontract.Parameter
|
||||
cosigners []transaction.Signer
|
||||
cosignersOffset = 0
|
||||
)
|
||||
|
@ -629,10 +634,14 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
paramsStart++
|
||||
|
||||
if len(args) > paramsStart {
|
||||
cosignersOffset, params, err = cmdargs.ParseParams(args[paramsStart:], true)
|
||||
cosignersOffset, scParams, err = cmdargs.ParseParams(args[paramsStart:], true)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
params = make([]interface{}, len(scParams))
|
||||
for i := range scParams {
|
||||
params[i] = scParams[i]
|
||||
}
|
||||
}
|
||||
|
||||
cosignersStart := paramsStart + cosignersOffset
|
||||
|
@ -653,18 +662,17 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
|||
defer w.Close()
|
||||
}
|
||||
|
||||
_, err = invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
||||
return err
|
||||
return invokeWithArgs(ctx, acc, w, script, operation, params, cosigners)
|
||||
}
|
||||
|
||||
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []smartcontract.Parameter, cosigners []transaction.Signer) (util.Uint160, error) {
|
||||
func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet, script util.Uint160, operation string, params []interface{}, cosigners []transaction.Signer) error {
|
||||
var (
|
||||
err error
|
||||
gas, sysgas fixedn.Fixed8
|
||||
signersAccounts []actor.SignerAccount
|
||||
resp *result.Invoke
|
||||
sender util.Uint160
|
||||
signAndPush = acc != nil
|
||||
inv *invoker.Invoker
|
||||
act *actor.Actor
|
||||
)
|
||||
if signAndPush {
|
||||
|
@ -672,35 +680,37 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
||||
signersAccounts, err = cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.None)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||
}
|
||||
sender = signersAccounts[0].Signer.Account
|
||||
}
|
||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
if err != nil {
|
||||
return sender, err
|
||||
return err
|
||||
}
|
||||
if signAndPush {
|
||||
act, err = actor.New(c, signersAccounts)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
||||
}
|
||||
inv = &act.Invoker
|
||||
} else {
|
||||
inv, err = options.GetInvoker(c, ctx, cosigners)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
out := ctx.String("out")
|
||||
// It's a bit easier to keep this as is (not using invoker.Invoker)
|
||||
// during transition period. Mostly because of the need to convert params
|
||||
// to []interface{}.
|
||||
resp, err = c.InvokeFunction(script, operation, params, cosigners)
|
||||
resp, err = inv.Call(script, operation, params...)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
if resp.State != "HALT" {
|
||||
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s", resp.State, resp.FaultException)
|
||||
if !signAndPush {
|
||||
return sender, cli.NewExitError(errText, 1)
|
||||
return cli.NewExitError(errText, 1)
|
||||
}
|
||||
|
||||
action := "send"
|
||||
|
@ -710,25 +720,25 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
process = "Saving"
|
||||
}
|
||||
if !ctx.Bool("force") {
|
||||
return sender, cli.NewExitError(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1)
|
||||
return cli.NewExitError(errText+".\nUse --force flag to "+action+" the transaction anyway.", 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, errText+".\n"+process+" transaction...")
|
||||
}
|
||||
if !signAndPush {
|
||||
b, err := json.MarshalIndent(resp, "", " ")
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
fmt.Fprintln(ctx.App.Writer, string(b))
|
||||
} else {
|
||||
if len(resp.Script) == 0 {
|
||||
return sender, cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
||||
return cli.NewExitError(errors.New("no script returned from the RPC node"), 1)
|
||||
}
|
||||
ver := act.GetVersion()
|
||||
tx, err := act.MakeUnsignedUncheckedRun(resp.Script, resp.GasConsumed+int64(sysgas), nil)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||
return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||
}
|
||||
tx.NetworkFee += int64(gas)
|
||||
if out != "" {
|
||||
|
@ -736,7 +746,7 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
tx.ValidUntilBlock += (ver.Protocol.MaxValidUntilBlockIncrement - uint32(ver.Protocol.ValidatorsCount)) - 2
|
||||
m := act.GetNetwork()
|
||||
if err := paramcontext.InitAndSave(m, tx, acc, out); err != nil {
|
||||
return sender, cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
||||
} else {
|
||||
|
@ -744,7 +754,7 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
promptTime := time.Now()
|
||||
err := input.ConfirmTx(ctx.App.Writer, tx)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(err, 1)
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
waitTime := time.Since(promptTime)
|
||||
// Compensate for confirmation waiting.
|
||||
|
@ -752,13 +762,13 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
|||
}
|
||||
txHash, _, err := act.SignAndSend(tx)
|
||||
if err != nil {
|
||||
return sender, cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
|
||||
return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1)
|
||||
}
|
||||
fmt.Fprintf(ctx.App.Writer, "Sent invocation transaction %s\n", txHash.StringLE())
|
||||
}
|
||||
}
|
||||
|
||||
return sender, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func testInvokeScript(ctx *cli.Context) error {
|
||||
|
@ -784,12 +794,12 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, signers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := c.InvokeScript(nefFile.Script, signers)
|
||||
resp, err := inv.Run(nefFile.Script)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -925,16 +935,8 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
return cli.NewExitError(fmt.Errorf("failed to read manifest file: %w", err), 1)
|
||||
}
|
||||
|
||||
appCallParams := []smartcontract.Parameter{
|
||||
{
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: f,
|
||||
},
|
||||
{
|
||||
Type: smartcontract.ByteArrayType,
|
||||
Value: manifestBytes,
|
||||
},
|
||||
}
|
||||
var appCallParams = []interface{}{f, manifestBytes}
|
||||
|
||||
signOffset, data, err := cmdargs.ParseParams(ctx.Args(), true)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("unable to parse 'data' parameter: %w", err), 1)
|
||||
|
@ -951,6 +953,7 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||
}
|
||||
defer w.Close()
|
||||
sender := acc.ScriptHash()
|
||||
|
||||
cosigners, sgnErr := cmdargs.GetSignersFromContext(ctx, signOffset)
|
||||
if sgnErr != nil {
|
||||
|
@ -962,7 +965,7 @@ func contractDeploy(ctx *cli.Context) error {
|
|||
}}
|
||||
}
|
||||
|
||||
sender, extErr := invokeWithArgs(ctx, acc, w, management.Hash, "deploy", appCallParams, cosigners)
|
||||
extErr := invokeWithArgs(ctx, acc, w, management.Hash, "deploy", appCallParams, cosigners)
|
||||
if extErr != nil {
|
||||
return extErr
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"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/rpcclient/nep11"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -116,50 +115,55 @@ func newNEP11Commands() []cli.Command {
|
|||
{
|
||||
Name: "properties",
|
||||
Usage: "print properties of NEP-11 token",
|
||||
UsageText: "properties --rpc-endpoint <node> --timeout <time> --token <hash> --id <token-id>",
|
||||
UsageText: "properties --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||
Action: printNEP11Properties,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
tokenID,
|
||||
options.Historic,
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "ownerOf",
|
||||
Usage: "print owner of non-divisible NEP-11 token with the specified ID",
|
||||
UsageText: "ownerOf --rpc-endpoint <node> --timeout <time> --token <hash> --id <token-id>",
|
||||
UsageText: "ownerOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||
Action: printNEP11NDOwner,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
tokenID,
|
||||
options.Historic,
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "ownerOfD",
|
||||
Usage: "print set of owners of divisible NEP-11 token with the specified ID (" + maxIters + " will be printed at max)",
|
||||
UsageText: "ownerOfD --rpc-endpoint <node> --timeout <time> --token <hash> --id <token-id>",
|
||||
UsageText: "ownerOfD --rpc-endpoint <node> [--timeout <time>] --token <hash> --id <token-id> [--historic <block/hash>]",
|
||||
Action: printNEP11DOwner,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
tokenID,
|
||||
options.Historic,
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "tokensOf",
|
||||
Usage: "print list of tokens IDs for the specified NFT owner (" + maxIters + " will be printed at max)",
|
||||
UsageText: "tokensOf --rpc-endpoint <node> --timeout <time> --token <hash> --address <addr>",
|
||||
UsageText: "tokensOf --rpc-endpoint <node> [--timeout <time>] --token <hash> --address <addr> [--historic <block/hash>]",
|
||||
Action: printNEP11TokensOf,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
ownerAddressFlag,
|
||||
options.Historic,
|
||||
}, options.RPC...),
|
||||
},
|
||||
{
|
||||
Name: "tokens",
|
||||
Usage: "print list of tokens IDs minted by the specified NFT (optional method; " + maxIters + " will be printed at max)",
|
||||
UsageText: "tokens --rpc-endpoint <node> --timeout <time> --token <hash>",
|
||||
UsageText: "tokens --rpc-endpoint <node> [--timeout <time>] --token <hash> [--historic <block/hash>]",
|
||||
Action: printNEP11Tokens,
|
||||
Flags: append([]cli.Flag{
|
||||
tokenAddressFlag,
|
||||
options.Historic,
|
||||
}, options.RPC...),
|
||||
},
|
||||
}
|
||||
|
@ -256,13 +260,13 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return err
|
||||
}
|
||||
|
||||
if divisible {
|
||||
n11 := nep11.NewDivisibleReader(invoker.New(c, nil), tokenHash.Uint160())
|
||||
n11 := nep11.NewDivisibleReader(inv, tokenHash.Uint160())
|
||||
result, err := n11.OwnerOfExpanded(tokenIDBytes, config.DefaultMaxIteratorResultItems)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 divisible `ownerOf` method: %s", err.Error()), 1)
|
||||
|
@ -271,7 +275,7 @@ func printNEP11Owner(ctx *cli.Context, divisible bool) error {
|
|||
fmt.Fprintln(ctx.App.Writer, address.Uint160ToString(h))
|
||||
}
|
||||
} else {
|
||||
n11 := nep11.NewNonDivisibleReader(invoker.New(c, nil), tokenHash.Uint160())
|
||||
n11 := nep11.NewNonDivisibleReader(inv, tokenHash.Uint160())
|
||||
result, err := n11.OwnerOf(tokenIDBytes)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 non-divisible `ownerOf` method: %s", err.Error()), 1)
|
||||
|
@ -297,12 +301,12 @@ func printNEP11TokensOf(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return err
|
||||
}
|
||||
|
||||
n11 := nep11.NewBaseReader(invoker.New(c, nil), tokenHash.Uint160())
|
||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||
result, err := n11.TokensOfExpanded(acc.Uint160(), config.DefaultMaxIteratorResultItems)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `tokensOf` method: %s", err.Error()), 1)
|
||||
|
@ -327,12 +331,12 @@ func printNEP11Tokens(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return err
|
||||
}
|
||||
|
||||
n11 := nep11.NewBaseReader(invoker.New(c, nil), tokenHash.Uint160())
|
||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||
result, err := n11.TokensExpanded(config.DefaultMaxIteratorResultItems)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call optional NEP-11 `tokens` method: %s", err.Error()), 1)
|
||||
|
@ -366,12 +370,12 @@ func printNEP11Properties(ctx *cli.Context) error {
|
|||
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
c, err := options.GetRPCClient(gctx, ctx)
|
||||
_, inv, err := options.GetRPCWithInvoker(gctx, ctx, nil)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
return err
|
||||
}
|
||||
|
||||
n11 := nep11.NewBaseReader(invoker.New(c, nil), tokenHash.Uint160())
|
||||
n11 := nep11.NewBaseReader(inv, tokenHash.Uint160())
|
||||
result, err := n11.Properties(tokenIDBytes)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Sprintf("failed to call NEP-11 `properties` method: %s", err.Error()), 1)
|
||||
|
|
Loading…
Reference in a new issue