From 51c486864157e321c6646b2caecded17dbb25644 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 26 Feb 2020 15:42:04 +0300 Subject: [PATCH] rpc: implement getclaimable RPC --- pkg/rpc/response/result/claimable.go | 22 ++++++++++++ pkg/rpc/server/prometheus.go | 8 +++++ pkg/rpc/server/server.go | 50 ++++++++++++++++++++++++++++ pkg/rpc/server/server_test.go | 34 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 pkg/rpc/response/result/claimable.go diff --git a/pkg/rpc/response/result/claimable.go b/pkg/rpc/response/result/claimable.go new file mode 100644 index 000000000..d537a5891 --- /dev/null +++ b/pkg/rpc/response/result/claimable.go @@ -0,0 +1,22 @@ +package result + +import "github.com/CityOfZion/neo-go/pkg/util" + +// ClaimableInfo is a result of a getclaimable RPC call. +type ClaimableInfo struct { + Spents []Claimable `json:"claimable"` + Address string `json:"address"` + Unclaimed util.Fixed8 `json:"unclaimed"` +} + +// Claimable represents spent outputs which can be claimed. +type Claimable struct { + Tx util.Uint256 `json:"txid"` + N int `json:"n"` + Value util.Fixed8 `json:"value"` + StartHeight uint32 `json:"start_height"` + EndHeight uint32 `json:"end_height"` + Generated util.Fixed8 `json:"generated"` + SysFee util.Fixed8 `json:"sys_fee"` + Unclaimed util.Fixed8 `json:"unclaimed"` +} diff --git a/pkg/rpc/server/prometheus.go b/pkg/rpc/server/prometheus.go index 2d095a322..00e7c313f 100644 --- a/pkg/rpc/server/prometheus.go +++ b/pkg/rpc/server/prometheus.go @@ -51,6 +51,14 @@ var ( }, ) + getclaimableCalled = prometheus.NewCounter( + prometheus.CounterOpts{ + Help: "Number of calls to getclaimable rpc endpoint", + Name: "getclaimable_called", + Namespace: "neogo", + }, + ) + getconnectioncountCalled = prometheus.NewCounter( prometheus.CounterOpts{ Help: "Number of calls to getconnectioncount rpc endpoint", diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index ebee6d090..2c055e5bf 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -190,6 +190,10 @@ Methods: getblocksysfeeCalled.Inc() results, resultsErr = s.getBlockSysFee(reqParams) + case "getclaimable": + getclaimableCalled.Inc() + results, resultsErr = s.getClaimable(reqParams) + case "getconnectioncount": getconnectioncountCalled.Inc() results = s.coreServer.PeerCount() @@ -322,6 +326,52 @@ func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, error return result.NewApplicationLog(appExecResult, scriptHash), nil } +func (s *Server) getClaimable(ps request.Params) (interface{}, error) { + p, ok := ps.ValueWithType(0, request.StringT) + if !ok { + return nil, response.ErrInvalidParams + } + u, err := p.GetUint160FromAddress() + if err != nil { + return nil, response.ErrInvalidParams + } + + var unclaimed []state.UnclaimedBalance + if acc := s.chain.GetAccountState(u); acc != nil { + unclaimed = acc.Unclaimed + } + + var sum util.Fixed8 + claimable := make([]result.Claimable, 0, len(unclaimed)) + for _, ub := range unclaimed { + gen, sys, err := s.chain.CalculateClaimable(ub.Value, ub.Start, ub.End) + if err != nil { + s.log.Info("error while calculating claim bonus", zap.Error(err)) + continue + } + + uc := gen.Add(sys) + sum += uc + + claimable = append(claimable, result.Claimable{ + Tx: ub.Tx, + N: int(ub.Index), + Value: ub.Value, + StartHeight: ub.Start, + EndHeight: ub.End, + Generated: gen, + SysFee: sys, + Unclaimed: uc, + }) + } + + return result.ClaimableInfo{ + Spents: claimable, + Address: p.String(), + Unclaimed: sum, + }, 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 e1b49b123..d7a8d9b3c 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -363,6 +363,40 @@ var rpcTestCases = map[string][]rpcTestCase{ fail: true, }, }, + "getclaimable": { + { + name: "no params", + params: "[]", + fail: true, + }, + { + name: "invalid address", + params: `["invalid"]`, + fail: true, + }, + { + name: "normal address", + params: `["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]`, + result: func(*executor) interface{} { + // hash of the issueTx + h, _ := util.Uint256DecodeStringBE("6da730b566db183bfceb863b780cd92dee2b497e5a023c322c1eaca81cf9ad7a") + amount := util.Fixed8FromInt64(52 * 8) // (endHeight - startHeight) * genAmount[0] + return &result.ClaimableInfo{ + Spents: []result.Claimable{ + { + Tx: h, + Value: util.Fixed8FromInt64(100000000), + EndHeight: 52, + Generated: amount, + Unclaimed: amount, + }, + }, + Address: "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", + Unclaimed: amount, + } + }, + }, + }, "getconnectioncount": { { params: "[]",