From adab83496c86d5efc9c5067fb8b936e6cddcf7a8 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 7 Jul 2022 17:41:01 +0300 Subject: [PATCH 1/4] rpc: move Request, Params and related code server-side It's absolutely irrelevant for the client and request/response packages should only contain code that is useful on both sides of the conversation. It's OK for client tests to reuse this code, but the package is used by external developers and they shouldn't be bothered with it. Nothing changed functionally here except WSClient simplification. Fixes #2236. --- pkg/rpc/client/rpc_test.go | 18 +- pkg/rpc/client/wsclient.go | 23 +-- pkg/rpc/client/wsclient_test.go | 25 +-- pkg/rpc/request/types.go | 161 +++++++++--------- pkg/rpc/{request => server/params}/param.go | 89 +--------- .../{request => server/params}/param_test.go | 17 +- pkg/rpc/{request => server/params}/params.go | 2 +- .../{request => server/params}/txBuilder.go | 2 +- .../params}/tx_builder_test.go | 2 +- pkg/rpc/server/params/types.go | 111 ++++++++++++ .../{request => server/params}/types_test.go | 2 +- pkg/rpc/server/server.go | 157 ++++++++--------- pkg/rpc/server/server_test.go | 4 +- 13 files changed, 319 insertions(+), 294 deletions(-) rename pkg/rpc/{request => server/params}/param.go (74%) rename pkg/rpc/{request => server/params}/param_test.go (96%) rename pkg/rpc/{request => server/params}/params.go (95%) rename pkg/rpc/{request => server/params}/txBuilder.go (99%) rename pkg/rpc/{request => server/params}/tx_builder_test.go (99%) create mode 100644 pkg/rpc/server/params/types.go rename pkg/rpc/{request => server/params}/types_test.go (98%) diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index 6f2ee6483..043e7a83f 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -27,8 +27,8 @@ import ( "github.com/nspcc-dev/neo-go/pkg/encoding/address" "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/io" - "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" + "github.com/nspcc-dev/neo-go/pkg/rpc/server/params" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" @@ -1816,7 +1816,7 @@ func initTestServer(t *testing.T, resp string) *httptest.Server { if err != nil { break } - r := request.NewIn() + r := params.NewIn() err = json.Unmarshal(p, r) if err != nil { t.Fatalf("Cannot decode request body: %s", req.Body) @@ -1832,7 +1832,7 @@ func initTestServer(t *testing.T, resp string) *httptest.Server { ws.Close() return } - r := request.NewRequest() + r := params.NewRequest() err := r.DecodeData(req.Body) if err != nil { t.Fatalf("Cannot decode request body: %s", req.Body) @@ -1845,7 +1845,7 @@ func initTestServer(t *testing.T, resp string) *httptest.Server { return srv } -func requestHandler(t *testing.T, r *request.In, w http.ResponseWriter, resp string) { +func requestHandler(t *testing.T, r *params.In, w http.ResponseWriter, resp string) { w.Header().Set("Content-Type", "application/json; charset=utf-8") response := wrapInitResponse(r, resp) _, err := w.Write([]byte(response)) @@ -1854,7 +1854,7 @@ func requestHandler(t *testing.T, r *request.In, w http.ResponseWriter, resp str } } -func wrapInitResponse(r *request.In, resp string) string { +func wrapInitResponse(r *params.In, resp string) string { var response string switch r.Method { case "getversion": @@ -1862,7 +1862,7 @@ func wrapInitResponse(r *request.In, resp string) string { case "getnativecontracts": response = `{"jsonrpc":"2.0","id":1,"result":[{"id":-1,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"ContractManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","offset":0,"safe":false},{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","offset":7,"safe":false},{"name":"destroy","parameters":[],"returntype":"Void","offset":14,"safe":false},{"name":"getContract","parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","offset":21,"safe":true},{"name":"getMinimumDeploymentFee","parameters":[],"returntype":"Integer","offset":28,"safe":true},{"name":"setMinimumDeploymentFee","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":35,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","offset":42,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","offset":49,"safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"StdLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"atoi","parameters":[{"name":"value","type":"String"}],"returntype":"Integer","offset":0,"safe":true},{"name":"atoi","parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"base58CheckDecode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":14,"safe":true},{"name":"base58CheckEncode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":21,"safe":true},{"name":"base58Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":28,"safe":true},{"name":"base58Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":35,"safe":true},{"name":"base64Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"base64Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":49,"safe":true},{"name":"deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","offset":56,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"}],"returntype":"String","offset":63,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","offset":70,"safe":true},{"name":"jsonDeserialize","parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","offset":77,"safe":true},{"name":"jsonSerialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":84,"safe":true},{"name":"memoryCompare","parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","offset":91,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","offset":98,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","offset":105,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","offset":112,"safe":true},{"name":"serialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":119,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","offset":126,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","offset":133,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1592866325},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":0,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":7,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","offset":14,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-4,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":529571427},"manifest":{"name":"LedgerContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"currentHash","parameters":[],"returntype":"Hash256","offset":0,"safe":true},{"name":"currentIndex","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlock","parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","offset":14,"safe":true},{"name":"getTransaction","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":21,"safe":true},{"name":"getTransactionFromBlock","parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getTransactionHeight","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":35,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":588003825},"manifest":{"name":"NeoToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getAccountState","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","offset":14,"safe":true},{"name":"getCandidates","parameters":[],"returntype":"Array","offset":21,"safe":true},{"name":"getCommittee","parameters":[],"returntype":"Array","offset":28,"safe":true},{"name":"getGasPerBlock","parameters":[],"returntype":"Integer","offset":35,"safe":true},{"name":"getNextBlockValidators","parameters":[],"returntype":"Array","offset":42,"safe":true},{"name":"getRegisterPrice","parameters":[],"returntype":"Integer","offset":49,"safe":true},{"name":"registerCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":56,"safe":false},{"name":"setGasPerBlock","parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","offset":63,"safe":false},{"name":"setRegisterPrice","parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","offset":70,"safe":false},{"name":"symbol","parameters":[],"returntype":"String","offset":77,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":84,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":91,"safe":false},{"name":"unclaimedGas","parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","offset":98,"safe":true},{"name":"unregisterCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":105,"safe":false},{"name":"vote","parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","offset":112,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-6,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":3443651689},"manifest":{"name":"PolicyContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"blockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":0,"safe":false},{"name":"getExecFeeFactor","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getFeePerByte","parameters":[],"returntype":"Integer","offset":14,"safe":true},{"name":"getStoragePrice","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"isBlocked","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":28,"safe":true},{"name":"setExecFeeFactor","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":35,"safe":false},{"name":"setFeePerByte","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":42,"safe":false},{"name":"setStoragePrice","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":49,"safe":false},{"name":"unblockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":56,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-8,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"designateAsRole","parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","offset":0,"safe":false},{"name":"getDesignatedByRole","parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","offset":7,"safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]},{"id":-9,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"finish","parameters":[],"returntype":"Void","offset":0,"safe":false},{"name":"getPrice","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"request","parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","offset":14,"safe":false},{"name":"setPrice","parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","offset":21,"safe":false},{"name":"verify","parameters":[],"returntype":"Boolean","offset":28,"safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null},"updatehistory":[0]}]}` case "getcontractstate": - p := request.Params(r.RawParams) + p := params.Params(r.RawParams) name, _ := p.Value(0).GetString() switch name { case "NeoToken": @@ -1886,7 +1886,7 @@ func TestCalculateValidUntilBlock(t *testing.T) { getValidatorsCalled int ) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - r := request.NewRequest() + r := params.NewRequest() err := r.DecodeData(req.Body) if err != nil { t.Fatalf("Cannot decode request body: %s", req.Body) @@ -1929,7 +1929,7 @@ func TestCalculateValidUntilBlock(t *testing.T) { func TestGetNetwork(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - r := request.NewRequest() + r := params.NewRequest() err := r.DecodeData(req.Body) if err != nil { t.Fatalf("Cannot decode request body: %s", req.Body) @@ -1968,7 +1968,7 @@ func TestGetNetwork(t *testing.T) { func TestUninitedClient(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - r := request.NewRequest() + r := params.NewRequest() err := r.DecodeData(req.Body) require.NoErrorf(t, err, "Cannot decode request body: %s", req.Body) // request handler already have `getversion` response wrapper diff --git a/pkg/rpc/client/wsclient.go b/pkg/rpc/client/wsclient.go index 14cd25f8e..4a36585f8 100644 --- a/pkg/rpc/client/wsclient.go +++ b/pkg/rpc/client/wsclient.go @@ -63,9 +63,9 @@ type Notification struct { // requestResponse is a combined type for request and response since we can get // any of them here. type requestResponse struct { - request.In - Error *response.Error `json:"error,omitempty"` - Result json.RawMessage `json:"result,omitempty"` + response.Raw + Method string `json:"method"` + RawParams []json.RawMessage `json:"params,omitempty"` } const ( @@ -158,7 +158,7 @@ readloop: connCloseErr = fmt.Errorf("failed to read JSON response (timeout/connection loss/malformed response): %w", err) break readloop } - if rr.RawID == nil && rr.Method != "" { + if rr.ID == nil && rr.Method != "" { event, err := response.GetEventIDFromString(rr.Method) if err != nil { // Bad event received. @@ -196,7 +196,7 @@ readloop: break readloop } if event != response.MissedEventID { - err = json.Unmarshal(rr.RawParams[0].RawMessage, val) + err = json.Unmarshal(rr.RawParams[0], val) if err != nil { // Bad event received. connCloseErr = fmt.Errorf("failed to unmarshal event of type %s from JSON: %w", event, err) @@ -204,15 +204,10 @@ readloop: } } c.Notifications <- Notification{event, val} - } else if rr.RawID != nil && (rr.Error != nil || rr.Result != nil) { - resp := new(response.Raw) - resp.ID = rr.RawID - resp.JSONRPC = rr.JSONRPC - resp.Error = rr.Error - resp.Result = rr.Result - id, err := strconv.Atoi(string(resp.ID)) + } else if rr.ID != nil && (rr.Error != nil || rr.Result != nil) { + id, err := strconv.Atoi(string(rr.ID)) if err != nil { - connCloseErr = fmt.Errorf("failed to retrieve response ID from string %s: %w", string(resp.ID), err) + connCloseErr = fmt.Errorf("failed to retrieve response ID from string %s: %w", string(rr.ID), err) break readloop // Malformed response (invalid response ID). } ch := c.getResponseChannel(uint64(id)) @@ -220,7 +215,7 @@ readloop: connCloseErr = fmt.Errorf("unknown response channel for response %d", id) break readloop // Unknown response (unexpected response ID). } - ch <- resp + ch <- &rr.Raw } else { // Malformed response, neither valid request, nor valid response. connCloseErr = fmt.Errorf("malformed response") diff --git a/pkg/rpc/client/wsclient_test.go b/pkg/rpc/client/wsclient_test.go index 73ea93ff6..b4d93fec7 100644 --- a/pkg/rpc/client/wsclient_test.go +++ b/pkg/rpc/client/wsclient_test.go @@ -18,6 +18,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/network/payload" "github.com/nspcc-dev/neo-go/pkg/rpc/request" + "github.com/nspcc-dev/neo-go/pkg/rpc/server/params" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" "go.uber.org/atomic" @@ -189,7 +190,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { var cases = []struct { name string clientCode func(*testing.T, *WSClient) - serverCode func(*testing.T, *request.Params) + serverCode func(*testing.T, *params.Params) }{ {"blocks", func(t *testing.T, wsc *WSClient) { @@ -197,7 +198,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForNewBlocks(&primary) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.BlockFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -210,7 +211,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForNewTransactions(&sender, nil) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.TxFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -224,7 +225,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForNewTransactions(nil, &signer) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.TxFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -239,7 +240,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForNewTransactions(&sender, &signer) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.TxFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -253,7 +254,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForExecutionNotifications(&contract, nil) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.NotificationFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -267,7 +268,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForExecutionNotifications(nil, &name) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.NotificationFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -282,7 +283,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForExecutionNotifications(&contract, &name) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.NotificationFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -296,7 +297,7 @@ func TestWSFilteredSubscriptions(t *testing.T) { _, err := wsc.SubscribeForTransactionExecutions(&state) require.NoError(t, err) }, - func(t *testing.T, p *request.Params) { + func(t *testing.T, p *params.Params) { param := p.Value(1) filt := new(request.ExecutionFilter) require.NoError(t, json.Unmarshal(param.RawMessage, filt)) @@ -313,10 +314,10 @@ func TestWSFilteredSubscriptions(t *testing.T) { require.NoError(t, err) err = ws.SetReadDeadline(time.Now().Add(2 * time.Second)) require.NoError(t, err) - req := request.In{} + req := params.In{} err = ws.ReadJSON(&req) require.NoError(t, err) - params := request.Params(req.RawParams) + params := params.Params(req.RawParams) c.serverCode(t, ¶ms) err = ws.SetWriteDeadline(time.Now().Add(2 * time.Second)) require.NoError(t, err) @@ -370,7 +371,7 @@ func TestWSConcurrentAccess(t *testing.T) { if err != nil { break } - r := request.NewIn() + r := params.NewIn() err = json.Unmarshal(p, r) if err != nil { t.Fatalf("Cannot decode request body: %s", req.Body) diff --git a/pkg/rpc/request/types.go b/pkg/rpc/request/types.go index 1862649d1..7ef644862 100644 --- a/pkg/rpc/request/types.go +++ b/pkg/rpc/request/types.go @@ -1,19 +1,19 @@ package request import ( - "bytes" "encoding/json" - "errors" "fmt" - "io" + "strings" + + "github.com/nspcc-dev/neo-go/pkg/core/transaction" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/util" ) const ( // JSONRPCVersion is the only JSON-RPC protocol version supported. JSONRPCVersion = "2.0" - - // maxBatchSize is the maximum number of requests per batch. - maxBatchSize = 100 ) // RawParams is just a slice of abstract values, used to represent parameters @@ -40,97 +40,88 @@ type Raw struct { ID uint64 `json:"id"` } -// Request contains standard JSON-RPC 2.0 request and batch of -// requests: http://www.jsonrpc.org/specification. -// It's used in server to represent incoming queries. -type Request struct { - In *In - Batch Batch -} +type ( + // BlockFilter is a wrapper structure for the block event filter. The only + // allowed filter is primary index. + BlockFilter struct { + Primary int `json:"primary"` + } + // TxFilter is a wrapper structure for the transaction event filter. It + // allows to filter transactions by senders and signers. + TxFilter struct { + Sender *util.Uint160 `json:"sender,omitempty"` + Signer *util.Uint160 `json:"signer,omitempty"` + } + // NotificationFilter is a wrapper structure representing a filter used for + // notifications generated during transaction execution. Notifications can + // be filtered by contract hash and by name. + NotificationFilter struct { + Contract *util.Uint160 `json:"contract,omitempty"` + Name *string `json:"name,omitempty"` + } + // ExecutionFilter is a wrapper structure used for transaction execution + // events. It allows to choose failing or successful transactions based + // on their VM state. + ExecutionFilter struct { + State string `json:"state"` + } + // SignerWithWitness represents transaction's signer with the corresponding witness. + SignerWithWitness struct { + transaction.Signer + transaction.Witness + } +) -// In represents a standard JSON-RPC 2.0 -// request: http://www.jsonrpc.org/specification#request_object. -type In struct { - JSONRPC string `json:"jsonrpc"` - Method string `json:"method"` - RawParams []Param `json:"params,omitempty"` - RawID json.RawMessage `json:"id,omitempty"` +// signerWithWitnessAux is an auxiliary struct for JSON marshalling. We need it because of +// DisallowUnknownFields JSON marshaller setting. +type signerWithWitnessAux struct { + Account string `json:"account"` + Scopes transaction.WitnessScope `json:"scopes"` + AllowedContracts []util.Uint160 `json:"allowedcontracts,omitempty"` + AllowedGroups []*keys.PublicKey `json:"allowedgroups,omitempty"` + Rules []transaction.WitnessRule `json:"rules,omitempty"` + InvocationScript []byte `json:"invocation,omitempty"` + VerificationScript []byte `json:"verification,omitempty"` } -// Batch represents a standard JSON-RPC 2.0 -// batch: https://www.jsonrpc.org/specification#batch. -type Batch []In - // MarshalJSON implements the json.Marshaler interface. -func (r Request) MarshalJSON() ([]byte, error) { - if r.In != nil { - return json.Marshal(r.In) +func (s *SignerWithWitness) MarshalJSON() ([]byte, error) { + signer := &signerWithWitnessAux{ + Account: s.Account.StringLE(), + Scopes: s.Scopes, + AllowedContracts: s.AllowedContracts, + AllowedGroups: s.AllowedGroups, + Rules: s.Rules, + InvocationScript: s.InvocationScript, + VerificationScript: s.VerificationScript, } - return json.Marshal(r.Batch) + return json.Marshal(signer) } // UnmarshalJSON implements the json.Unmarshaler interface. -func (r *Request) UnmarshalJSON(data []byte) error { - var ( - in *In - batch Batch - ) - in = &In{} - err := json.Unmarshal(data, in) - if err == nil { - r.In = in - return nil - } - decoder := json.NewDecoder(bytes.NewReader(data)) - t, err := decoder.Token() // read `[` +func (s *SignerWithWitness) UnmarshalJSON(data []byte) error { + aux := new(signerWithWitnessAux) + err := json.Unmarshal(data, aux) if err != nil { - return err + return fmt.Errorf("not a signer: %w", err) } - if t != json.Delim('[') { - return fmt.Errorf("`[` expected, got %s", t) + acc, err := util.Uint160DecodeStringLE(strings.TrimPrefix(aux.Account, "0x")) + if err != nil { + acc, err = address.StringToUint160(aux.Account) } - count := 0 - for decoder.More() { - if count > maxBatchSize { - return fmt.Errorf("the number of requests in batch shouldn't exceed %d", maxBatchSize) - } - in = &In{} - decodeErr := decoder.Decode(in) - if decodeErr != nil { - return decodeErr - } - batch = append(batch, *in) - count++ + if err != nil { + return fmt.Errorf("not a signer: %w", err) } - if len(batch) == 0 { - return errors.New("empty request") + s.Signer = transaction.Signer{ + Account: acc, + Scopes: aux.Scopes, + AllowedContracts: aux.AllowedContracts, + AllowedGroups: aux.AllowedGroups, + Rules: aux.Rules, + } + s.Witness = transaction.Witness{ + InvocationScript: aux.InvocationScript, + VerificationScript: aux.VerificationScript, } - r.Batch = batch return nil } - -// DecodeData decodes the given reader into the the request -// struct. -func (r *Request) DecodeData(data io.ReadCloser) error { - defer data.Close() - - rawData := json.RawMessage{} - err := json.NewDecoder(data).Decode(&rawData) - if err != nil { - return fmt.Errorf("error parsing JSON payload: %w", err) - } - - return r.UnmarshalJSON(rawData) -} - -// NewRequest creates a new Request struct. -func NewRequest() *Request { - return &Request{} -} - -// NewIn creates a new In struct. -func NewIn() *In { - return &In{ - JSONRPC: JSONRPCVersion, - } -} diff --git a/pkg/rpc/request/param.go b/pkg/rpc/server/params/param.go similarity index 74% rename from pkg/rpc/request/param.go rename to pkg/rpc/server/params/param.go index 429955ce8..b4dfcd4da 100644 --- a/pkg/rpc/request/param.go +++ b/pkg/rpc/server/params/param.go @@ -1,4 +1,4 @@ -package request +package params import ( "bytes" @@ -13,8 +13,8 @@ import ( "github.com/google/uuid" "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -34,35 +34,6 @@ type ( Type smartcontract.ParamType `json:"type"` Value Param `json:"value"` } - // BlockFilter is a wrapper structure for the block event filter. The only - // allowed filter is primary index. - BlockFilter struct { - Primary int `json:"primary"` - } - // TxFilter is a wrapper structure for the transaction event filter. It - // allows to filter transactions by senders and signers. - TxFilter struct { - Sender *util.Uint160 `json:"sender,omitempty"` - Signer *util.Uint160 `json:"signer,omitempty"` - } - // NotificationFilter is a wrapper structure representing a filter used for - // notifications generated during transaction execution. Notifications can - // be filtered by contract hash and by name. - NotificationFilter struct { - Contract *util.Uint160 `json:"contract,omitempty"` - Name *string `json:"name,omitempty"` - } - // ExecutionFilter is a wrapper structure used for transaction execution - // events. It allows to choose failing or successful transactions based - // on their VM state. - ExecutionFilter struct { - State string `json:"state"` - } - // SignerWithWitness represents transaction's signer with the corresponding witness. - SignerWithWitness struct { - transaction.Signer - transaction.Witness - } ) var ( @@ -409,33 +380,13 @@ func (p *Param) GetBytesBase64() ([]byte, error) { return base64.StdEncoding.DecodeString(s) } -// GetSignerWithWitness returns a SignerWithWitness value of the parameter. -func (p *Param) GetSignerWithWitness() (SignerWithWitness, error) { +// GetSignerWithWitness returns a request.SignerWithWitness value of the parameter. +func (p *Param) GetSignerWithWitness() (request.SignerWithWitness, error) { // This one doesn't need to be cached, it's used only once. - aux := new(signerWithWitnessAux) - err := json.Unmarshal(p.RawMessage, aux) + c := request.SignerWithWitness{} + err := json.Unmarshal(p.RawMessage, &c) if err != nil { - return SignerWithWitness{}, fmt.Errorf("not a signer: %w", err) - } - acc, err := util.Uint160DecodeStringLE(strings.TrimPrefix(aux.Account, "0x")) - if err != nil { - acc, err = address.StringToUint160(aux.Account) - } - if err != nil { - return SignerWithWitness{}, fmt.Errorf("not a signer: %w", err) - } - c := SignerWithWitness{ - Signer: transaction.Signer{ - Account: acc, - Scopes: aux.Scopes, - AllowedContracts: aux.AllowedContracts, - AllowedGroups: aux.AllowedGroups, - Rules: aux.Rules, - }, - Witness: transaction.Witness{ - InvocationScript: aux.InvocationScript, - VerificationScript: aux.VerificationScript, - }, + return request.SignerWithWitness{}, fmt.Errorf("not a signer: %w", err) } return c, nil } @@ -480,32 +431,6 @@ func (p *Param) IsNull() bool { return bytes.Equal(p.RawMessage, jsonNullBytes) } -// signerWithWitnessAux is an auxiliary struct for JSON marshalling. We need it because of -// DisallowUnknownFields JSON marshaller setting. -type signerWithWitnessAux struct { - Account string `json:"account"` - Scopes transaction.WitnessScope `json:"scopes"` - AllowedContracts []util.Uint160 `json:"allowedcontracts,omitempty"` - AllowedGroups []*keys.PublicKey `json:"allowedgroups,omitempty"` - Rules []transaction.WitnessRule `json:"rules,omitempty"` - InvocationScript []byte `json:"invocation,omitempty"` - VerificationScript []byte `json:"verification,omitempty"` -} - -// MarshalJSON implements the json.Marshaler interface. -func (s *SignerWithWitness) MarshalJSON() ([]byte, error) { - signer := &signerWithWitnessAux{ - Account: s.Account.StringLE(), - Scopes: s.Scopes, - AllowedContracts: s.AllowedContracts, - AllowedGroups: s.AllowedGroups, - Rules: s.Rules, - InvocationScript: s.InvocationScript, - VerificationScript: s.VerificationScript, - } - return json.Marshal(signer) -} - // GetUUID returns UUID from parameter. func (p *Param) GetUUID() (uuid.UUID, error) { s, err := p.GetString() diff --git a/pkg/rpc/request/param_test.go b/pkg/rpc/server/params/param_test.go similarity index 96% rename from pkg/rpc/request/param_test.go rename to pkg/rpc/server/params/param_test.go index 59e0a2bcb..44227ab59 100644 --- a/pkg/rpc/request/param_test.go +++ b/pkg/rpc/server/params/param_test.go @@ -1,4 +1,4 @@ -package request +package params import ( "encoding/base64" @@ -12,6 +12,7 @@ import ( "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/rpc/request" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/assert" @@ -154,7 +155,7 @@ func TestParam_UnmarshalJSON(t *testing.T) { require.NoError(t, err) expectedAcc, err := util.Uint160DecodeStringLE("cadb3dc2faa3ef14a13b619c9a43124755aa2569") require.NoError(t, err) - require.Equal(t, SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc}}, actual) + require.Equal(t, request.SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc}}, actual) }, expectedRawMessage: []byte(`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"}`), }, @@ -164,7 +165,7 @@ func TestParam_UnmarshalJSON(t *testing.T) { require.NoError(t, err) expectedAcc, err := address.StringToUint160("NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag") require.NoError(t, err) - require.Equal(t, SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc, Scopes: transaction.Global}}, actual) + require.Equal(t, request.SignerWithWitness{Signer: transaction.Signer{Account: expectedAcc, Scopes: transaction.Global}}, actual) }, expectedRawMessage: []byte(`{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"}`), }, @@ -243,21 +244,21 @@ func TestGetWitness(t *testing.T) { testCases := []struct { raw string - expected SignerWithWitness + expected request.SignerWithWitness }{ - {`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"}`, SignerWithWitness{ + {`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"}`, request.SignerWithWitness{ Signer: transaction.Signer{ Account: accountHash, Scopes: transaction.None, }}, }, - {`{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"}`, SignerWithWitness{ + {`{"account": "NYxb4fSZVKAz8YsgaPK2WkT3KcAE9b3Vag", "scopes": "Global"}`, request.SignerWithWitness{ Signer: transaction.Signer{ Account: addrHash, Scopes: transaction.Global, }}, }, - {`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}`, SignerWithWitness{ + {`{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": "Global"}`, request.SignerWithWitness{ Signer: transaction.Signer{ Account: accountHash, Scopes: transaction.Global, @@ -404,7 +405,7 @@ func TestParamGetBytesBase64(t *testing.T) { } func TestParamGetSigner(t *testing.T) { - c := SignerWithWitness{ + c := request.SignerWithWitness{ Signer: transaction.Signer{ Account: util.Uint160{1, 2, 3, 4}, Scopes: transaction.Global, diff --git a/pkg/rpc/request/params.go b/pkg/rpc/server/params/params.go similarity index 95% rename from pkg/rpc/request/params.go rename to pkg/rpc/server/params/params.go index 9ba8fb159..92a197f8d 100644 --- a/pkg/rpc/request/params.go +++ b/pkg/rpc/server/params/params.go @@ -1,4 +1,4 @@ -package request +package params import "fmt" diff --git a/pkg/rpc/request/txBuilder.go b/pkg/rpc/server/params/txBuilder.go similarity index 99% rename from pkg/rpc/request/txBuilder.go rename to pkg/rpc/server/params/txBuilder.go index 84215314d..2c8272739 100644 --- a/pkg/rpc/request/txBuilder.go +++ b/pkg/rpc/server/params/txBuilder.go @@ -1,4 +1,4 @@ -package request +package params import ( "errors" diff --git a/pkg/rpc/request/tx_builder_test.go b/pkg/rpc/server/params/tx_builder_test.go similarity index 99% rename from pkg/rpc/request/tx_builder_test.go rename to pkg/rpc/server/params/tx_builder_test.go index 1a5fd4f1a..983e31abb 100644 --- a/pkg/rpc/request/tx_builder_test.go +++ b/pkg/rpc/server/params/tx_builder_test.go @@ -1,4 +1,4 @@ -package request +package params import ( "encoding/base64" diff --git a/pkg/rpc/server/params/types.go b/pkg/rpc/server/params/types.go new file mode 100644 index 000000000..48e3403eb --- /dev/null +++ b/pkg/rpc/server/params/types.go @@ -0,0 +1,111 @@ +package params + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io" + + "github.com/nspcc-dev/neo-go/pkg/rpc/request" +) + +const ( + // maxBatchSize is the maximum number of requests per batch. + maxBatchSize = 100 +) + +// Request contains standard JSON-RPC 2.0 request and batch of +// requests: http://www.jsonrpc.org/specification. +// It's used in server to represent incoming queries. +type Request struct { + In *In + Batch Batch +} + +// In represents a standard JSON-RPC 2.0 +// request: http://www.jsonrpc.org/specification#request_object. +type In struct { + JSONRPC string `json:"jsonrpc"` + Method string `json:"method"` + RawParams []Param `json:"params,omitempty"` + RawID json.RawMessage `json:"id,omitempty"` +} + +// Batch represents a standard JSON-RPC 2.0 +// batch: https://www.jsonrpc.org/specification#batch. +type Batch []In + +// MarshalJSON implements the json.Marshaler interface. +func (r Request) MarshalJSON() ([]byte, error) { + if r.In != nil { + return json.Marshal(r.In) + } + return json.Marshal(r.Batch) +} + +// UnmarshalJSON implements the json.Unmarshaler interface. +func (r *Request) UnmarshalJSON(data []byte) error { + var ( + in *In + batch Batch + ) + in = &In{} + err := json.Unmarshal(data, in) + if err == nil { + r.In = in + return nil + } + decoder := json.NewDecoder(bytes.NewReader(data)) + t, err := decoder.Token() // read `[` + if err != nil { + return err + } + if t != json.Delim('[') { + return fmt.Errorf("`[` expected, got %s", t) + } + count := 0 + for decoder.More() { + if count > maxBatchSize { + return fmt.Errorf("the number of requests in batch shouldn't exceed %d", maxBatchSize) + } + in = &In{} + decodeErr := decoder.Decode(in) + if decodeErr != nil { + return decodeErr + } + batch = append(batch, *in) + count++ + } + if len(batch) == 0 { + return errors.New("empty request") + } + r.Batch = batch + return nil +} + +// DecodeData decodes the given reader into the the request +// struct. +func (r *Request) DecodeData(data io.ReadCloser) error { + defer data.Close() + + rawData := json.RawMessage{} + err := json.NewDecoder(data).Decode(&rawData) + if err != nil { + return fmt.Errorf("error parsing JSON payload: %w", err) + } + + return r.UnmarshalJSON(rawData) +} + +// NewRequest creates a new Request struct. +func NewRequest() *Request { + return &Request{} +} + +// NewIn creates a new In struct. +func NewIn() *In { + return &In{ + JSONRPC: request.JSONRPCVersion, + } +} diff --git a/pkg/rpc/request/types_test.go b/pkg/rpc/server/params/types_test.go similarity index 98% rename from pkg/rpc/request/types_test.go rename to pkg/rpc/server/params/types_test.go index aabbb27fe..d4bab190b 100644 --- a/pkg/rpc/request/types_test.go +++ b/pkg/rpc/server/params/types_test.go @@ -1,4 +1,4 @@ -package request +package params import ( "bytes" diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 39ed8a909..cd8460e48 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -44,6 +44,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/rpc/response" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result/subscriptions" + "github.com/nspcc-dev/neo-go/pkg/rpc/server/params" "github.com/nspcc-dev/neo-go/pkg/services/oracle" "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" @@ -148,7 +149,7 @@ const ( defaultSessionPoolSize = 20 ) -var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *response.Error){ +var rpcHandlers = map[string]func(*Server, params.Params) (interface{}, *response.Error){ "calculatenetworkfee": (*Server).calculateNetworkFee, "findstates": (*Server).findStates, "getapplicationlog": (*Server).getApplicationLog, @@ -197,7 +198,7 @@ var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, *respon "verifyproof": (*Server).verifyProof, } -var rpcWsHandlers = map[string]func(*Server, request.Params, *subscriber) (interface{}, *response.Error){ +var rpcWsHandlers = map[string]func(*Server, params.Params, *subscriber) (interface{}, *response.Error){ "subscribe": (*Server).subscribe, "unsubscribe": (*Server).unsubscribe, } @@ -366,7 +367,7 @@ func (s *Server) Shutdown() { } func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Request) { - req := request.NewRequest() + req := params.NewRequest() if httpRequest.URL.Path == "/ws" && httpRequest.Method == "GET" { // Technically there is a race between this check and @@ -378,7 +379,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.subsLock.RUnlock() if numOfSubs >= maxSubscribers { s.writeHTTPErrorResponse( - request.NewIn(), + params.NewIn(), w, response.NewInternalServerError("websocket users limit reached"), ) @@ -402,7 +403,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ if httpRequest.Method != "POST" { s.writeHTTPErrorResponse( - request.NewIn(), + params.NewIn(), w, response.NewInvalidParamsError(fmt.Sprintf("invalid method '%s', please retry with 'POST'", httpRequest.Method)), ) @@ -411,7 +412,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ err := req.DecodeData(httpRequest.Body) if err != nil { - s.writeHTTPErrorResponse(request.NewIn(), w, response.NewParseError(err.Error())) + s.writeHTTPErrorResponse(params.NewIn(), w, response.NewParseError(err.Error())) return } @@ -419,7 +420,7 @@ func (s *Server) handleHTTPRequest(w http.ResponseWriter, httpRequest *http.Requ s.writeHTTPServerResponse(req, w, resp) } -func (s *Server) handleRequest(req *request.Request, sub *subscriber) abstractResult { +func (s *Server) handleRequest(req *params.Request, sub *subscriber) abstractResult { if req.In != nil { req.In.Method = escapeForLog(req.In.Method) // No valid method name will be changed by it. return s.handleIn(req.In, sub) @@ -432,14 +433,14 @@ func (s *Server) handleRequest(req *request.Request, sub *subscriber) abstractRe return resp } -func (s *Server) handleIn(req *request.In, sub *subscriber) abstract { +func (s *Server) handleIn(req *params.In, sub *subscriber) abstract { var res interface{} var resErr *response.Error if req.JSONRPC != request.JSONRPCVersion { return s.packResponse(req, nil, response.NewInvalidParamsError(fmt.Sprintf("problem parsing JSON: invalid version, expected 2.0 got '%s'", req.JSONRPC))) } - reqParams := request.Params(req.RawParams) + reqParams := params.Params(req.RawParams) s.log.Debug("processing rpc request", zap.String("method", req.Method), @@ -519,7 +520,7 @@ func (s *Server) handleWsReads(ws *websocket.Conn, resChan chan<- abstractResult ws.SetPongHandler(func(string) error { return ws.SetReadDeadline(time.Now().Add(wsPongLimit)) }) requestloop: for err == nil { - req := request.NewRequest() + req := params.NewRequest() err := ws.ReadJSON(req) if err != nil { break @@ -546,23 +547,23 @@ requestloop: ws.Close() } -func (s *Server) getBestBlockHash(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBestBlockHash(_ params.Params) (interface{}, *response.Error) { return "0x" + s.chain.CurrentBlockHash().StringLE(), nil } -func (s *Server) getBlockCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockCount(_ params.Params) (interface{}, *response.Error) { return s.chain.BlockHeight() + 1, nil } -func (s *Server) getBlockHeaderCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHeaderCount(_ params.Params) (interface{}, *response.Error) { return s.chain.HeaderHeight() + 1, nil } -func (s *Server) getConnectionCount(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getConnectionCount(_ params.Params) (interface{}, *response.Error) { return s.coreServer.PeerCount(), nil } -func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *response.Error) { +func (s *Server) blockHashFromParam(param *params.Param) (util.Uint256, *response.Error) { var ( hash util.Uint256 err error @@ -581,7 +582,7 @@ func (s *Server) blockHashFromParam(param *request.Param) (util.Uint256, *respon return hash, nil } -func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlock(reqParams params.Params) (interface{}, *response.Error) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -601,7 +602,7 @@ func (s *Server) getBlock(reqParams request.Params) (interface{}, *response.Erro return writer.Bytes(), nil } -func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHash(reqParams params.Params) (interface{}, *response.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return nil, response.ErrInvalidParams @@ -610,7 +611,7 @@ func (s *Server) getBlockHash(reqParams request.Params) (interface{}, *response. return s.chain.GetHeaderHash(num), nil } -func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getVersion(_ params.Params) (interface{}, *response.Error) { port, err := s.coreServer.Port() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err)) @@ -638,7 +639,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) { }, nil } -func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getPeers(_ params.Params) (interface{}, *response.Error) { peers := result.NewGetPeers() peers.AddUnconnected(s.coreServer.UnconnectedPeers()) peers.AddConnected(s.coreServer.ConnectedPeers()) @@ -646,7 +647,7 @@ func (s *Server) getPeers(_ request.Params) (interface{}, *response.Error) { return peers, nil } -func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getRawMempool(reqParams params.Params) (interface{}, *response.Error) { verbose, _ := reqParams.Value(0).GetBoolean() mp := s.chain.GetMemPool() hashList := make([]util.Uint256, 0) @@ -663,7 +664,7 @@ func (s *Server) getRawMempool(reqParams request.Params) (interface{}, *response }, nil } -func (s *Server) validateAddress(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) validateAddress(reqParams params.Params) (interface{}, *response.Error) { param, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -676,7 +677,7 @@ func (s *Server) validateAddress(reqParams request.Params) (interface{}, *respon } // calculateNetworkFee calculates network fee for the transaction. -func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) calculateNetworkFee(reqParams params.Params) (interface{}, *response.Error) { if len(reqParams) < 1 { return 0, response.ErrInvalidParams } @@ -730,7 +731,7 @@ func (s *Server) calculateNetworkFee(reqParams request.Params) (interface{}, *re } // getApplicationLog returns the contract log based on the specified txid or blockid. -func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getApplicationLog(reqParams params.Params) (interface{}, *response.Error) { hash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -779,7 +780,7 @@ func (s *Server) getNEP11Tokens(h util.Uint160, acc util.Uint160, bw *io.BufBinW return vals, sym, int(dec.Int64()), nil } -func (s *Server) getNEP11Balances(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Balances(ps params.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -868,7 +869,7 @@ func (s *Server) invokeNEP11Properties(h util.Uint160, id []byte, bw *io.BufBinW return item.Value().([]stackitem.MapElement), nil } -func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Properties(ps params.Params) (interface{}, *response.Error) { asset, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -904,7 +905,7 @@ func (s *Server) getNEP11Properties(ps request.Params) (interface{}, *response.E return res, nil } -func (s *Server) getNEP17Balances(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP17Balances(ps params.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1034,7 +1035,7 @@ func (s *Server) getNEP11DTokenBalance(h util.Uint160, acc util.Uint160, id []by return res, nil } -func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, int, error) { +func getTimestampsAndLimit(ps params.Params, index int) (uint64, uint64, int, int, error) { var start, end uint64 var limit, page int @@ -1084,15 +1085,15 @@ func getTimestampsAndLimit(ps request.Params, index int) (uint64, uint64, int, i return start, end, limit, page, nil } -func (s *Server) getNEP11Transfers(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP11Transfers(ps params.Params) (interface{}, *response.Error) { return s.getTokenTransfers(ps, true) } -func (s *Server) getNEP17Transfers(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getNEP17Transfers(ps params.Params) (interface{}, *response.Error) { return s.getTokenTransfers(ps, false) } -func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}, *response.Error) { +func (s *Server) getTokenTransfers(ps params.Params, isNEP11 bool) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1209,7 +1210,7 @@ func (s *Server) getHash(contractID int32, cache map[int32]util.Uint160) (util.U return h, nil } -func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Error) { +func (s *Server) contractIDFromParam(param *params.Param) (int32, *response.Error) { var result int32 if param == nil { return 0, response.ErrInvalidParams @@ -1234,7 +1235,7 @@ func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Err } // getContractScriptHashFromParam returns the contract script hash by hex contract hash, address, id or native contract name. -func (s *Server) contractScriptHashFromParam(param *request.Param) (util.Uint160, *response.Error) { +func (s *Server) contractScriptHashFromParam(param *params.Param) (util.Uint160, *response.Error) { var result util.Uint160 if param == nil { return result, response.ErrInvalidParams @@ -1274,7 +1275,7 @@ func makeStorageKey(id int32, key []byte) []byte { var errKeepOnlyLatestState = errors.New("'KeepOnlyLatestState' setting is enabled") -func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getProof(ps params.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'getproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1305,7 +1306,7 @@ func (s *Server) getProof(ps request.Params) (interface{}, *response.Error) { }, nil } -func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { +func (s *Server) verifyProof(ps params.Params) (interface{}, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("'verifyproof' is not supported: %s", errKeepOnlyLatestState)) } @@ -1329,7 +1330,7 @@ func (s *Server) verifyProof(ps request.Params) (interface{}, *response.Error) { return vp, nil } -func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getState(ps params.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1363,7 +1364,7 @@ func (s *Server) getState(ps request.Params) (interface{}, *response.Error) { return res, nil } -func (s *Server) findStates(ps request.Params) (interface{}, *response.Error) { +func (s *Server) findStates(ps params.Params) (interface{}, *response.Error) { root, err := ps.Value(0).GetUint256() if err != nil { return nil, response.WrapErrorWithData(response.ErrInvalidParams, "invalid stateroot") @@ -1471,7 +1472,7 @@ func (s *Server) getHistoricalContractState(root util.Uint256, csHash util.Uint1 return contract, nil } -func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getStateHeight(_ params.Params) (interface{}, *response.Error) { var height = s.chain.BlockHeight() var stateHeight = s.chain.GetStateModule().CurrentValidatedHeight() if s.chain.GetConfig().StateRootInHeader { @@ -1483,7 +1484,7 @@ func (s *Server) getStateHeight(_ request.Params) (interface{}, *response.Error) }, nil } -func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getStateRoot(ps params.Params) (interface{}, *response.Error) { p := ps.Value(0) if p == nil { return nil, response.NewInvalidParamsError("missing stateroot identifier") @@ -1509,7 +1510,7 @@ func (s *Server) getStateRoot(ps request.Params) (interface{}, *response.Error) return rt, nil } -func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getStorage(ps params.Params) (interface{}, *response.Error) { id, rErr := s.contractIDFromParam(ps.Value(0)) if rErr == response.ErrUnknown { return nil, nil @@ -1531,7 +1532,7 @@ func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) { return []byte(item), nil } -func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getrawtransaction(reqParams params.Params) (interface{}, *response.Error) { txHash, err := reqParams.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1561,7 +1562,7 @@ func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *resp return tx.Bytes(), nil } -func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getTransactionHeight(ps params.Params) (interface{}, *response.Error) { h, err := ps.Value(0).GetUint256() if err != nil { return nil, response.ErrInvalidParams @@ -1577,7 +1578,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response // getContractState returns contract state (contract information, according to the contract script hash, // contract id or native contract name). -func (s *Server) getContractState(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getContractState(reqParams params.Params) (interface{}, *response.Error) { scriptHash, err := s.contractScriptHashFromParam(reqParams.Value(0)) if err != nil { return nil, err @@ -1589,12 +1590,12 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, *respo return cs, nil } -func (s *Server) getNativeContracts(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getNativeContracts(_ params.Params) (interface{}, *response.Error) { return s.chain.GetNatives(), nil } // getBlockSysFee returns the system fees of the block, based on the specified index. -func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockSysFee(reqParams params.Params) (interface{}, *response.Error) { num, err := s.blockHeightFromParam(reqParams.Value(0)) if err != nil { return 0, response.NewRPCError("Invalid height", "invalid block identifier") @@ -1615,7 +1616,7 @@ func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, *respons } // getBlockHeader returns the corresponding block header information according to the specified script hash. -func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) getBlockHeader(reqParams params.Params) (interface{}, *response.Error) { param := reqParams.Value(0) hash, respErr := s.blockHashFromParam(param) if respErr != nil { @@ -1641,7 +1642,7 @@ func (s *Server) getBlockHeader(reqParams request.Params) (interface{}, *respons } // getUnclaimedGas returns unclaimed GAS amount of the specified address. -func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Error) { +func (s *Server) getUnclaimedGas(ps params.Params) (interface{}, *response.Error) { u, err := ps.Value(0).GetUint160FromAddressOrHex() if err != nil { return nil, response.ErrInvalidParams @@ -1664,7 +1665,7 @@ func (s *Server) getUnclaimedGas(ps request.Params) (interface{}, *response.Erro } // getCandidates returns the current list of candidates with their active/inactive voting status. -func (s *Server) getCandidates(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getCandidates(_ params.Params) (interface{}, *response.Error) { var validators keys.PublicKeys validators, err := s.chain.GetNextBlockValidators() @@ -1687,7 +1688,7 @@ func (s *Server) getCandidates(_ request.Params) (interface{}, *response.Error) } // getNextBlockValidators returns validators for the next block with voting status. -func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getNextBlockValidators(_ params.Params) (interface{}, *response.Error) { var validators keys.PublicKeys validators, err := s.chain.GetNextBlockValidators() @@ -1712,7 +1713,7 @@ func (s *Server) getNextBlockValidators(_ request.Params) (interface{}, *respons } // getCommittee returns the current list of NEO committee members. -func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { +func (s *Server) getCommittee(_ params.Params) (interface{}, *response.Error) { keys, err := s.chain.GetCommittee() if err != nil { return nil, response.NewInternalServerError(fmt.Sprintf("can't get committee members: %s", err)) @@ -1721,7 +1722,7 @@ func (s *Server) getCommittee(_ request.Params) (interface{}, *response.Error) { } // invokeFunction implements the `invokeFunction` RPC call. -func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeFunction(reqParams params.Params) (interface{}, *response.Error) { tx, verbose, respErr := s.getInvokeFunctionParams(reqParams) if respErr != nil { return nil, respErr @@ -1730,7 +1731,7 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons } // invokeFunctionHistoric implements the `invokeFunctionHistoric` RPC call. -func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeFunctionHistoric(reqParams params.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1745,7 +1746,7 @@ func (s *Server) invokeFunctionHistoric(reqParams request.Params) (interface{}, return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { +func (s *Server) getInvokeFunctionParams(reqParams params.Params) (*transaction.Transaction, bool, *response.Error) { if len(reqParams) < 2 { return nil, false, response.ErrInvalidParams } @@ -1757,9 +1758,9 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction if err != nil { return nil, false, response.ErrInvalidParams } - var params *request.Param + var invparams *params.Param if len(reqParams) > 2 { - params = &reqParams[2] + invparams = &reqParams[2] } tx := &transaction.Transaction{} if len(reqParams) > 3 { @@ -1779,7 +1780,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction if len(tx.Signers) == 0 { tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.None}} } - script, err := request.CreateFunctionInvocationScript(scriptHash, method, params) + script, err := params.CreateFunctionInvocationScript(scriptHash, method, invparams) if err != nil { return nil, false, response.NewInternalServerError(fmt.Sprintf("can't create invocation script: %s", err)) } @@ -1788,7 +1789,7 @@ func (s *Server) getInvokeFunctionParams(reqParams request.Params) (*transaction } // invokescript implements the `invokescript` RPC call. -func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokescript(reqParams params.Params) (interface{}, *response.Error) { tx, verbose, respErr := s.getInvokeScriptParams(reqParams) if respErr != nil { return nil, respErr @@ -1797,7 +1798,7 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response. } // invokescripthistoric implements the `invokescripthistoric` RPC call. -func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokescripthistoric(reqParams params.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1812,7 +1813,7 @@ func (s *Server) invokescripthistoric(reqParams request.Params) (interface{}, *r return s.runScriptInVM(trigger.Application, tx.Script, util.Uint160{}, tx, b, verbose) } -func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.Transaction, bool, *response.Error) { +func (s *Server) getInvokeScriptParams(reqParams params.Params) (*transaction.Transaction, bool, *response.Error) { script, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, false, response.ErrInvalidParams @@ -1842,7 +1843,7 @@ func (s *Server) getInvokeScriptParams(reqParams request.Params) (*transaction.T } // invokeContractVerify implements the `invokecontractverify` RPC call. -func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeContractVerify(reqParams params.Params) (interface{}, *response.Error) { scriptHash, tx, invocationScript, respErr := s.getInvokeContractVerifyParams(reqParams) if respErr != nil { return nil, respErr @@ -1851,7 +1852,7 @@ func (s *Server) invokeContractVerify(reqParams request.Params) (interface{}, *r } // invokeContractVerifyHistoric implements the `invokecontractverifyhistoric` RPC call. -func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) invokeContractVerifyHistoric(reqParams params.Params) (interface{}, *response.Error) { b, respErr := s.getHistoricParams(reqParams) if respErr != nil { return nil, respErr @@ -1866,7 +1867,7 @@ func (s *Server) invokeContractVerifyHistoric(reqParams request.Params) (interfa return s.runScriptInVM(trigger.Verification, invocationScript, scriptHash, tx, b, false) } -func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.Uint160, *transaction.Transaction, []byte, *response.Error) { +func (s *Server) getInvokeContractVerifyParams(reqParams params.Params) (util.Uint160, *transaction.Transaction, []byte, *response.Error) { scriptHash, responseErr := s.contractScriptHashFromParam(reqParams.Value(0)) if responseErr != nil { return util.Uint160{}, nil, nil, responseErr @@ -1879,7 +1880,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U return util.Uint160{}, nil, nil, response.WrapErrorWithData(response.ErrInvalidParams, err.Error()) } if len(args) > 0 { - err := request.ExpandArrayIntoScript(bw.BinWriter, args) + err := params.ExpandArrayIntoScript(bw.BinWriter, args) if err != nil { return util.Uint160{}, nil, nil, response.NewInternalServerError(fmt.Sprintf("can't create witness invocation script: %s", err)) } @@ -1906,7 +1907,7 @@ func (s *Server) getInvokeContractVerifyParams(reqParams request.Params) (util.U // with the specified index to perform the historic call. It also checks that // specified stateroot is stored at the specified height for further request // handling consistency. -func (s *Server) getHistoricParams(reqParams request.Params) (*block.Block, *response.Error) { +func (s *Server) getHistoricParams(reqParams params.Params) (*block.Block, *response.Error) { if s.chain.GetConfig().KeepOnlyLatestState { return nil, response.NewInvalidRequestError(fmt.Sprintf("only latest state is supported: %s", errKeepOnlyLatestState)) } @@ -2065,7 +2066,7 @@ func (s *Server) runScriptInVM(t trigger.Type, script []byte, contractScriptHash return result.NewInvoke(ic, script, faultException, registerIterator, s.config.MaxIteratorResultItems), nil } -func (s *Server) traverseIterator(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) traverseIterator(reqParams params.Params) (interface{}, *response.Error) { if !s.config.SessionEnabled { return nil, response.NewInvalidRequestError("sessions are disabled") } @@ -2154,7 +2155,7 @@ func (s *Server) traverseIterator(reqParams request.Params) (interface{}, *respo return result, nil } -func (s *Server) terminateSession(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) terminateSession(reqParams params.Params) (interface{}, *response.Error) { if !s.config.SessionEnabled { return nil, response.NewInvalidRequestError("sessions are disabled") } @@ -2183,7 +2184,7 @@ func (s *Server) terminateSession(reqParams request.Params) (interface{}, *respo } // submitBlock broadcasts a raw block over the NEO network. -func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) submitBlock(reqParams params.Params) (interface{}, *response.Error) { blockBytes, err := reqParams.Value(0).GetBytesBase64() if err != nil { return nil, response.NewInvalidParamsError(fmt.Sprintf("missing parameter or not a base64: %s", err)) @@ -2209,7 +2210,7 @@ func (s *Server) submitBlock(reqParams request.Params) (interface{}, *response.E } // submitNotaryRequest broadcasts P2PNotaryRequest over the NEO network. -func (s *Server) submitNotaryRequest(ps request.Params) (interface{}, *response.Error) { +func (s *Server) submitNotaryRequest(ps params.Params) (interface{}, *response.Error) { if !s.chain.P2PSigExtensionsEnabled() { return nil, response.NewRPCError("P2PSignatureExtensions are disabled", "") } @@ -2243,7 +2244,7 @@ func getRelayResult(err error, hash util.Uint256) (interface{}, *response.Error) } } -func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response.Error) { +func (s *Server) submitOracleResponse(ps params.Params) (interface{}, *response.Error) { if s.oracle == nil { return nil, response.NewRPCError("Oracle is not enabled", "") } @@ -2275,7 +2276,7 @@ func (s *Server) submitOracleResponse(ps request.Params) (interface{}, *response return json.RawMessage([]byte("{}")), nil } -func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *response.Error) { +func (s *Server) sendrawtransaction(reqParams params.Params) (interface{}, *response.Error) { if len(reqParams) < 1 { return nil, response.NewInvalidParamsError("not enough parameters") } @@ -2291,7 +2292,7 @@ func (s *Server) sendrawtransaction(reqParams request.Params) (interface{}, *res } // subscribe handles subscription requests from websocket clients. -func (s *Server) subscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { +func (s *Server) subscribe(reqParams params.Params, sub *subscriber) (interface{}, *response.Error) { streamName, err := reqParams.Value(0).GetString() if err != nil { return nil, response.ErrInvalidParams @@ -2392,7 +2393,7 @@ func (s *Server) subscribeToChannel(event response.EventID) { } // unsubscribe handles unsubscription requests from websocket clients. -func (s *Server) unsubscribe(reqParams request.Params, sub *subscriber) (interface{}, *response.Error) { +func (s *Server) unsubscribe(reqParams params.Params, sub *subscriber) (interface{}, *response.Error) { id, err := reqParams.Value(0).GetInt() if err != nil || id < 0 { return nil, response.ErrInvalidParams @@ -2562,7 +2563,7 @@ drainloop: close(s.notaryRequestCh) } -func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Error) { +func (s *Server) blockHeightFromParam(param *params.Param) (int, *response.Error) { num, err := param.GetInt() if err != nil { return 0, response.ErrInvalidParams @@ -2574,7 +2575,7 @@ func (s *Server) blockHeightFromParam(param *request.Param) (int, *response.Erro return num, nil } -func (s *Server) packResponse(r *request.In, result interface{}, respErr *response.Error) abstract { +func (s *Server) packResponse(r *params.In, result interface{}, respErr *response.Error) abstract { resp := abstract{ Header: response.Header{ JSONRPC: r.JSONRPC, @@ -2590,7 +2591,7 @@ func (s *Server) packResponse(r *request.In, result interface{}, respErr *respon } // logRequestError is a request error logger. -func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { +func (s *Server) logRequestError(r *params.Request, jsonErr *response.Error) { logFields := []zap.Field{ zap.Int64("code", jsonErr.Code), } @@ -2600,7 +2601,7 @@ func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { if r.In != nil { logFields = append(logFields, zap.String("method", r.In.Method)) - params := request.Params(r.In.RawParams) + params := params.Params(r.In.RawParams) logFields = append(logFields, zap.Any("params", params)) } @@ -2614,12 +2615,12 @@ func (s *Server) logRequestError(r *request.Request, jsonErr *response.Error) { } // writeHTTPErrorResponse writes an error response to the ResponseWriter. -func (s *Server) writeHTTPErrorResponse(r *request.In, w http.ResponseWriter, jsonErr *response.Error) { +func (s *Server) writeHTTPErrorResponse(r *params.In, w http.ResponseWriter, jsonErr *response.Error) { resp := s.packResponse(r, nil, jsonErr) - s.writeHTTPServerResponse(&request.Request{In: r}, w, resp) + s.writeHTTPServerResponse(¶ms.Request{In: r}, w, resp) } -func (s *Server) writeHTTPServerResponse(r *request.Request, w http.ResponseWriter, resp abstractResult) { +func (s *Server) writeHTTPServerResponse(r *params.Request, w http.ResponseWriter, resp abstractResult) { // Errors can happen in many places and we can only catch ALL of them here. resp.RunForErrors(func(jsonErr *response.Error) { s.logRequestError(r, jsonErr) diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index f69af3308..6e80c8eee 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -35,9 +35,9 @@ import ( "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/network" "github.com/nspcc-dev/neo-go/pkg/network/payload" - "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" + "github.com/nspcc-dev/neo-go/pkg/rpc/server/params" rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" @@ -3138,7 +3138,7 @@ func BenchmarkHandleIn(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { b.StopTimer() - in := new(request.In) + in := new(params.In) b.StartTimer() err := json.Unmarshal(req, in) if err != nil { From 9aecfb7c94d4ec594b6d3ee6e41aec8c41fa08a8 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 7 Jul 2022 17:45:33 +0300 Subject: [PATCH 2/4] rpc/client: correct ID unmarshaling in wsclient We always use uint64 IDs in the client, so we should parse them as such and not just ints that then are casted to uint64. --- pkg/rpc/client/wsclient.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/rpc/client/wsclient.go b/pkg/rpc/client/wsclient.go index 4a36585f8..5d3d00439 100644 --- a/pkg/rpc/client/wsclient.go +++ b/pkg/rpc/client/wsclient.go @@ -205,12 +205,12 @@ readloop: } c.Notifications <- Notification{event, val} } else if rr.ID != nil && (rr.Error != nil || rr.Result != nil) { - id, err := strconv.Atoi(string(rr.ID)) + id, err := strconv.ParseUint(string(rr.ID), 10, 64) if err != nil { connCloseErr = fmt.Errorf("failed to retrieve response ID from string %s: %w", string(rr.ID), err) break readloop // Malformed response (invalid response ID). } - ch := c.getResponseChannel(uint64(id)) + ch := c.getResponseChannel(id) if ch == nil { connCloseErr = fmt.Errorf("unknown response channel for response %d", id) break readloop // Unknown response (unexpected response ID). From 113cb0fac303d0bf3f8b566b68f527b8ba3cb8cd Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 7 Jul 2022 18:33:23 +0300 Subject: [PATCH 3/4] rpc: rename RawParams to Params in Raw, add comments We've got parameters here and usually we name them Raw when they're represented by json.RawMessage which is not the case here, so make it a bit more friendly (the type itself is only used in client internals, so rename is not a huge problem). --- pkg/rpc/client/client.go | 8 ++++---- pkg/rpc/client/wsclient.go | 2 +- pkg/rpc/request/types.go | 28 ++++++++++++++++++++-------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index a837e5238..b904c82b8 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -174,10 +174,10 @@ func (c *Client) Close() { func (c *Client) performRequest(method string, p request.RawParams, v interface{}) error { var r = request.Raw{ - JSONRPC: request.JSONRPCVersion, - Method: method, - RawParams: p.Values, - ID: c.getNextRequestID(), + JSONRPC: request.JSONRPCVersion, + Method: method, + Params: p.Values, + ID: c.getNextRequestID(), } raw, err := c.requestF(&r) diff --git a/pkg/rpc/client/wsclient.go b/pkg/rpc/client/wsclient.go index 5d3d00439..adcfdede8 100644 --- a/pkg/rpc/client/wsclient.go +++ b/pkg/rpc/client/wsclient.go @@ -256,7 +256,7 @@ writeloop: break writeloop } if err := c.ws.WriteJSON(req); err != nil { - connCloseErr = fmt.Errorf("failed to write JSON request (%s / %d): %w", req.Method, len(req.RawParams), err) + connCloseErr = fmt.Errorf("failed to write JSON request (%s / %d): %w", req.Method, len(req.Params), err) break writeloop } case <-pingTicker.C: diff --git a/pkg/rpc/request/types.go b/pkg/rpc/request/types.go index 7ef644862..866f91926 100644 --- a/pkg/rpc/request/types.go +++ b/pkg/rpc/request/types.go @@ -32,15 +32,27 @@ func NewRawParams(vals ...interface{}) RawParams { return p } -// Raw represents JSON-RPC request on the Client side. -type Raw struct { - JSONRPC string `json:"jsonrpc"` - Method string `json:"method"` - RawParams []interface{} `json:"params"` - ID uint64 `json:"id"` -} - type ( + // Raw represents JSON-RPC request. It's generic enough to be used in many + // generic JSON-RPC communication scenarios, yet at the same time it's + // tailored for NeoGo RPC Client needs. + Raw struct { + // JSONRPC is the protocol version, only valid when it contains JSONRPCVersion. + JSONRPC string `json:"jsonrpc"` + // Method is the method being called. + Method string `json:"method"` + // Params is a set of method-specific parameters passed to the call. They + // can be anything as long as they can be marshaled to JSON correctly and + // used by the method implementation on the server side. While JSON-RPC + // technically allows it to be an object, all Neo calls expect params + // to be an array. + Params []interface{} `json:"params"` + // ID is an identifier associated with this request. JSON-RPC itself allows + // any strings to be used for it as well, but NeoGo RPC client uses numeric + // identifiers. + ID uint64 `json:"id"` + } + // BlockFilter is a wrapper structure for the block event filter. The only // allowed filter is primary index. BlockFilter struct { From 9462ed71d8ad96fc424edccc1601ec211e88c409 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Thu, 7 Jul 2022 20:03:10 +0300 Subject: [PATCH 4/4] rpc: drop useless RawParams type It doesn't add anything useful to regular Go types and actually native types are always better to use in the Client. Especially given that this type is not used by any code outside of the Client itself. --- pkg/rpc/client/client.go | 7 +- pkg/rpc/client/rpc.go | 212 ++++++++---------- pkg/rpc/client/wsclient.go | 26 +-- pkg/rpc/request/types.go | 16 -- .../helpers/rpcbroadcaster/broadcaster.go | 7 +- pkg/services/helpers/rpcbroadcaster/client.go | 7 +- pkg/services/oracle/broadcaster/oracle.go | 7 +- 7 files changed, 124 insertions(+), 158 deletions(-) diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index b904c82b8..b511871b7 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -172,11 +172,14 @@ func (c *Client) Close() { c.cli.CloseIdleConnections() } -func (c *Client) performRequest(method string, p request.RawParams, v interface{}) error { +func (c *Client) performRequest(method string, p []interface{}, v interface{}) error { + if p == nil { + p = []interface{}{} // neo-project/neo-modules#742 + } var r = request.Raw{ JSONRPC: request.JSONRPCVersion, Method: method, - Params: p.Values, + Params: p, ID: c.getNextRequestID(), } diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index a35043f43..9cdd148b7 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -38,7 +38,7 @@ var errNetworkNotInitialized = errors.New("RPC client network is not initialized // filled for standard sig/multisig signers. func (c *Client) CalculateNetworkFee(tx *transaction.Transaction) (int64, error) { var ( - params = request.NewRawParams(tx.Bytes()) + params = []interface{}{tx.Bytes()} resp = new(result.NetworkFee) ) if err := c.performRequest("calculatenetworkfee", params, resp); err != nil { @@ -50,11 +50,11 @@ func (c *Client) CalculateNetworkFee(tx *transaction.Transaction) (int64, error) // GetApplicationLog returns a contract log based on the specified txid. func (c *Client) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) { var ( - params = request.NewRawParams(hash.StringLE()) + params = []interface{}{hash.StringLE()} resp = new(result.ApplicationLog) ) if trig != nil { - params.Values = append(params.Values, trig.String()) + params = append(params, trig.String()) } if err := c.performRequest("getapplicationlog", params, resp); err != nil { return nil, err @@ -65,7 +65,7 @@ func (c *Client) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*resu // GetBestBlockHash returns the hash of the tallest block in the blockchain. func (c *Client) GetBestBlockHash() (util.Uint256, error) { var resp = util.Uint256{} - if err := c.performRequest("getbestblockhash", request.NewRawParams(), &resp); err != nil { + if err := c.performRequest("getbestblockhash", nil, &resp); err != nil { return resp, err } return resp, nil @@ -74,7 +74,7 @@ func (c *Client) GetBestBlockHash() (util.Uint256, error) { // GetBlockCount returns the number of blocks in the blockchain. func (c *Client) GetBlockCount() (uint32, error) { var resp uint32 - if err := c.performRequest("getblockcount", request.NewRawParams(), &resp); err != nil { + if err := c.performRequest("getblockcount", nil, &resp); err != nil { return resp, err } return resp, nil @@ -83,22 +83,22 @@ func (c *Client) GetBlockCount() (uint32, error) { // GetBlockByIndex returns a block by its height. You should initialize network magic // with Init before calling GetBlockByIndex. func (c *Client) GetBlockByIndex(index uint32) (*block.Block, error) { - return c.getBlock(request.NewRawParams(index)) + return c.getBlock(index) } // GetBlockByHash returns a block by its hash. You should initialize network magic // with Init before calling GetBlockByHash. func (c *Client) GetBlockByHash(hash util.Uint256) (*block.Block, error) { - return c.getBlock(request.NewRawParams(hash.StringLE())) + return c.getBlock(hash.StringLE()) } -func (c *Client) getBlock(params request.RawParams) (*block.Block, error) { +func (c *Client) getBlock(param interface{}) (*block.Block, error) { var ( resp []byte err error b *block.Block ) - if err = c.performRequest("getblock", params, &resp); err != nil { + if err = c.performRequest("getblock", []interface{}{param}, &resp); err != nil { return nil, err } r := io.NewBinReaderFromBuf(resp) @@ -118,19 +118,20 @@ func (c *Client) getBlock(params request.RawParams) (*block.Block, error) { // its height. You should initialize network magic with Init before calling GetBlockByIndexVerbose. // NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively. func (c *Client) GetBlockByIndexVerbose(index uint32) (*result.Block, error) { - return c.getBlockVerbose(request.NewRawParams(index, 1)) + return c.getBlockVerbose(index) } // GetBlockByHashVerbose returns a block wrapper with additional metadata by // its hash. You should initialize network magic with Init before calling GetBlockByHashVerbose. func (c *Client) GetBlockByHashVerbose(hash util.Uint256) (*result.Block, error) { - return c.getBlockVerbose(request.NewRawParams(hash.StringLE(), 1)) + return c.getBlockVerbose(hash.StringLE()) } -func (c *Client) getBlockVerbose(params request.RawParams) (*result.Block, error) { +func (c *Client) getBlockVerbose(param interface{}) (*result.Block, error) { var ( - resp = &result.Block{} - err error + params = []interface{}{param, 1} // 1 for verbose. + resp = &result.Block{} + err error ) sr, err := c.StateRootInHeader() if err != nil { @@ -146,7 +147,7 @@ func (c *Client) getBlockVerbose(params request.RawParams) (*result.Block, error // GetBlockHash returns the hash value of the corresponding block based on the specified index. func (c *Client) GetBlockHash(index uint32) (util.Uint256, error) { var ( - params = request.NewRawParams(index) + params = []interface{}{index} resp = util.Uint256{} ) if err := c.performRequest("getblockhash", params, &resp); err != nil { @@ -160,7 +161,7 @@ func (c *Client) GetBlockHash(index uint32) (util.Uint256, error) { // with Init before calling GetBlockHeader. func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) { var ( - params = request.NewRawParams(hash.StringLE()) + params = []interface{}{hash.StringLE()} resp []byte h *block.Header ) @@ -184,7 +185,7 @@ func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) { // GetBlockHeaderCount returns the number of headers in the main chain. func (c *Client) GetBlockHeaderCount() (uint32, error) { var resp uint32 - if err := c.performRequest("getblockheadercount", request.NewRawParams(), &resp); err != nil { + if err := c.performRequest("getblockheadercount", nil, &resp); err != nil { return resp, err } return resp, nil @@ -194,7 +195,7 @@ func (c *Client) GetBlockHeaderCount() (uint32, error) { // according to the specified script hash. func (c *Client) GetBlockHeaderVerbose(hash util.Uint256) (*result.Header, error) { var ( - params = request.NewRawParams(hash.StringLE(), 1) + params = []interface{}{hash.StringLE(), 1} resp = &result.Header{} ) if err := c.performRequest("getblockheader", params, resp); err != nil { @@ -206,7 +207,7 @@ func (c *Client) GetBlockHeaderVerbose(hash util.Uint256) (*result.Header, error // GetBlockSysFee returns the system fees of the block based on the specified index. func (c *Client) GetBlockSysFee(index uint32) (fixedn.Fixed8, error) { var ( - params = request.NewRawParams(index) + params = []interface{}{index} resp fixedn.Fixed8 ) if err := c.performRequest("getblocksysfee", params, &resp); err != nil { @@ -217,11 +218,9 @@ func (c *Client) GetBlockSysFee(index uint32) (fixedn.Fixed8, error) { // GetConnectionCount returns the current number of the connections for the node. func (c *Client) GetConnectionCount() (int, error) { - var ( - params = request.NewRawParams() - resp int - ) - if err := c.performRequest("getconnectioncount", params, &resp); err != nil { + var resp int + + if err := c.performRequest("getconnectioncount", nil, &resp); err != nil { return resp, err } return resp, nil @@ -229,11 +228,9 @@ func (c *Client) GetConnectionCount() (int, error) { // GetCommittee returns the current public keys of NEO nodes in the committee. func (c *Client) GetCommittee() (keys.PublicKeys, error) { - var ( - params = request.NewRawParams() - resp = new(keys.PublicKeys) - ) - if err := c.performRequest("getcommittee", params, resp); err != nil { + var resp = new(keys.PublicKeys) + + if err := c.performRequest("getcommittee", nil, resp); err != nil { return nil, err } return *resp, nil @@ -257,7 +254,7 @@ func (c *Client) GetContractStateByID(id int32) (*state.Contract, error) { // getContractState is an internal representation of GetContractStateBy* methods. func (c *Client) getContractState(param interface{}) (*state.Contract, error) { var ( - params = request.NewRawParams(param) + params = []interface{}{param} resp = &state.Contract{} ) if err := c.performRequest("getcontractstate", params, resp); err != nil { @@ -268,11 +265,8 @@ func (c *Client) getContractState(param interface{}) (*state.Contract, error) { // GetNativeContracts queries information about native contracts. func (c *Client) GetNativeContracts() ([]state.NativeContract, error) { - var ( - params = request.NewRawParams() - resp []state.NativeContract - ) - if err := c.performRequest("getnativecontracts", params, &resp); err != nil { + var resp []state.NativeContract + if err := c.performRequest("getnativecontracts", nil, &resp); err != nil { return resp, err } @@ -288,7 +282,7 @@ func (c *Client) GetNativeContracts() ([]state.NativeContract, error) { // GetNEP11Balances is a wrapper for getnep11balances RPC. func (c *Client) GetNEP11Balances(address util.Uint160) (*result.NEP11Balances, error) { - params := request.NewRawParams(address.StringLE()) + params := []interface{}{address.StringLE()} resp := new(result.NEP11Balances) if err := c.performRequest("getnep11balances", params, resp); err != nil { return nil, err @@ -298,7 +292,7 @@ func (c *Client) GetNEP11Balances(address util.Uint160) (*result.NEP11Balances, // GetNEP17Balances is a wrapper for getnep17balances RPC. func (c *Client) GetNEP17Balances(address util.Uint160) (*result.NEP17Balances, error) { - params := request.NewRawParams(address.StringLE()) + params := []interface{}{address.StringLE()} resp := new(result.NEP17Balances) if err := c.performRequest("getnep17balances", params, resp); err != nil { return nil, err @@ -312,7 +306,7 @@ func (c *Client) GetNEP17Balances(address util.Uint160) (*result.NEP17Balances, // attributes like "description", "image", "name" and "tokenURI" it returns strings, // while for all others []byte (which can be nil). func (c *Client) GetNEP11Properties(asset util.Uint160, token []byte) (map[string]interface{}, error) { - params := request.NewRawParams(asset.StringLE(), hex.EncodeToString(token)) + params := []interface{}{asset.StringLE(), hex.EncodeToString(token)} resp := make(map[string]interface{}) if err := c.performRequest("getnep11properties", params, &resp); err != nil { return nil, err @@ -346,22 +340,22 @@ func (c *Client) GetNEP11Transfers(address util.Uint160, start, stop *uint64, li return nil, err } resp := new(result.NEP11Transfers) - if err := c.performRequest("getnep11transfers", *params, resp); err != nil { + if err := c.performRequest("getnep11transfers", params, resp); err != nil { return nil, err } return resp, nil } -func packTransfersParams(address util.Uint160, start, stop *uint64, limit, page *int) (*request.RawParams, error) { - params := request.NewRawParams(address.StringLE()) +func packTransfersParams(address util.Uint160, start, stop *uint64, limit, page *int) ([]interface{}, error) { + params := []interface{}{address.StringLE()} if start != nil { - params.Values = append(params.Values, *start) + params = append(params, *start) if stop != nil { - params.Values = append(params.Values, *stop) + params = append(params, *stop) if limit != nil { - params.Values = append(params.Values, *limit) + params = append(params, *limit) if page != nil { - params.Values = append(params.Values, *page) + params = append(params, *page) } } else if page != nil { return nil, errors.New("bad parameters") @@ -372,7 +366,7 @@ func packTransfersParams(address util.Uint160, start, stop *uint64, limit, page } else if stop != nil || limit != nil || page != nil { return nil, errors.New("bad parameters") } - return ¶ms, nil + return params, nil } // GetNEP17Transfers is a wrapper for getnep17transfers RPC. Address parameter @@ -386,7 +380,7 @@ func (c *Client) GetNEP17Transfers(address util.Uint160, start, stop *uint64, li return nil, err } resp := new(result.NEP17Transfers) - if err := c.performRequest("getnep17transfers", *params, resp); err != nil { + if err := c.performRequest("getnep17transfers", params, resp); err != nil { return nil, err } return resp, nil @@ -394,11 +388,9 @@ func (c *Client) GetNEP17Transfers(address util.Uint160, start, stop *uint64, li // GetPeers returns a list of the nodes that the node is currently connected to/disconnected from. func (c *Client) GetPeers() (*result.GetPeers, error) { - var ( - params = request.NewRawParams() - resp = &result.GetPeers{} - ) - if err := c.performRequest("getpeers", params, resp); err != nil { + var resp = &result.GetPeers{} + + if err := c.performRequest("getpeers", nil, resp); err != nil { return resp, err } return resp, nil @@ -406,11 +398,9 @@ func (c *Client) GetPeers() (*result.GetPeers, error) { // GetRawMemPool returns a list of unconfirmed transactions in the memory. func (c *Client) GetRawMemPool() ([]util.Uint256, error) { - var ( - params = request.NewRawParams() - resp = new([]util.Uint256) - ) - if err := c.performRequest("getrawmempool", params, resp); err != nil { + var resp = new([]util.Uint256) + + if err := c.performRequest("getrawmempool", nil, resp); err != nil { return *resp, err } return *resp, nil @@ -419,7 +409,7 @@ func (c *Client) GetRawMemPool() ([]util.Uint256, error) { // GetRawTransaction returns a transaction by hash. func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, error) { var ( - params = request.NewRawParams(hash.StringLE()) + params = []interface{}{hash.StringLE()} resp []byte err error ) @@ -438,7 +428,7 @@ func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, // NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively. func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.TransactionOutputRaw, error) { var ( - params = request.NewRawParams(hash.StringLE(), 1) + params = []interface{}{hash.StringLE(), 1} // 1 for verbose. resp = &result.TransactionOutputRaw{} err error ) @@ -452,7 +442,7 @@ func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.Transactio // historical contract hash and historical item key. func (c *Client) GetState(stateroot util.Uint256, historicalContractHash util.Uint160, historicalKey []byte) ([]byte, error) { var ( - params = request.NewRawParams(stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey) + params = []interface{}{stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey} resp []byte ) if err := c.performRequest("getstate", params, &resp); err != nil { @@ -471,17 +461,17 @@ func (c *Client) FindStates(stateroot util.Uint256, historicalContractHash util. historicalPrefix = []byte{} } var ( - params = request.NewRawParams(stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix) + params = []interface{}{stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix} resp result.FindStates ) if start == nil && maxCount != nil { start = []byte{} } if start != nil { - params.Values = append(params.Values, start) + params = append(params, start) } if maxCount != nil { - params.Values = append(params.Values, *maxCount) + params = append(params, *maxCount) } if err := c.performRequest("findstates", params, &resp); err != nil { return resp, err @@ -491,17 +481,17 @@ func (c *Client) FindStates(stateroot util.Uint256, historicalContractHash util. // GetStateRootByHeight returns the state root for the specified height. func (c *Client) GetStateRootByHeight(height uint32) (*state.MPTRoot, error) { - return c.getStateRoot(request.NewRawParams(height)) + return c.getStateRoot(height) } // GetStateRootByBlockHash returns the state root for the block with the specified hash. func (c *Client) GetStateRootByBlockHash(hash util.Uint256) (*state.MPTRoot, error) { - return c.getStateRoot(request.NewRawParams(hash)) + return c.getStateRoot(hash) } -func (c *Client) getStateRoot(params request.RawParams) (*state.MPTRoot, error) { +func (c *Client) getStateRoot(param interface{}) (*state.MPTRoot, error) { var resp = new(state.MPTRoot) - if err := c.performRequest("getstateroot", params, resp); err != nil { + if err := c.performRequest("getstateroot", []interface{}{param}, resp); err != nil { return nil, err } return resp, nil @@ -509,11 +499,9 @@ func (c *Client) getStateRoot(params request.RawParams) (*state.MPTRoot, error) // GetStateHeight returns the current validated and local node state height. func (c *Client) GetStateHeight() (*result.StateHeight, error) { - var ( - params = request.NewRawParams() - resp = new(result.StateHeight) - ) - if err := c.performRequest("getstateheight", params, resp); err != nil { + var resp = new(result.StateHeight) + + if err := c.performRequest("getstateheight", nil, resp); err != nil { return nil, err } return resp, nil @@ -521,15 +509,15 @@ func (c *Client) GetStateHeight() (*result.StateHeight, error) { // GetStorageByID returns the stored value according to the contract ID and the stored key. func (c *Client) GetStorageByID(id int32, key []byte) ([]byte, error) { - return c.getStorage(request.NewRawParams(id, key)) + return c.getStorage([]interface{}{id, key}) } // GetStorageByHash returns the stored value according to the contract script hash and the stored key. func (c *Client) GetStorageByHash(hash util.Uint160, key []byte) ([]byte, error) { - return c.getStorage(request.NewRawParams(hash.StringLE(), key)) + return c.getStorage([]interface{}{hash.StringLE(), key}) } -func (c *Client) getStorage(params request.RawParams) ([]byte, error) { +func (c *Client) getStorage(params []interface{}) ([]byte, error) { var resp []byte if err := c.performRequest("getstorage", params, &resp); err != nil { return nil, err @@ -540,7 +528,7 @@ func (c *Client) getStorage(params request.RawParams) ([]byte, error) { // GetTransactionHeight returns the block index where the transaction is found. func (c *Client) GetTransactionHeight(hash util.Uint256) (uint32, error) { var ( - params = request.NewRawParams(hash.StringLE()) + params = []interface{}{hash.StringLE()} resp uint32 ) if err := c.performRequest("gettransactionheight", params, &resp); err != nil { @@ -552,7 +540,7 @@ func (c *Client) GetTransactionHeight(hash util.Uint256) (uint32, error) { // GetUnclaimedGas returns the unclaimed GAS amount for the specified address. func (c *Client) GetUnclaimedGas(address string) (result.UnclaimedGas, error) { var ( - params = request.NewRawParams(address) + params = []interface{}{address} resp result.UnclaimedGas ) if err := c.performRequest("getunclaimedgas", params, &resp); err != nil { @@ -564,11 +552,9 @@ func (c *Client) GetUnclaimedGas(address string) (result.UnclaimedGas, error) { // GetCandidates returns the current list of NEO candidate node with voting data and // validator status. func (c *Client) GetCandidates() ([]result.Candidate, error) { - var ( - params = request.NewRawParams() - resp = new([]result.Candidate) - ) - if err := c.performRequest("getcandidates", params, resp); err != nil { + var resp = new([]result.Candidate) + + if err := c.performRequest("getcandidates", nil, resp); err != nil { return nil, err } return *resp, nil @@ -576,11 +562,9 @@ func (c *Client) GetCandidates() ([]result.Candidate, error) { // GetNextBlockValidators returns the current NEO consensus nodes information and voting data. func (c *Client) GetNextBlockValidators() ([]result.Validator, error) { - var ( - params = request.NewRawParams() - resp = new([]result.Validator) - ) - if err := c.performRequest("getnextblockvalidators", params, resp); err != nil { + var resp = new([]result.Validator) + + if err := c.performRequest("getnextblockvalidators", nil, resp); err != nil { return nil, err } return *resp, nil @@ -588,11 +572,9 @@ func (c *Client) GetNextBlockValidators() ([]result.Validator, error) { // GetVersion returns the version information about the queried node. func (c *Client) GetVersion() (*result.Version, error) { - var ( - params = request.NewRawParams() - resp = &result.Version{} - ) - if err := c.performRequest("getversion", params, resp); err != nil { + var resp = &result.Version{} + + if err := c.performRequest("getversion", nil, resp); err != nil { return nil, err } return resp, nil @@ -601,7 +583,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(script) + var p = []interface{}{script} return c.invokeSomething("invokescript", p, signers) } @@ -610,7 +592,7 @@ func (c *Client) InvokeScript(script []byte, signers []transaction.Signer) (*res // height. // NOTE: This is a test invoke and will not affect the blockchain. func (c *Client) InvokeScriptAtHeight(height uint32, script []byte, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(height, script) + var p = []interface{}{height, script} return c.invokeSomething("invokescripthistoric", p, signers) } @@ -619,7 +601,7 @@ func (c *Client) InvokeScriptAtHeight(height uint32, script []byte, signers []tr // hash. // NOTE: This is a test invoke and will not affect the blockchain. func (c *Client) InvokeScriptAtBlock(blockHash util.Uint256, script []byte, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(blockHash.StringLE(), script) + var p = []interface{}{blockHash.StringLE(), script} return c.invokeSomething("invokescripthistoric", p, signers) } @@ -628,7 +610,7 @@ func (c *Client) InvokeScriptAtBlock(blockHash util.Uint256, script []byte, sign // stateroot hash. // NOTE: This is a test invoke and will not affect the blockchain. func (c *Client) InvokeScriptWithState(stateroot util.Uint256, script []byte, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(stateroot.StringLE(), script) + var p = []interface{}{stateroot.StringLE(), script} return c.invokeSomething("invokescripthistoric", p, signers) } @@ -636,7 +618,7 @@ func (c *Client) InvokeScriptWithState(stateroot util.Uint256, script []byte, si // with the given operation and parameters. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(contract.StringLE(), operation, params) + var p = []interface{}{contract.StringLE(), operation, params} return c.invokeSomething("invokefunction", p, signers) } @@ -645,7 +627,7 @@ func (c *Client) InvokeFunction(contract util.Uint160, operation string, params // specified by the blockchain height. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeFunctionAtHeight(height uint32, contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(height, contract.StringLE(), operation, params) + var p = []interface{}{height, contract.StringLE(), operation, params} return c.invokeSomething("invokefunctionhistoric", p, signers) } @@ -654,7 +636,7 @@ func (c *Client) InvokeFunctionAtHeight(height uint32, contract util.Uint160, op // specified by the block hash. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeFunctionAtBlock(blockHash util.Uint256, contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(blockHash.StringLE(), contract.StringLE(), operation, params) + var p = []interface{}{blockHash.StringLE(), contract.StringLE(), operation, params} return c.invokeSomething("invokefunctionhistoric", p, signers) } @@ -663,7 +645,7 @@ func (c *Client) InvokeFunctionAtBlock(blockHash util.Uint256, contract util.Uin // by the specified stateroot hash. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeFunctionWithState(stateroot util.Uint256, contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { - var p = request.NewRawParams(stateroot.StringLE(), contract.StringLE(), operation, params) + var p = []interface{}{stateroot.StringLE(), contract.StringLE(), operation, params} return c.invokeSomething("invokefunctionhistoric", p, signers) } @@ -671,7 +653,7 @@ func (c *Client) InvokeFunctionWithState(stateroot util.Uint256, contract util.U // with the given parameters under verification trigger type. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeContractVerify(contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { - var p = request.NewRawParams(contract.StringLE(), params) + var p = []interface{}{contract.StringLE(), params} return c.invokeSomething("invokecontractverify", p, signers, witnesses...) } @@ -680,7 +662,7 @@ func (c *Client) InvokeContractVerify(contract util.Uint160, params []smartcontr // at the blockchain state specified by the blockchain height. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeContractVerifyAtHeight(height uint32, contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { - var p = request.NewRawParams(height, contract.StringLE(), params) + var p = []interface{}{height, contract.StringLE(), params} return c.invokeSomething("invokecontractverifyhistoric", p, signers, witnesses...) } @@ -689,7 +671,7 @@ func (c *Client) InvokeContractVerifyAtHeight(height uint32, contract util.Uint1 // at the blockchain state specified by the block hash. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeContractVerifyAtBlock(blockHash util.Uint256, contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { - var p = request.NewRawParams(blockHash.StringLE(), contract.StringLE(), params) + var p = []interface{}{blockHash.StringLE(), contract.StringLE(), params} return c.invokeSomething("invokecontractverifyhistoric", p, signers, witnesses...) } @@ -698,16 +680,16 @@ func (c *Client) InvokeContractVerifyAtBlock(blockHash util.Uint256, contract ut // at the blockchain state specified by the stateroot hash. // NOTE: this is test invoke and will not affect the blockchain. func (c *Client) InvokeContractVerifyWithState(stateroot util.Uint256, contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { - var p = request.NewRawParams(stateroot.StringLE(), contract.StringLE(), params) + var p = []interface{}{stateroot.StringLE(), contract.StringLE(), params} return c.invokeSomething("invokecontractverifyhistoric", p, signers, witnesses...) } // invokeSomething is an inner wrapper for Invoke* functions. -func (c *Client) invokeSomething(method string, p request.RawParams, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { +func (c *Client) invokeSomething(method string, p []interface{}, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { var resp = new(result.Invoke) if signers != nil { if witnesses == nil { - p.Values = append(p.Values, signers) + p = append(p, signers) } else { if len(witnesses) != len(signers) { return nil, fmt.Errorf("number of witnesses should match number of signers, got %d vs %d", len(witnesses), len(signers)) @@ -719,7 +701,7 @@ func (c *Client) invokeSomething(method string, p request.RawParams, signers []t Witness: witnesses[i], } } - p.Values = append(p.Values, signersWithWitnesses) + p = append(p, signersWithWitnesses) } } if err := c.performRequest(method, p, resp); err != nil { @@ -734,7 +716,7 @@ func (c *Client) invokeSomething(method string, p request.RawParams, signers []t // been broadcasted to the network. func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) (util.Uint256, error) { var ( - params = request.NewRawParams(rawTX.Bytes()) + params = []interface{}{rawTX.Bytes()} resp = new(result.RelayResult) ) if err := c.performRequest("sendrawtransaction", params, resp); err != nil { @@ -746,7 +728,7 @@ func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) (util.Uint25 // SubmitBlock broadcasts a raw block over the NEO network. func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) { var ( - params request.RawParams + params []interface{} resp = new(result.RelayResult) ) buf := io.NewBufBinWriter() @@ -754,7 +736,7 @@ func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) { if err := buf.Err; err != nil { return util.Uint256{}, err } - params = request.NewRawParams(buf.Bytes()) + params = []interface{}{buf.Bytes()} if err := c.performRequest("submitblock", params, resp); err != nil { return util.Uint256{}, err @@ -764,7 +746,7 @@ func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) { // SubmitRawOracleResponse submits a raw oracle response to the oracle node. // Raw params are used to avoid excessive marshalling. -func (c *Client) SubmitRawOracleResponse(ps request.RawParams) error { +func (c *Client) SubmitRawOracleResponse(ps []interface{}) error { return c.performRequest("submitoracleresponse", ps, new(result.RelayResult)) } @@ -997,7 +979,7 @@ func (c *Client) SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uin if err != nil { return util.Uint256{}, fmt.Errorf("failed to encode request: %w", err) } - params := request.NewRawParams(bytes) + params := []interface{}{bytes} if err := c.performRequest("submitnotaryrequest", params, resp); err != nil { return util.Uint256{}, err } @@ -1007,7 +989,7 @@ func (c *Client) SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uin // ValidateAddress verifies that the address is a correct NEO address. func (c *Client) ValidateAddress(address string) error { var ( - params = request.NewRawParams(address) + params = []interface{}{address} resp = &result.ValidateAddress{} ) @@ -1161,7 +1143,7 @@ func (c *Client) TraverseIterator(sessionID, iteratorID uuid.UUID, maxItemsCount maxItemsCount = config.DefaultMaxIteratorResultItems } var ( - params = request.NewRawParams(sessionID.String(), iteratorID.String(), maxItemsCount) + params = []interface{}{sessionID.String(), iteratorID.String(), maxItemsCount} resp []json.RawMessage ) if err := c.performRequest("traverseiterator", params, &resp); err != nil { @@ -1183,7 +1165,7 @@ func (c *Client) TraverseIterator(sessionID, iteratorID uuid.UUID, maxItemsCount // the specified session was found on server. func (c *Client) TerminateSession(sessionID uuid.UUID) (bool, error) { var resp bool - params := request.NewRawParams(sessionID.String()) + params := []interface{}{sessionID.String()} if err := c.performRequest("terminatesession", params, &resp); err != nil { return false, err } diff --git a/pkg/rpc/client/wsclient.go b/pkg/rpc/client/wsclient.go index adcfdede8..d98c5093b 100644 --- a/pkg/rpc/client/wsclient.go +++ b/pkg/rpc/client/wsclient.go @@ -315,7 +315,7 @@ func (c *WSClient) makeWsRequest(r *request.Raw) (*response.Raw, error) { } } -func (c *WSClient) performSubscription(params request.RawParams) (string, error) { +func (c *WSClient) performSubscription(params []interface{}) (string, error) { var resp string if err := c.performRequest("subscribe", params, &resp); err != nil { @@ -338,7 +338,7 @@ func (c *WSClient) performUnsubscription(id string) error { if !c.subscriptions[id] { return errors.New("no subscription with this ID") } - if err := c.performRequest("unsubscribe", request.NewRawParams(id), &resp); err != nil { + if err := c.performRequest("unsubscribe", []interface{}{id}, &resp); err != nil { return err } if !resp { @@ -352,9 +352,9 @@ func (c *WSClient) performUnsubscription(id string) error { // of the client. It can be filtered by primary consensus node index, nil value doesn't // add any filters. func (c *WSClient) SubscribeForNewBlocks(primary *int) (string, error) { - params := request.NewRawParams("block_added") + params := []interface{}{"block_added"} if primary != nil { - params.Values = append(params.Values, request.BlockFilter{Primary: *primary}) + params = append(params, request.BlockFilter{Primary: *primary}) } return c.performSubscription(params) } @@ -363,9 +363,9 @@ func (c *WSClient) SubscribeForNewBlocks(primary *int) (string, error) { // this instance of the client. It can be filtered by the sender and/or the signer, nil // value is treated as missing filter. func (c *WSClient) SubscribeForNewTransactions(sender *util.Uint160, signer *util.Uint160) (string, error) { - params := request.NewRawParams("transaction_added") + params := []interface{}{"transaction_added"} if sender != nil || signer != nil { - params.Values = append(params.Values, request.TxFilter{Sender: sender, Signer: signer}) + params = append(params, request.TxFilter{Sender: sender, Signer: signer}) } return c.performSubscription(params) } @@ -375,9 +375,9 @@ func (c *WSClient) SubscribeForNewTransactions(sender *util.Uint160, signer *uti // filtered by the contract's hash (that emits notifications), nil value puts no such // restrictions. func (c *WSClient) SubscribeForExecutionNotifications(contract *util.Uint160, name *string) (string, error) { - params := request.NewRawParams("notification_from_execution") + params := []interface{}{"notification_from_execution"} if contract != nil || name != nil { - params.Values = append(params.Values, request.NotificationFilter{Contract: contract, Name: name}) + params = append(params, request.NotificationFilter{Contract: contract, Name: name}) } return c.performSubscription(params) } @@ -387,12 +387,12 @@ func (c *WSClient) SubscribeForExecutionNotifications(contract *util.Uint160, na // be filtered by state (HALT/FAULT) to check for successful or failing // transactions, nil value means no filtering. func (c *WSClient) SubscribeForTransactionExecutions(state *string) (string, error) { - params := request.NewRawParams("transaction_executed") + params := []interface{}{"transaction_executed"} if state != nil { if *state != "HALT" && *state != "FAULT" { return "", errors.New("bad state parameter") } - params.Values = append(params.Values, request.ExecutionFilter{State: *state}) + params = append(params, request.ExecutionFilter{State: *state}) } return c.performSubscription(params) } @@ -402,9 +402,9 @@ func (c *WSClient) SubscribeForTransactionExecutions(state *string) (string, err // request sender's hash, or main tx signer's hash, nil value puts no such // restrictions. func (c *WSClient) SubscribeForNotaryRequests(sender *util.Uint160, mainSigner *util.Uint160) (string, error) { - params := request.NewRawParams("notary_request_event") + params := []interface{}{"notary_request_event"} if sender != nil { - params.Values = append(params.Values, request.TxFilter{Sender: sender, Signer: mainSigner}) + params = append(params, request.TxFilter{Sender: sender, Signer: mainSigner}) } return c.performSubscription(params) } @@ -421,7 +421,7 @@ func (c *WSClient) UnsubscribeAll() error { for id := range c.subscriptions { var resp bool - if err := c.performRequest("unsubscribe", request.NewRawParams(id), &resp); err != nil { + if err := c.performRequest("unsubscribe", []interface{}{id}, &resp); err != nil { return err } if !resp { diff --git a/pkg/rpc/request/types.go b/pkg/rpc/request/types.go index 866f91926..1da9a5f70 100644 --- a/pkg/rpc/request/types.go +++ b/pkg/rpc/request/types.go @@ -16,22 +16,6 @@ const ( JSONRPCVersion = "2.0" ) -// RawParams is just a slice of abstract values, used to represent parameters -// passed from the client to the server. -type RawParams struct { - Values []interface{} -} - -// NewRawParams creates RawParams from its parameters. -func NewRawParams(vals ...interface{}) RawParams { - p := RawParams{} - p.Values = make([]interface{}, len(vals)) - for i := 0; i < len(p.Values); i++ { - p.Values[i] = vals[i] - } - return p -} - type ( // Raw represents JSON-RPC request. It's generic enough to be used in many // generic JSON-RPC communication scenarios, yet at the same time it's diff --git a/pkg/services/helpers/rpcbroadcaster/broadcaster.go b/pkg/services/helpers/rpcbroadcaster/broadcaster.go index 7b6620b2a..2738f3b47 100644 --- a/pkg/services/helpers/rpcbroadcaster/broadcaster.go +++ b/pkg/services/helpers/rpcbroadcaster/broadcaster.go @@ -3,7 +3,6 @@ package rpcbroadcaster import ( "time" - "github.com/nspcc-dev/neo-go/pkg/rpc/request" "go.uber.org/zap" ) @@ -11,7 +10,7 @@ import ( type RPCBroadcaster struct { Clients map[string]*RPCClient Log *zap.Logger - Responses chan request.RawParams + Responses chan []interface{} close chan struct{} finished chan struct{} @@ -25,7 +24,7 @@ func NewRPCBroadcaster(log *zap.Logger, sendTimeout time.Duration) *RPCBroadcast Log: log, close: make(chan struct{}), finished: make(chan struct{}), - Responses: make(chan request.RawParams), + Responses: make(chan []interface{}), sendTimeout: sendTimeout, } } @@ -66,7 +65,7 @@ drain: } // SendParams sends a request using all clients if the broadcaster is active. -func (r *RPCBroadcaster) SendParams(params request.RawParams) { +func (r *RPCBroadcaster) SendParams(params []interface{}) { select { case <-r.close: case r.Responses <- params: diff --git a/pkg/services/helpers/rpcbroadcaster/client.go b/pkg/services/helpers/rpcbroadcaster/client.go index 33696084f..ca45d7135 100644 --- a/pkg/services/helpers/rpcbroadcaster/client.go +++ b/pkg/services/helpers/rpcbroadcaster/client.go @@ -5,7 +5,6 @@ import ( "time" "github.com/nspcc-dev/neo-go/pkg/rpc/client" - "github.com/nspcc-dev/neo-go/pkg/rpc/request" "go.uber.org/zap" ) @@ -15,17 +14,17 @@ type RPCClient struct { addr string close chan struct{} finished chan struct{} - responses chan request.RawParams + responses chan []interface{} log *zap.Logger sendTimeout time.Duration method SendMethod } // SendMethod represents an rpc method for sending data to other nodes. -type SendMethod func(*client.Client, request.RawParams) error +type SendMethod func(*client.Client, []interface{}) error // NewRPCClient returns a new rpc client for the provided address and method. -func (r *RPCBroadcaster) NewRPCClient(addr string, method SendMethod, timeout time.Duration, ch chan request.RawParams) *RPCClient { +func (r *RPCBroadcaster) NewRPCClient(addr string, method SendMethod, timeout time.Duration, ch chan []interface{}) *RPCClient { return &RPCClient{ addr: addr, close: r.close, diff --git a/pkg/services/oracle/broadcaster/oracle.go b/pkg/services/oracle/broadcaster/oracle.go index 8a8d4c328..9fc2627e2 100644 --- a/pkg/services/oracle/broadcaster/oracle.go +++ b/pkg/services/oracle/broadcaster/oracle.go @@ -9,7 +9,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/rpc/client" - "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/services/helpers/rpcbroadcaster" "github.com/nspcc-dev/neo-go/pkg/services/oracle" "go.uber.org/zap" @@ -35,7 +34,7 @@ func New(cfg config.OracleConfiguration, log *zap.Logger) oracle.Broadcaster { } for i := range cfg.Nodes { r.Clients[cfg.Nodes[i]] = r.NewRPCClient(cfg.Nodes[i], (*client.Client).SubmitRawOracleResponse, - cfg.ResponseTimeout, make(chan request.RawParams, defaultChanCapacity)) + cfg.ResponseTimeout, make(chan []interface{}, defaultChanCapacity)) } return r } @@ -45,12 +44,12 @@ func (r *oracleBroadcaster) SendResponse(priv *keys.PrivateKey, resp *transactio pub := priv.PublicKey() data := GetMessage(pub.Bytes(), resp.ID, txSig) msgSig := priv.Sign(data) - params := request.NewRawParams( + params := []interface{}{ base64.StdEncoding.EncodeToString(pub.Bytes()), resp.ID, base64.StdEncoding.EncodeToString(txSig), base64.StdEncoding.EncodeToString(msgSig), - ) + } r.SendParams(params) }