From 2757882d263f5084e9870163310133870c9164b9 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 5 Mar 2020 14:50:06 +0300 Subject: [PATCH] rpc: implement getnep5balances RPC --- docs/rpc.md | 2 +- pkg/rpc/client/doc.go | 2 +- pkg/rpc/client/rpc.go | 10 ++++++++++ pkg/rpc/response/result/nep5.go | 16 ++++++++++++++++ pkg/rpc/server/prometheus.go | 8 ++++++++ pkg/rpc/server/server.go | 29 +++++++++++++++++++++++++++++ pkg/rpc/server/server_test.go | 29 ++++++++++++++++++++++++++++- 7 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 pkg/rpc/response/result/nep5.go diff --git a/docs/rpc.md b/docs/rpc.md index 6781a18f1..910464833 100644 --- a/docs/rpc.md +++ b/docs/rpc.md @@ -47,7 +47,7 @@ which would yield the response: | `getclaimable` | Yes | | `getconnectioncount` | Yes | | `getcontractstate` | Yes | -| `getnep5balances` | No (#498) | +| `getnep5balances` | Yes | | `getnep5transfers` | No (#498) | | `getpeers` | Yes | | `getrawmempool` | Yes | diff --git a/pkg/rpc/client/doc.go b/pkg/rpc/client/doc.go index 1df4f0682..03e85379f 100644 --- a/pkg/rpc/client/doc.go +++ b/pkg/rpc/client/doc.go @@ -21,6 +21,7 @@ Supported methods getaccountstate getblock getclaimable + getnep5balances getrawtransaction getunspents invoke @@ -43,7 +44,6 @@ Unsupported methods getconnectioncount getcontractstate getmetricblocktimestamp - getnep5balances getnep5transfers getnewaddress getpeers diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index beeef25cf..6d9b3f67f 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -93,6 +93,16 @@ func (c *Client) GetClaimable(address string) (*result.ClaimableInfo, error) { return resp, nil } +// GetNEP5Balances is a wrapper for getnep5balances RPC. +func (c *Client) GetNEP5Balances(address util.Uint160) (*result.NEP5Balances, error) { + params := request.NewRawParams(address.StringLE()) + resp := new(result.NEP5Balances) + if err := c.performRequest("getnep5balances", params, resp); err != nil { + return nil, err + } + return resp, nil +} + // GetRawTransaction returns a transaction by hash. func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, error) { var ( diff --git a/pkg/rpc/response/result/nep5.go b/pkg/rpc/response/result/nep5.go new file mode 100644 index 000000000..8a70b13b7 --- /dev/null +++ b/pkg/rpc/response/result/nep5.go @@ -0,0 +1,16 @@ +package result + +import "github.com/nspcc-dev/neo-go/pkg/util" + +// NEP5Balances is a result for the getnep5balances RPC call. +type NEP5Balances struct { + Balances []NEP5Balance `json:"balances"` + Address string `json:"address"` +} + +// NEP5Balance represents balance for the single token contract. +type NEP5Balance struct { + Asset util.Uint160 `json:"asset_hash"` + Amount string `json:"amount"` + LastUpdated uint32 `json:"last_updated_block"` +} diff --git a/pkg/rpc/server/prometheus.go b/pkg/rpc/server/prometheus.go index b406761ba..0907b0bc5 100644 --- a/pkg/rpc/server/prometheus.go +++ b/pkg/rpc/server/prometheus.go @@ -75,6 +75,14 @@ var ( }, ) + getnep5balancesCalled = prometheus.NewCounter( + prometheus.CounterOpts{ + Help: "Number of calls to getnep5balances rpc endpoint", + Name: "getnep5balances_called", + Namespace: "neogo", + }, + ) + getversionCalled = prometheus.NewCounter( prometheus.CounterOpts{ Help: "Number of calls to getversion rpc endpoint", diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 5a47cd7c6..37b7e4561 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -198,6 +198,10 @@ Methods: getconnectioncountCalled.Inc() results = s.coreServer.PeerCount() + case "getnep5balances": + getnep5balancesCalled.Inc() + results, resultsErr = s.getNEP5Balances(reqParams) + case "getversion": getversionCalled.Inc() results = result.Version{ @@ -381,6 +385,31 @@ func (s *Server) getClaimable(ps request.Params) (interface{}, error) { }, nil } +func (s *Server) getNEP5Balances(ps request.Params) (interface{}, error) { + p, ok := ps.ValueWithType(0, request.StringT) + if !ok { + return nil, response.ErrInvalidParams + } + u, err := p.GetUint160FromHex() + if err != nil { + return nil, response.ErrInvalidParams + } + + as := s.chain.GetAccountState(u) + bs := &result.NEP5Balances{Address: address.Uint160ToString(u)} + if as != nil { + for h, bal := range as.NEP5Balances { + amount := strconv.FormatInt(bal.Balance, 10) + bs.Balances = append(bs.Balances, result.NEP5Balance{ + Asset: h, + Amount: amount, + LastUpdated: bal.LastUpdatedBlock, + }) + } + } + return bs, nil +} + func (s *Server) getStorage(ps request.Params) (interface{}, error) { param, ok := ps.Value(0) if !ok { diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index ada0a8623..a2a77381c 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -51,7 +51,7 @@ var rpcTestCases = map[string][]rpcTestCase{ require.True(t, ok) - expectedTxHash, err := util.Uint256DecodeStringLE("cdb9fef85da4efde173682233b1a6166c9f39e8e41e40b75abb88230bf0c04bc") + expectedTxHash, err := util.Uint256DecodeStringLE("440b84d1580e36e84379416b58d9a3ad978cc557e54fd7ec6a2648329975b333") require.NoError(t, err) assert.Equal(t, expectedTxHash, res.TxHash) assert.Equal(t, 1, len(res.Executions)) @@ -143,6 +143,33 @@ var rpcTestCases = map[string][]rpcTestCase{ fail: true, }, }, + + "getnep5balances": { + { + name: "no params", + params: `[]`, + fail: true, + }, + { + name: "invalid address", + params: `["notahex"]`, + fail: true, + }, + { + name: "positive", + params: `["a90f00d94349a320376b7cb86c884b53ad76aa2b"]`, + result: func(e *executor) interface{} { return &result.NEP5Balances{} }, + check: func(t *testing.T, e *executor, acc interface{}) { + res, ok := acc.(*result.NEP5Balances) + require.True(t, ok) + require.Equal(t, "AKkkumHbBipZ46UMZJoFynJMXzSRnBvKcs", res.Address) + require.Equal(t, 1, len(res.Balances)) + require.Equal(t, "877", res.Balances[0].Amount) + require.Equal(t, "d864728bdbc88da799bc43862ae6aaa62adc3a87", res.Balances[0].Asset.StringLE()) + require.Equal(t, uint32(208), res.Balances[0].LastUpdated) + }, + }, + }, "getstorage": { { name: "positive",