rpcclient: add CallAndExpandIterator to Invoker
And deprecate Client.InvokeAndPackIteratorResults.
This commit is contained in:
parent
b52282c3c7
commit
31c9ae6339
6 changed files with 36 additions and 22 deletions
|
@ -111,6 +111,9 @@ func topMapFromStack(st []stackitem.Item) (*stackitem.Map, error) {
|
||||||
// retrieve iterator values via single `invokescript` JSON-RPC call. It returns
|
// retrieve iterator values via single `invokescript` JSON-RPC call. It returns
|
||||||
// maxIteratorResultItems items at max which is set to
|
// maxIteratorResultItems items at max which is set to
|
||||||
// config.DefaultMaxIteratorResultItems by default.
|
// 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) {
|
func (c *Client) InvokeAndPackIteratorResults(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer, maxIteratorResultItems ...int) (*result.Invoke, error) {
|
||||||
max := config.DefaultMaxIteratorResultItems
|
max := config.DefaultMaxIteratorResultItems
|
||||||
if len(maxIteratorResultItems) != 0 {
|
if len(maxIteratorResultItems) != 0 {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package invoker
|
package invoker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"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/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"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)
|
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
|
// Verify invokes contract's verify method in the verification context with
|
||||||
// Invoker-specific signers and given witnesses and parameters.
|
// Invoker-specific signers and given witnesses and parameters.
|
||||||
func (v *Invoker) Verify(contract util.Uint160, witnesses []transaction.Witness, params ...interface{}) (*result.Invoke, error) {
|
func (v *Invoker) Verify(contract util.Uint160, witnesses []transaction.Witness, params ...interface{}) (*result.Invoke, error) {
|
||||||
|
|
|
@ -86,6 +86,13 @@ func TestInvoker(t *testing.T) {
|
||||||
|
|
||||||
_, err = inv.Call(util.Uint160{}, "method", make(map[int]int))
|
_, err = inv.Call(util.Uint160{}, "method", make(map[int]int))
|
||||||
require.Error(t, err)
|
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) {
|
t.Run("standard", func(t *testing.T) {
|
||||||
testInv(t, New(ri, nil))
|
testInv(t, New(ri, nil))
|
||||||
|
|
|
@ -7,12 +7,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"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/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
"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/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"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/rpcclient/nns"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"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
|
// that no iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||||
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
|
func (c *Client) NNSUnpackedGetAllRecords(nnsHash util.Uint160, name string) ([]nns.RecordState, error) {
|
||||||
result, err := c.InvokeAndPackIteratorResults(nnsHash, "getAllRecords", []smartcontract.Parameter{
|
result, err := c.reader.CallAndExpandIterator(nnsHash, "getAllRecords", config.DefaultMaxIteratorResultItems, name)
|
||||||
{
|
|
||||||
Type: smartcontract.StringType,
|
|
||||||
Value: name,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"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/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"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/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
|
// is used to retrieve values from iterator. Instead, unpacking VM script is created and invoked via
|
||||||
// `invokescript` JSON-RPC call.
|
// `invokescript` JSON-RPC call.
|
||||||
func (c *Client) NEP11UnpackedTokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
|
func (c *Client) NEP11UnpackedTokensOf(tokenHash util.Uint160, owner util.Uint160) ([][]byte, error) {
|
||||||
result, err := c.InvokeAndPackIteratorResults(tokenHash, "tokensOf", []smartcontract.Parameter{
|
result, err := c.reader.CallAndExpandIterator(tokenHash, "tokensOf", config.DefaultMaxIteratorResultItems, owner)
|
||||||
{
|
|
||||||
Type: smartcontract.Hash160Type,
|
|
||||||
Value: owner,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// iterator session is used to retrieve values from iterator. Instead, unpacking VM
|
||||||
// script is created and invoked via `invokescript` JSON-RPC call.
|
// script is created and invoked via `invokescript` JSON-RPC call.
|
||||||
func (c *Client) NEP11DUnpackedOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
|
func (c *Client) NEP11DUnpackedOwnerOf(tokenHash util.Uint160, tokenID []byte) ([]util.Uint160, error) {
|
||||||
result, err := c.InvokeAndPackIteratorResults(tokenHash, "ownerOf", []smartcontract.Parameter{
|
result, err := c.reader.CallAndExpandIterator(tokenHash, "ownerOf", config.DefaultMaxIteratorResultItems, tokenID)
|
||||||
{
|
|
||||||
Type: smartcontract.ByteArrayType,
|
|
||||||
Value: tokenID,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// iterator session is used to retrieve values from iterator. Instead, unpacking
|
||||||
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
// VM script is created and invoked via `invokescript` JSON-RPC call.
|
||||||
func (c *Client) NEP11UnpackedTokens(tokenHash util.Uint160) ([][]byte, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1280,7 +1280,7 @@ func TestClient_InvokeAndPackIteratorResults(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("default max items constraint", func(t *testing.T) {
|
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.NoError(t, err)
|
||||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||||
require.Equal(t, 1, len(res.Stack))
|
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) {
|
t.Run("custom max items constraint", func(t *testing.T) {
|
||||||
max := 123
|
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.NoError(t, err)
|
||||||
require.Equal(t, vmstate.Halt.String(), res.State)
|
require.Equal(t, vmstate.Halt.String(), res.State)
|
||||||
require.Equal(t, 1, len(res.Stack))
|
require.Equal(t, 1, len(res.Stack))
|
||||||
|
|
Loading…
Reference in a new issue