mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-04 19:19:44 +00:00
Merge pull request #1282 from nspcc-dev/rpc/invoke_with_hashes
rpc: use hashes for verifying in `invoke*` calls
This commit is contained in:
commit
ebcec6e5dc
11 changed files with 183 additions and 69 deletions
|
@ -68,6 +68,9 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
|||
func Main(op string, args []interface{}) {
|
||||
runtime.Notify("Hello world!")
|
||||
}`
|
||||
|
||||
// hashesForVerifyingSeparator delimits `invoke*` parameters from hashes for verifying
|
||||
hashesForVerifyingSeparator = "--"
|
||||
)
|
||||
|
||||
// NewCommands returns 'contract' command.
|
||||
|
@ -169,8 +172,9 @@ func NewCommands() []cli.Command {
|
|||
{
|
||||
Name: "testinvoke",
|
||||
Usage: "invoke deployed contract on the blockchain (test mode)",
|
||||
UsageText: "neo-go contract testinvoke -e endpoint scripthash [arguments...]",
|
||||
Description: `Executes given (as a script hash) deployed script with the given arguments.
|
||||
UsageText: "neo-go contract testinvoke -e endpoint scripthash [arguments...] [-- hashesForVerifying...]",
|
||||
Description: `Executes given (as a script hash) deployed script with the given arguments
|
||||
and hashes to verify using runtime.CheckWitness syscall.
|
||||
It's very similar to the tesinvokefunction command, but differs in the way
|
||||
arguments are being passed. This invoker does not accept method parameter
|
||||
and it passes all given parameters as plain values to the contract, not
|
||||
|
@ -189,13 +193,14 @@ func NewCommands() []cli.Command {
|
|||
{
|
||||
Name: "testinvokefunction",
|
||||
Usage: "invoke deployed contract on the blockchain (test mode)",
|
||||
UsageText: "neo-go contract testinvokefunction -e endpoint scripthash [method] [arguments...]",
|
||||
Description: `Executes given (as a script hash) deployed script with the given method and
|
||||
arguments. If no method is given "" is passed to the script, if no arguments
|
||||
are given, an empty array is passed. All of the given arguments are
|
||||
encapsulated into array before invoking the script. The script thus should
|
||||
follow the regular convention of smart contract arguments (method string and
|
||||
an array of other arguments).
|
||||
UsageText: "neo-go contract testinvokefunction -e endpoint scripthash [method] [arguments...] [-- hashesForVerifying...]",
|
||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||
arguments and hashes to verify using System.Runtime.CheckWitness syscall.
|
||||
If no method is given "" is passed to the script, if no arguments
|
||||
are given, an empty array is passed, if no hashes are given, no array is
|
||||
passed. All of the given arguments are encapsulated into array before
|
||||
invoking the script. The script thus should follow the regular convention
|
||||
of smart contract arguments (method string and an array of other arguments).
|
||||
|
||||
Arguments always do have regular Neo smart contract parameter types, either
|
||||
specified explicitly or being inferred from the value. To specify the type
|
||||
|
@ -251,6 +256,15 @@ func NewCommands() []cli.Command {
|
|||
* 'string\:string' is a string with a value of 'string:string'
|
||||
* '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c' is a
|
||||
key with a value of '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c'
|
||||
|
||||
HashesForVerifying represent a set of Uint160 hashes which are used to verify
|
||||
hashes in System.Runtime.CheckWitness syscall. To specify hash use its
|
||||
hex-encoded 160 bit (20 byte) LE representation with optional '0x' prefix.
|
||||
If no hashes were specified, no array is passed.
|
||||
|
||||
Examples:
|
||||
* '0000000009070e030d0f0e020d0c06050e030c02'
|
||||
* '0x0000000009070e030d0f0e020d0c06050e030c02'
|
||||
`,
|
||||
Action: testInvokeFunction,
|
||||
Flags: []cli.Flag{
|
||||
|
@ -258,9 +272,10 @@ func NewCommands() []cli.Command {
|
|||
},
|
||||
},
|
||||
{
|
||||
Name: "testinvokescript",
|
||||
Usage: "Invoke compiled AVM code on the blockchain (test mode, not creating a transaction for it)",
|
||||
Action: testInvokeScript,
|
||||
Name: "testinvokescript",
|
||||
Usage: "Invoke compiled AVM code on the blockchain (test mode, not creating a transaction for it)",
|
||||
UsageText: "neo-go contract testinvokescript -e endpoint -i testcontract.avm [-- hashesForVerifying...]",
|
||||
Action: testInvokeScript,
|
||||
Flags: []cli.Flag{
|
||||
endpointFlag,
|
||||
cli.StringFlag{
|
||||
|
@ -407,13 +422,15 @@ func invokeFunction(ctx *cli.Context) error {
|
|||
|
||||
func invokeInternal(ctx *cli.Context, withMethod bool, signAndPush bool) error {
|
||||
var (
|
||||
err error
|
||||
gas util.Fixed8
|
||||
operation string
|
||||
params = make([]smartcontract.Parameter, 0)
|
||||
paramsStart = 1
|
||||
resp *result.Invoke
|
||||
acc *wallet.Account
|
||||
err error
|
||||
gas util.Fixed8
|
||||
operation string
|
||||
params = make([]smartcontract.Parameter, 0)
|
||||
paramsStart = 1
|
||||
hashesForVerifying []util.Uint160
|
||||
hashesForVerifyingStart = 0
|
||||
resp *result.Invoke
|
||||
acc *wallet.Account
|
||||
)
|
||||
|
||||
endpoint := ctx.String("endpoint")
|
||||
|
@ -435,6 +452,13 @@ func invokeInternal(ctx *cli.Context, withMethod bool, signAndPush bool) error {
|
|||
}
|
||||
if len(args) > paramsStart {
|
||||
for k, s := range args[paramsStart:] {
|
||||
if s == hashesForVerifyingSeparator {
|
||||
if signAndPush {
|
||||
return cli.NewExitError("adding hashes for verifying available for test invokes only", 1)
|
||||
}
|
||||
hashesForVerifyingStart = paramsStart + k + 1
|
||||
break
|
||||
}
|
||||
param, err := smartcontract.NewParameterFromString(s)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to parse argument #%d: %v", k+paramsStart+1, err), 1)
|
||||
|
@ -443,6 +467,16 @@ func invokeInternal(ctx *cli.Context, withMethod bool, signAndPush bool) error {
|
|||
}
|
||||
}
|
||||
|
||||
if len(args) >= hashesForVerifyingStart && hashesForVerifyingStart > 0 {
|
||||
for i, c := range args[hashesForVerifyingStart:] {
|
||||
h, err := parseUint160(c)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to parse hash for verifying #%d: %v", i+1, err), 1)
|
||||
}
|
||||
hashesForVerifying = append(hashesForVerifying, h)
|
||||
}
|
||||
}
|
||||
|
||||
if signAndPush {
|
||||
gas = flags.Fixed8FromContext(ctx, "gas")
|
||||
acc, err = getAccFromContext(ctx)
|
||||
|
@ -456,9 +490,9 @@ func invokeInternal(ctx *cli.Context, withMethod bool, signAndPush bool) error {
|
|||
}
|
||||
|
||||
if withMethod {
|
||||
resp, err = c.InvokeFunction(script, operation, params)
|
||||
resp, err = c.InvokeFunction(script, operation, params, hashesForVerifying)
|
||||
} else {
|
||||
resp, err = c.Invoke(script, params)
|
||||
resp, err = c.Invoke(script, params, hashesForVerifying)
|
||||
}
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
@ -503,13 +537,25 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
args := ctx.Args()
|
||||
var hashesForVerifying []util.Uint160
|
||||
if args.Present() {
|
||||
for i, c := range args[:] {
|
||||
h, err := parseUint160(c)
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("failed to parse hash for verifying #%d: %v", i+1, err), 1)
|
||||
}
|
||||
hashesForVerifying = append(hashesForVerifying, h)
|
||||
}
|
||||
}
|
||||
|
||||
c, err := client.New(context.TODO(), endpoint, client.Options{})
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
||||
scriptHex := hex.EncodeToString(b)
|
||||
resp, err := c.InvokeScript(scriptHex)
|
||||
resp, err := c.InvokeScript(scriptHex, hashesForVerifying)
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
}
|
||||
|
@ -524,6 +570,13 @@ func testInvokeScript(ctx *cli.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func parseUint160(s string) (util.Uint160, error) {
|
||||
if len(s) == 2*util.Uint160Size+2 && s[0] == '0' && s[1] == 'x' {
|
||||
s = s[2:]
|
||||
}
|
||||
return util.Uint160DecodeStringLE(s)
|
||||
}
|
||||
|
||||
// ProjectConfig contains project metadata.
|
||||
type ProjectConfig struct {
|
||||
Version uint
|
||||
|
|
|
@ -2450,8 +2450,8 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([
|
|||
}
|
||||
|
||||
// GetTestVM returns a VM and a Store setup for a test run of some sort of code.
|
||||
func (bc *Blockchain) GetTestVM() *vm.VM {
|
||||
systemInterop := bc.newInteropContext(trigger.Application, bc.dao, nil, nil)
|
||||
func (bc *Blockchain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
||||
systemInterop := bc.newInteropContext(trigger.Application, bc.dao, nil, tx)
|
||||
vm := systemInterop.SpawnVM()
|
||||
vm.SetPriceGetter(getPrice)
|
||||
return vm
|
||||
|
|
|
@ -45,7 +45,7 @@ type Blockchainer interface {
|
|||
GetStateRoot(height uint32) (*state.MPTRootState, error)
|
||||
GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem
|
||||
GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error)
|
||||
GetTestVM() *vm.VM
|
||||
GetTestVM(tx *transaction.Transaction) *vm.VM
|
||||
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
|
||||
GetUnspentCoinState(util.Uint256) *state.UnspentCoin
|
||||
References(t *transaction.Transaction) ([]transaction.InOut, error)
|
||||
|
|
|
@ -602,7 +602,7 @@ func (ic *interopContext) contractMigrate(v *vm.VM) error {
|
|||
ic.dao.MigrateNEP5Balances(hash, contract.ScriptHash())
|
||||
|
||||
// save NEP5 metadata if any
|
||||
v := ic.bc.GetTestVM()
|
||||
v := ic.bc.GetTestVM(nil)
|
||||
w := io.NewBufBinWriter()
|
||||
emit.AppCallWithOperationAndArgs(w.BinWriter, hash, "decimals")
|
||||
v.SetGasLimit(ic.bc.GetConfig().FreeGasLimit)
|
||||
|
|
|
@ -123,7 +123,7 @@ func (chain testChain) GetStateRoot(height uint32) (*state.MPTRootState, error)
|
|||
func (chain testChain) GetStorageItem(scripthash util.Uint160, key []byte) *state.StorageItem {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) GetTestVM() *vm.VM {
|
||||
func (chain testChain) GetTestVM(tx *transaction.Transaction) *vm.VM {
|
||||
panic("TODO")
|
||||
}
|
||||
func (chain testChain) GetStorageItems(hash util.Uint160) (map[string]*state.StorageItem, error) {
|
||||
|
|
|
@ -18,7 +18,7 @@ import (
|
|||
|
||||
// NEP5Decimals invokes `decimals` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "decimals", []smartcontract.Parameter{})
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "decimals", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if result.State != "HALT" || len(result.Stack) == 0 {
|
||||
|
@ -30,7 +30,7 @@ func (c *Client) NEP5Decimals(tokenHash util.Uint160) (int64, error) {
|
|||
|
||||
// NEP5Name invokes `name` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) {
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "name", []smartcontract.Parameter{})
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "name", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if result.State != "HALT" || len(result.Stack) == 0 {
|
||||
|
@ -42,7 +42,7 @@ func (c *Client) NEP5Name(tokenHash util.Uint160) (string, error) {
|
|||
|
||||
// NEP5Symbol invokes `symbol` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) {
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "symbol", []smartcontract.Parameter{})
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "symbol", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if result.State != "HALT" || len(result.Stack) == 0 {
|
||||
|
@ -54,7 +54,7 @@ func (c *Client) NEP5Symbol(tokenHash util.Uint160) (string, error) {
|
|||
|
||||
// NEP5TotalSupply invokes `totalSupply` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "totalSupply", []smartcontract.Parameter{})
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "totalSupply", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if result.State != "HALT" || len(result.Stack) == 0 {
|
||||
|
@ -66,7 +66,7 @@ func (c *Client) NEP5TotalSupply(tokenHash util.Uint160) (int64, error) {
|
|||
|
||||
// NEP5BalanceOf invokes `balanceOf` NEP5 method on a specified contract.
|
||||
func (c *Client) NEP5BalanceOf(tokenHash util.Uint160) (int64, error) {
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "balanceOf", []smartcontract.Parameter{})
|
||||
result, err := c.InvokeFunction(tokenHash.StringLE(), "balanceOf", []smartcontract.Parameter{}, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
} else if result.State != "HALT" || len(result.Stack) == 0 {
|
||||
|
|
|
@ -394,39 +394,34 @@ func (c *Client) GetVersion() (*result.Version, error) {
|
|||
|
||||
// InvokeScript returns the result of the given script after running it true the VM.
|
||||
// NOTE: This is a test invoke and will not affect the blockchain.
|
||||
func (c *Client) InvokeScript(script string) (*result.Invoke, error) {
|
||||
var (
|
||||
params = request.NewRawParams(script)
|
||||
resp = &result.Invoke{}
|
||||
)
|
||||
if err := c.performRequest("invokescript", params, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
func (c *Client) InvokeScript(script string, hashesForVerifying []util.Uint160) (*result.Invoke, error) {
|
||||
params := request.NewRawParams(script)
|
||||
return c.invokeSomething("invokescript", params, hashesForVerifying)
|
||||
}
|
||||
|
||||
// InvokeFunction returns the results after calling the smart contract scripthash
|
||||
// with the given operation and parameters.
|
||||
// NOTE: this is test invoke and will not affect the blockchain.
|
||||
func (c *Client) InvokeFunction(script, operation string, params []smartcontract.Parameter) (*result.Invoke, error) {
|
||||
var (
|
||||
p = request.NewRawParams(script, operation, params)
|
||||
resp = &result.Invoke{}
|
||||
)
|
||||
if err := c.performRequest("invokefunction", p, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
func (c *Client) InvokeFunction(script, operation string, params []smartcontract.Parameter, hashesForVerifying []util.Uint160) (*result.Invoke, error) {
|
||||
p := request.NewRawParams(script, operation, params)
|
||||
return c.invokeSomething("invokefunction", p, hashesForVerifying)
|
||||
}
|
||||
|
||||
// Invoke returns the results after calling the smart contract scripthash
|
||||
// with the given parameters.
|
||||
func (c *Client) Invoke(script string, params []smartcontract.Parameter) (*result.Invoke, error) {
|
||||
var (
|
||||
p = request.NewRawParams(script, params)
|
||||
resp = &result.Invoke{}
|
||||
)
|
||||
if err := c.performRequest("invoke", p, resp); err != nil {
|
||||
// NOTE: this is test invoke and will not affect the blockchain.
|
||||
func (c *Client) Invoke(script string, params []smartcontract.Parameter, hashesForVerifying []util.Uint160) (*result.Invoke, error) {
|
||||
p := request.NewRawParams(script, params)
|
||||
return c.invokeSomething("invoke", p, hashesForVerifying)
|
||||
}
|
||||
|
||||
// invokeSomething is an inner wrapper for Invoke* functions
|
||||
func (c *Client) invokeSomething(method string, p request.RawParams, hashesForVerifying []util.Uint160) (*result.Invoke, error) {
|
||||
var resp = new(result.Invoke)
|
||||
if hashesForVerifying != nil {
|
||||
p.Values = append(p.Values, hashesForVerifying)
|
||||
}
|
||||
if err := c.performRequest(method, p, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
|
|
@ -813,7 +813,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
Type: smartcontract.Hash160Type,
|
||||
Value: hash,
|
||||
},
|
||||
})
|
||||
}, nil)
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf","state":"HALT","gas_consumed":"0.311","stack":[{"type":"ByteArray","value":"262bec084432"}],"tx":"d101361426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf000000000000000000000000"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
|
@ -839,7 +839,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
|
|||
{
|
||||
name: "positive",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191")
|
||||
return c.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191", nil)
|
||||
},
|
||||
serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"00046e616d656724058e5e1b6008847cd662728549088a9ee82191","state":"HALT","gas_consumed":"0.161","stack":[{"type":"ByteArray","value":"4e45503520474153"}],"tx":"d1011b00046e616d656724058e5e1b6008847cd662728549088a9ee82191000000000000000000000000"}}`,
|
||||
result: func(c *Client) interface{} {
|
||||
|
@ -1186,13 +1186,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
{
|
||||
name: "invokefunction_invalid_params_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.InvokeFunction("", "", []smartcontract.Parameter{})
|
||||
return c.InvokeFunction("", "", []smartcontract.Parameter{}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invokescript_invalid_params_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.InvokeScript("")
|
||||
return c.InvokeScript("", nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1392,13 +1392,13 @@ var rpcClientErrorCases = map[string][]rpcClientErrorCase{
|
|||
{
|
||||
name: "invokefunction_unmarshalling_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.InvokeFunction("", "", []smartcontract.Parameter{})
|
||||
return c.InvokeFunction("", "", []smartcontract.Parameter{}, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invokescript_unmarshalling_error",
|
||||
invoke: func(c *Client) (interface{}, error) {
|
||||
return c.InvokeScript("")
|
||||
return c.InvokeScript("", nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -164,6 +164,27 @@ func (p *Param) GetUint160FromAddressOrHex() (util.Uint160, error) {
|
|||
return p.GetUint160FromAddress()
|
||||
}
|
||||
|
||||
// GetArrayUint160FromHex returns array of Uint160 values of the parameter that
|
||||
// was supply as array of raw hex.
|
||||
func (p *Param) GetArrayUint160FromHex() ([]util.Uint160, error) {
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
arr, err := p.GetArray()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result = make([]util.Uint160, len(arr))
|
||||
for i, parameter := range arr {
|
||||
hash, err := parameter.GetUint160FromHex()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[i] = hash
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetFuncParam returns current parameter as a function call parameter.
|
||||
func (p *Param) GetFuncParam() (FuncParam, error) {
|
||||
if p == nil {
|
||||
|
|
|
@ -185,6 +185,24 @@ func TestParam_GetUint160FromAddressOrHex(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestParam_GetArrayUint160FromHex(t *testing.T) {
|
||||
in1 := util.Uint160{1, 2, 3}
|
||||
in2 := util.Uint160{4, 5, 6}
|
||||
p := Param{Type: ArrayT, Value: []Param{
|
||||
{
|
||||
Type: StringT,
|
||||
Value: in1.StringLE(),
|
||||
},
|
||||
{
|
||||
Type: StringT,
|
||||
Value: in2.StringLE(),
|
||||
},
|
||||
}}
|
||||
arr, err := p.GetArrayUint160FromHex()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []util.Uint160{in1, in2}, arr)
|
||||
}
|
||||
|
||||
func TestParamGetFuncParam(t *testing.T) {
|
||||
fp := FuncParam{
|
||||
Type: smartcontract.StringType,
|
||||
|
|
|
@ -1097,24 +1097,37 @@ func (s *Server) invoke(reqParams request.Params) (interface{}, *response.Error)
|
|||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
hashesForVerifying, err := reqParams.ValueWithType(2, request.ArrayT).GetArrayUint160FromHex()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
script, err := request.CreateInvocationScript(scriptHash, slice)
|
||||
if err != nil {
|
||||
return nil, response.NewInternalServerError("can't create invocation script", err)
|
||||
}
|
||||
return s.runScriptInVM(script), nil
|
||||
return s.runScriptInVM(script, hashesForVerifying), nil
|
||||
}
|
||||
|
||||
// invokescript implements the `invokescript` RPC call.
|
||||
// invokeFunction implements the `invokefunction` RPC call.
|
||||
func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) {
|
||||
scriptHash, err := reqParams.ValueWithType(0, request.StringT).GetUint160FromHex()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1:])
|
||||
var hashesForVerifying []util.Uint160
|
||||
hashesForVerifyingIndex := len(reqParams)
|
||||
if hashesForVerifyingIndex > 3 {
|
||||
hashesForVerifying, err = reqParams.ValueWithType(3, request.ArrayT).GetArrayUint160FromHex()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
hashesForVerifyingIndex--
|
||||
}
|
||||
script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1:hashesForVerifyingIndex])
|
||||
if err != nil {
|
||||
return nil, response.NewInternalServerError("can't create invocation script", err)
|
||||
}
|
||||
return s.runScriptInVM(script), nil
|
||||
return s.runScriptInVM(script, hashesForVerifying), nil
|
||||
}
|
||||
|
||||
// invokescript implements the `invokescript` RPC call.
|
||||
|
@ -1128,13 +1141,27 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
|
|||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
||||
return s.runScriptInVM(script), nil
|
||||
hashesForVerifying, err := reqParams.ValueWithType(1, request.ArrayT).GetArrayUint160FromHex()
|
||||
if err != nil {
|
||||
return nil, response.ErrInvalidParams
|
||||
}
|
||||
|
||||
return s.runScriptInVM(script, hashesForVerifying), nil
|
||||
}
|
||||
|
||||
// runScriptInVM runs given script in a new test VM and returns the invocation
|
||||
// result.
|
||||
func (s *Server) runScriptInVM(script []byte) *result.Invoke {
|
||||
vm := s.chain.GetTestVM()
|
||||
func (s *Server) runScriptInVM(script []byte, scriptHashesForVerifying []util.Uint160) *result.Invoke {
|
||||
var tx *transaction.Transaction
|
||||
if count := len(scriptHashesForVerifying); count != 0 {
|
||||
tx := new(transaction.Transaction)
|
||||
tx.Attributes = make([]transaction.Attribute, count)
|
||||
for i, a := range tx.Attributes {
|
||||
a.Data = scriptHashesForVerifying[i].BytesBE()
|
||||
a.Usage = transaction.Script
|
||||
}
|
||||
}
|
||||
vm := s.chain.GetTestVM(tx)
|
||||
vm.SetGasLimit(s.config.MaxGasInvoke)
|
||||
vm.LoadScript(script)
|
||||
_ = vm.Run()
|
||||
|
|
Loading…
Reference in a new issue