From 4715efd5316f69f82762dc6f6ffcf1054a038cdf Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 6 Aug 2020 19:25:43 +0300 Subject: [PATCH 1/3] core, rpc: invoke script with hashes for verifying Closes #1275 --- pkg/core/blockchain.go | 4 ++-- pkg/core/blockchainer.go | 2 +- pkg/core/interop_neo.go | 2 +- pkg/network/helper_test.go | 2 +- pkg/rpc/request/param.go | 21 +++++++++++++++++++ pkg/rpc/request/param_test.go | 18 ++++++++++++++++ pkg/rpc/server/server.go | 39 +++++++++++++++++++++++++++++------ 7 files changed, 77 insertions(+), 11 deletions(-) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 82b26fbd7..bf7f48cac 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -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 diff --git a/pkg/core/blockchainer.go b/pkg/core/blockchainer.go index 03f0bd4e3..8f8bc0729 100644 --- a/pkg/core/blockchainer.go +++ b/pkg/core/blockchainer.go @@ -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) diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index 5f4d56b7e..12d653d0c 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -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) diff --git a/pkg/network/helper_test.go b/pkg/network/helper_test.go index 93aa36ccf..d35b222e5 100644 --- a/pkg/network/helper_test.go +++ b/pkg/network/helper_test.go @@ -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) { diff --git a/pkg/rpc/request/param.go b/pkg/rpc/request/param.go index a6a254dd0..cd78a1078 100644 --- a/pkg/rpc/request/param.go +++ b/pkg/rpc/request/param.go @@ -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 { diff --git a/pkg/rpc/request/param_test.go b/pkg/rpc/request/param_test.go index 0f51bc1db..feaee36a7 100644 --- a/pkg/rpc/request/param_test.go +++ b/pkg/rpc/request/param_test.go @@ -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, diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 07318983c..1a633045f 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1075,11 +1075,15 @@ 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. @@ -1088,11 +1092,20 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons 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. @@ -1106,13 +1119,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() From d20e54b725836531619867f3586bdfa8f12805e6 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 6 Aug 2020 19:27:15 +0300 Subject: [PATCH 2/3] rpc: fix method comment --- pkg/rpc/server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 1a633045f..d6ee67ad8 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -1086,7 +1086,7 @@ func (s *Server) invoke(reqParams request.Params) (interface{}, *response.Error) 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 { From 4b351f31233e7393971093fa927e0eaf1e3bfa23 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 6 Aug 2020 21:59:03 +0300 Subject: [PATCH 3/3] cli: use hashes for verifying in `invoke*` calls --- cli/smartcontract/smart_contract.go | 97 ++++++++++++++++++++++------- pkg/rpc/client/nep5.go | 10 +-- pkg/rpc/client/rpc.go | 43 ++++++------- pkg/rpc/client/rpc_test.go | 12 ++-- 4 files changed, 105 insertions(+), 57 deletions(-) diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index ccf9bb1bf..164ee166a 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -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 diff --git a/pkg/rpc/client/nep5.go b/pkg/rpc/client/nep5.go index fd38e399c..17cfdeedc 100644 --- a/pkg/rpc/client/nep5.go +++ b/pkg/rpc/client/nep5.go @@ -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 { diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 09257d09a..5a9411075 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -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 diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index d7e1437f1..0aefc8197 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -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) }, }, {