rpcclient: add CallAndExpandIterator to Invoker

And deprecate Client.InvokeAndPackIteratorResults.
This commit is contained in:
Roman Khimov 2022-08-01 15:27:36 +03:00
parent b52282c3c7
commit 31c9ae6339
6 changed files with 36 additions and 22 deletions

View file

@ -111,6 +111,9 @@ func topMapFromStack(st []stackitem.Item) (*stackitem.Map, error) {
// retrieve iterator values via single `invokescript` JSON-RPC call. It returns
// maxIteratorResultItems items at max which is set to
// config.DefaultMaxIteratorResultItems by default.
//
// Deprecated: please use more convenient and powerful invoker.Invoker interface with
// CallAndExpandIterator method. This method will be removed in future versions.
func (c *Client) InvokeAndPackIteratorResults(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer, maxIteratorResultItems ...int) (*result.Invoke, error) {
max := config.DefaultMaxIteratorResultItems
if len(maxIteratorResultItems) != 0 {

View file

@ -1,6 +1,8 @@
package invoker
import (
"fmt"
"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/smartcontract"
@ -125,6 +127,22 @@ func (v *Invoker) Call(contract util.Uint160, operation string, params ...interf
return v.client.InvokeFunction(contract, operation, ps, v.signers)
}
// CallAndExpandIterator creates a script containing a call of the specified method
// of a contract with given parameters (similar to how Call operates). But then this
// script contains additional code that expects that the result of the first call is
// an iterator. This iterator is traversed extracting values from it and adding them
// into an array until maxItems is reached or iterator has no more elements. The
// result of the whole script is an array containing up to maxResultItems elements
// from the iterator returned from the contract's method call. This script is executed
// using regular JSON-API (according to the way Iterator is set up).
func (v *Invoker) CallAndExpandIterator(contract util.Uint160, method string, maxItems int, params ...interface{}) (*result.Invoke, error) {
bytes, err := smartcontract.CreateCallAndUnwrapIteratorScript(contract, method, maxItems, params...)
if err != nil {
return nil, fmt.Errorf("iterator unwrapper script: %w", err)
}
return v.Run(bytes)
}
// Verify invokes contract's verify method in the verification context with
// Invoker-specific signers and given witnesses and parameters.
func (v *Invoker) Verify(contract util.Uint160, witnesses []transaction.Witness, params ...interface{}) (*result.Invoke, error) {

View file

@ -86,6 +86,13 @@ func TestInvoker(t *testing.T) {
_, err = inv.Call(util.Uint160{}, "method", make(map[int]int))
require.Error(t, err)
res, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, 42)
require.NoError(t, err)
require.Equal(t, resExp, res)
_, err = inv.CallAndExpandIterator(util.Uint160{}, "method", 10, make(map[int]int))
require.Error(t, err)
}
t.Run("standard", func(t *testing.T) {
testInv(t, New(ri, nil))

View file

@ -7,12 +7,12 @@ import (
"fmt"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"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/nns"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
)
@ -118,12 +118,7 @@ func (c *Client) NNSGetAllRecords(nnsHash util.Uint160, name string) (uuid.UUID,
// that no iterator session is used to retrieve values from iterator. Instead, unpacking
// VM script is created and invoked via `invokescript` JSON-RPC call.
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
result, err := c.InvokeAndPackIteratorResults(nnsHash, "getAllRecords", []smartcontract.Parameter{
{
Type: smartcontract.StringType,
Value: name,
},
}, nil)
result, err := c.reader.CallAndExpandIterator(nnsHash, "getAllRecords", config.DefaultMaxIteratorResultItems, name)
if err != nil {
return nil, err
}

View file

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
@ -101,12 +102,7 @@ func (c *Client) NEP11TokensOf(tokenHash util.Uint160, owner util.Uint160) (uuid
// is used to retrieve values from iterator. Instead, unpacking VM script is created and invoked via
// `invokescript` JSON-RPC call.
func (c *Client) NEP11UnpackedTokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
result, err := c.InvokeAndPackIteratorResults(tokenHash, "tokensOf", []smartcontract.Parameter{
{
Type: smartcontract.Hash160Type,
Value: owner,
},
}, nil)
result, err := c.reader.CallAndExpandIterator(tokenHash, "tokensOf", config.DefaultMaxIteratorResultItems, owner)
if err != nil {
return nil, err
}
@ -194,12 +190,7 @@ func (c *Client) NEP11DOwnerOf(tokenHash util.Uint160, tokenID []byte) (uuid.UUI
// iterator session is used to retrieve values from iterator. Instead, unpacking VM
// script is created and invoked via `invokescript` JSON-RPC call.
func (c *Client) NEP11DUnpackedOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
result, err := c.InvokeAndPackIteratorResults(tokenHash, "ownerOf", []smartcontract.Parameter{
{
Type: smartcontract.ByteArrayType,
Value: tokenID,
},
}, nil)
result, err := c.reader.CallAndExpandIterator(tokenHash, "ownerOf", config.DefaultMaxIteratorResultItems, tokenID)
if err != nil {
return nil, err
}
@ -261,7 +252,7 @@ func (c *Client) NEP11Tokens(tokenHash util.Uint160) (uuid.UUID, result.Iterator
// iterator session is used to retrieve values from iterator. Instead, unpacking
// VM script is created and invoked via `invokescript` JSON-RPC call.
func (c *Client) NEP11UnpackedTokens(tokenHash util.Uint160) ([][]byte, error) {
result, err := c.InvokeAndPackIteratorResults(tokenHash, "tokens", []smartcontract.Parameter{}, nil)
result, err := c.reader.CallAndExpandIterator(tokenHash, "tokens", config.DefaultMaxIteratorResultItems)
if err != nil {
return nil, err
}

View file

@ -1280,7 +1280,7 @@ func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
require.NoError(t, err)
t.Run("default max items constraint", func(t *testing.T) {
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil)
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
require.NoError(t, err)
require.Equal(t, vmstate.Halt.String(), res.State)
require.Equal(t, 1, len(res.Stack))
@ -1296,7 +1296,7 @@ func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
})
t.Run("custom max items constraint", func(t *testing.T) {
max := 123
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil, max)
res, err := c.InvokeAndPackIteratorResults(storageHash, "iterateOverValues", []smartcontract.Parameter{}, nil, max) //nolint:staticcheck // SA1019: c.InvokeAndPackIteratorResults is deprecated
require.NoError(t, err)
require.Equal(t, vmstate.Halt.String(), res.State)
require.Equal(t, 1, len(res.Stack))