diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 231b7bc59..fbd6098be 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -500,11 +500,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { fmt.Fprintln(ctx.App.Writer, errText+". Sending transaction...") } if out := ctx.String("out"); out != "" { - script, err := hex.DecodeString(resp.Script) - if err != nil { - return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %w", err), 1) - } - tx, err := c.CreateTxFromScript(script, acc, resp.GasConsumed, int64(gas), cosigners...) + tx, err := c.CreateTxFromScript(resp.Script, acc, resp.GasConsumed, int64(gas), cosigners...) if err != nil { return cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1) } @@ -518,11 +514,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error { if len(resp.Script) == 0 { return cli.NewExitError(errors.New("no script returned from the RPC node"), 1) } - script, err := hex.DecodeString(resp.Script) - if err != nil { - return cli.NewExitError(fmt.Errorf("bad script returned from the RPC node: %w", err), 1) - } - txHash, err := c.SignAndPushInvocationTx(script, acc, resp.GasConsumed, gas, cosigners) + txHash, err := c.SignAndPushInvocationTx(resp.Script, acc, resp.GasConsumed, gas, cosigners) if err != nil { return cli.NewExitError(fmt.Errorf("failed to push invocation tx: %w", err), 1) } diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 8331a4f9b..e9122fcde 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -381,7 +381,7 @@ 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 []byte, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(hex.EncodeToString(script)) + var p = request.NewRawParams(script) return c.invokeSomething("invokescript", p, signers) } diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index 1d5669ecd..6c58e6075 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -347,7 +347,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetFeePerByte() }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c0d676574466565506572427974650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMDWdldEZlZVBlckJ5dGUMFJphpG7sl7iTBtfOgfFbRiCR0AkyQWJ9W1I=","stack":[{"type":"Integer","value":"1000"}],"tx":null}}`, result: func(c *Client) interface{} { return int64(1000) }, @@ -359,7 +359,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetMaxTransactionsPerBlock() }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c1a6765744d61785472616e73616374696f6e73506572426c6f636b0c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"512"}],"tx":null}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMGmdldE1heFRyYW5zYWN0aW9uc1BlckJsb2NrDBSaYaRu7Je4kwbXzoHxW0YgkdAJMkFifVtS","stack":[{"type":"Integer","value":"512"}],"tx":null}}`, result: func(c *Client) interface{} { return int64(512) }, @@ -371,7 +371,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetMaxBlockSize() }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c0f6765744d6178426c6f636b53697a650c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMD2dldE1heEJsb2NrU2l6ZQwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Integer","value":"262144"}],"tx":null}}`, result: func(c *Client) interface{} { return int64(262144) }, @@ -383,7 +383,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetBlockedAccounts() }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"10c00c12676574426c6f636b65644163636f756e74730c149a61a46eec97b89306d7ce81f15b462091d0093241627d5b52","stack":[{"type":"Array","value":[]}],"tx":null}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"state":"HALT","gasconsumed":"2007390","script":"EMAMEmdldEJsb2NrZWRBY2NvdW50cwwUmmGkbuyXuJMG186B8VtGIJHQCTJBYn1bUg==","stack":[{"type":"Array","value":[]}],"tx":null}}`, result: func(c *Client) interface{} { return native.BlockedAccounts{} }, @@ -663,7 +663,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ Account: util.Uint160{1, 2, 3}, }}) }, - serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"01e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b5238","state":"HALT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv","state":"HALT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"}}`, result: func(c *Client) interface{} { return &result.Invoke{} }, @@ -674,9 +674,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } + script, err := base64.StdEncoding.DecodeString("FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv") + if err != nil { + panic(err) + } assert.Equal(t, "HALT", res.State) assert.Equal(t, int64(31100000), res.GasConsumed) - assert.Equal(t, "01e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b5238", res.Script) + assert.Equal(t, script, res.Script) assert.Equal(t, []stackitem.Item{stackitem.NewByteArray(bytes)}, res.Stack) assert.NotNil(t, res.Transaction) }, @@ -701,7 +705,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ Account: util.Uint160{1, 2, 3}, }}) }, - serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf","state":"FAULT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78","exception":"gas limit exceeded"}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv","state":"FAULT","gasconsumed":"31100000","stack":[{"type":"ByteString","value":"JivsCEQy"}],"tx":"000800000080969800000000000204130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005701e8030c14aa8acf859d4fe402b34e673f2156821796a488eb0c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb013c00c087472616e736665720c14e79eb66d3c134a4a776ee807d2e5b846dda4fdb041627d5b523801420c40d83408774d4bd8b19ae870561d06f2744eb7678f58d1b90cf2f50e98ae83f60b0824e2feeadef6de6418a4cfc43bbc1f916c33ec594cbe662a9d924786e17a14290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78","exception":"gas limit exceeded"}}`, result: func(c *Client) interface{} { return &result.Invoke{} }, @@ -712,9 +716,13 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } + script, err := base64.StdEncoding.DecodeString("FCaufGyYYexBhGjB8P3Ep/KWPriRUcEJYmFsYW5jZU9mZ74557Vi9gy/4q68o3Wi5e4oc3yv") + if err != nil { + panic(err) + } assert.Equal(t, "FAULT", res.State) assert.Equal(t, int64(31100000), res.GasConsumed) - assert.Equal(t, "1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf", res.Script) + assert.Equal(t, script, res.Script) assert.Equal(t, []stackitem.Item{stackitem.NewByteArray(bytes)}, res.Stack) assert.NotNil(t, res.Transaction) }, @@ -724,7 +732,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "positive", invoke: func(c *Client) (interface{}, error) { - script, err := hex.DecodeString("00046e616d656724058e5e1b6008847cd662728549088a9ee82191") + script, err := base64.StdEncoding.DecodeString("AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR") if err != nil { panic(err) } @@ -732,16 +740,20 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ Account: util.Uint160{1, 2, 3}, }}) }, - serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"00046e616d656724058e5e1b6008847cd662728549088a9ee82191","state":"HALT","gasconsumed":"16100000","stack":[{"type":"ByteString","value":"TkVQNSBHQVM="}],"tx":null}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"script":"AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR","state":"HALT","gasconsumed":"16100000","stack":[{"type":"ByteString","value":"TkVQNSBHQVM="}],"tx":null}}`, result: func(c *Client) interface{} { bytes, err := hex.DecodeString("4e45503520474153") if err != nil { panic(err) } + script, err := base64.StdEncoding.DecodeString("AARuYW1lZyQFjl4bYAiEfNZicoVJCIqe6CGR") + if err != nil { + panic(err) + } return &result.Invoke{ State: "HALT", GasConsumed: 16100000, - Script: "00046e616d656724058e5e1b6008847cd662728549088a9ee82191", + Script: script, Stack: []stackitem.Item{stackitem.NewByteArray(bytes)}, } }, diff --git a/pkg/rpc/response/result/invoke.go b/pkg/rpc/response/result/invoke.go index 52c9d937d..3816ca971 100644 --- a/pkg/rpc/response/result/invoke.go +++ b/pkg/rpc/response/result/invoke.go @@ -18,7 +18,7 @@ import ( type Invoke struct { State string GasConsumed int64 - Script string + Script []byte Stack []stackitem.Item FaultException string // Transaction represents transaction bytes. Use GetTransaction method to decode it. @@ -28,7 +28,7 @@ type Invoke struct { type invokeAux struct { State string `json:"state"` GasConsumed int64 `json:"gasconsumed,string"` - Script string `json:"script"` + Script []byte `json:"script"` Stack json.RawMessage `json:"stack"` FaultException string `json:"exception,omitempty"` Transaction string `json:"tx,omitempty"` diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 5d9f18bac..85630ca8a 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -977,7 +977,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. return nil, response.ErrInvalidParams } - script, err := reqParams[0].GetBytesHex() + script, err := reqParams[0].GetBytesBase64() if err != nil { return nil, response.ErrInvalidParams } @@ -1011,7 +1011,7 @@ func (s *Server) runScriptInVM(script []byte, tx *transaction.Transaction) *resu result := &result.Invoke{ State: vm.State().String(), GasConsumed: vm.GasConsumed(), - Script: hex.EncodeToString(script), + Script: script, Stack: vm.Estack().ToArray(), FaultException: faultException, } diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index e28863d85..ee294da32 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -60,6 +60,7 @@ const deploymentTxHash = "59f7b22b90e26f883a56b916c1580e3ee4f13caded686353cd7757 const verifyContractHash = "c1213693b22cb0454a436d6e0bd76b8c0a3bfdf7" const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740" +const testVerifyContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGgRVUH4J+yMIaonBwAAABFADBQNDwMCCQACAQMHAwQFAgEADgYMCdswcWkRVUH4J+yMIaonBwAAABJAE0A=" var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { @@ -537,7 +538,7 @@ var rpcTestCases = map[string][]rpcTestCase{ check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke) require.True(t, ok) - assert.NotEqual(t, "", res.Script) + assert.NotNil(t, res.Script) assert.NotEqual(t, "", res.State) assert.NotEqual(t, 0, res.GasConsumed) }, @@ -566,7 +567,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "invokescript": { { name: "positive", - params: `["51c56b0d48656c6c6f2c20776f726c6421680f4e656f2e52756e74696d652e4c6f67616c7566"]`, + params: `["UcVrDUhlbGxvLCB3b3JsZCFoD05lby5SdW50aW1lLkxvZ2FsdWY="]`, result: func(e *executor) interface{} { return &result.Invoke{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke) @@ -578,8 +579,8 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { name: "positive, good witness", - // script is hex-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix - params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, + // script is base64-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix + params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, testVerifyContractAVM), result: func(e *executor) interface{} { return &result.Invoke{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke) @@ -591,7 +592,7 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { name: "positive, bad witness of second hash", - params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, + params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, testVerifyContractAVM), result: func(e *executor) interface{} { return &result.Invoke{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke) @@ -603,7 +604,7 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { name: "positive, no good hashes", - params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340"]`, + params: fmt.Sprintf(`["%s"]`, testVerifyContractAVM), result: func(e *executor) interface{} { return &result.Invoke{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke) @@ -615,7 +616,7 @@ var rpcTestCases = map[string][]rpcTestCase{ }, { name: "positive, bad hashes witness", - params: `["5707000c14010c030e05060c0d020e0f0d030e070900000000db307068115541f827ec8c21aa270700000011400c140d0f03020900020103070304050201000e060c09db307169115541f827ec8c21aa270700000012401340",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, + params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, testVerifyContractAVM), result: func(e *executor) interface{} { return &result.Invoke{} }, check: func(t *testing.T, e *executor, inv interface{}) { res, ok := inv.(*result.Invoke)