Merge pull request #753 from nspcc-dev/refactoring/rpc

rpc: unify RPC handlers and metrics
This commit is contained in:
Roman Khimov 2020-03-25 15:33:12 +03:00 committed by GitHub
commit b52da3b928
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 188 additions and 450 deletions

View file

@ -1,249 +1,31 @@
package server package server
import "github.com/prometheus/client_golang/prometheus" import (
"fmt"
// Metrics used in monitoring service. "github.com/prometheus/client_golang/prometheus"
var (
getapplicationlogCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getapplicationlog rpc endpoint",
Name: "getapplicationlog_called",
Namespace: "neogo",
},
)
getbestblockhashCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getbestblockhash rpc endpoint",
Name: "getbestblockhash_called",
Namespace: "neogo",
},
)
getbestblockCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getbestblock rpc endpoint",
Name: "getbestblock_called",
Namespace: "neogo",
},
)
getblockcountCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getblockcount rpc endpoint",
Name: "getblockcount_called",
Namespace: "neogo",
},
)
getblockHashCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getblockhash rpc endpoint",
Name: "getblockhash_called",
Namespace: "neogo",
},
)
getblockheaderCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getblockheader rpc endpoint",
Name: "getblockheader_called",
Namespace: "neogo",
},
)
getblocksysfeeCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getblocksysfee rpc endpoint",
Name: "getblocksysfee_called",
Namespace: "neogo",
},
)
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",
Name: "getconnectioncount_called",
Namespace: "neogo",
},
)
getcontractstateCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getcontractstate rpc endpoint",
Name: "getcontractstate_called",
Namespace: "neogo",
},
)
getvalidatorsCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getvalidators rpc endpoint",
Name: "getvalidators_called",
Namespace: "neogo",
},
)
getnep5balancesCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getnep5balances rpc endpoint",
Name: "getnep5balances_called",
Namespace: "neogo",
},
)
getnep5transfersCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getnep5transfers rpc endpoint",
Name: "getnep5transfers_called",
Namespace: "neogo",
},
)
getversionCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getversion rpc endpoint",
Name: "getversion_called",
Namespace: "neogo",
},
)
getpeersCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getpeers rpc endpoint",
Name: "getpeers_called",
Namespace: "neogo",
},
)
getrawmempoolCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getrawmempool rpc endpoint",
Name: "getrawmempool_called",
Namespace: "neogo",
},
)
validateaddressCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to validateaddress rpc endpoint",
Name: "validateaddress_called",
Namespace: "neogo",
},
)
getassetstateCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getassetstate rpc endpoint",
Name: "getassetstate_called",
Namespace: "neogo",
},
)
getaccountstateCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getaccountstate rpc endpoint",
Name: "getaccountstate_called",
Namespace: "neogo",
},
)
gettransactionheightCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to gettransactionheight rpc endpoint",
Name: "gettransactionheight_called",
Namespace: "neogo",
},
)
gettxoutCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to gettxout rpc endpoint",
Name: "gettxout_called",
Namespace: "neogo",
},
)
getrawtransactionCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getrawtransaction rpc endpoint",
Name: "getrawtransaction_called",
Namespace: "neogo",
},
)
getunclaimedCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getunclaimed rpc endpoint",
Name: "getunclaimed_called",
Namespace: "neogo",
},
)
getunspentsCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getunspents rpc endpoint",
Name: "getunspents_called",
Namespace: "neogo",
},
)
sendrawtransactionCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to sendrawtransaction rpc endpoint",
Name: "sendrawtransaction_called",
Namespace: "neogo",
},
)
submitblockCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to submitblock rpc endpoint",
Name: "submitblock_called",
Namespace: "neogo",
},
)
getstorageCalled = prometheus.NewCounter(
prometheus.CounterOpts{
Help: "Number of calls to getstorage rpc endpoint",
Name: "getstorage_called",
Namespace: "neogo",
},
)
) )
func init() { // Metrics used in monitoring service.
prometheus.MustRegister( var rpcCounter = map[string]prometheus.Counter{}
getapplicationlogCalled,
getbestblockhashCalled, func incCounter(name string) {
getbestblockCalled, ctr, ok := rpcCounter[name]
getblockcountCalled, if ok {
getblockHashCalled, ctr.Inc()
getblockheaderCalled, }
getblocksysfeeCalled, }
getconnectioncountCalled,
getcontractstateCalled, func init() {
getvalidatorsCalled, for call := range rpcHandlers {
getversionCalled, ctr := prometheus.NewCounter(
getpeersCalled, prometheus.CounterOpts{
getrawmempoolCalled, Help: fmt.Sprintf("Number of calls to %s rpc endpoint", call),
validateaddressCalled, Name: fmt.Sprintf("%s_called", call),
getassetstateCalled, Namespace: "neogo",
getaccountstateCalled, },
getunclaimedCalled, )
getunspentsCalled, prometheus.MustRegister(ctr)
gettransactionheightCalled, rpcCounter[call] = ctr
gettxoutCalled, }
getrawtransactionCalled,
sendrawtransactionCalled,
submitblockCalled,
getstorageCalled,
)
} }

View file

@ -42,6 +42,39 @@ type (
} }
) )
var rpcHandlers = map[string]func(*Server, request.Params) (interface{}, error){
"getaccountstate": (*Server).getAccountState,
"getapplicationlog": (*Server).getApplicationLog,
"getassetstate": (*Server).getAssetState,
"getbestblockhash": (*Server).getBestBlockHash,
"getblock": (*Server).getBlock,
"getblockcount": (*Server).getBlockCount,
"getblockhash": (*Server).getBlockHash,
"getblockheader": (*Server).getBlockHeader,
"getblocksysfee": (*Server).getBlockSysFee,
"getclaimable": (*Server).getClaimable,
"getconnectioncount": (*Server).getConnectionCount,
"getcontractstate": (*Server).getContractState,
"getnep5balances": (*Server).getNEP5Balances,
"getnep5transfers": (*Server).getNEP5Transfers,
"getpeers": (*Server).getPeers,
"getrawmempool": (*Server).getRawMempool,
"getrawtransaction": (*Server).getrawtransaction,
"getstorage": (*Server).getStorage,
"gettransactionheight": (*Server).getTransactionHeight,
"gettxout": (*Server).getTxOut,
"getunclaimed": (*Server).getUnclaimed,
"getunspents": (*Server).getUnspents,
"getvalidators": (*Server).getValidators,
"getversion": (*Server).getVersion,
"invoke": (*Server).invoke,
"invokefunction": (*Server).invokeFunction,
"invokescript": (*Server).invokescript,
"sendrawtransaction": (*Server).sendrawtransaction,
"submitblock": (*Server).submitBlock,
"validateaddress": (*Server).validateAddress,
}
var invalidBlockHeightError = func(index int, height int) error { var invalidBlockHeightError = func(index int, height int) error {
return errors.Errorf("Param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height) return errors.Errorf("Param at index %d should be greater than or equal to 0 and less then or equal to current block height, got: %d", index, height)
} }
@ -153,211 +186,12 @@ func (s *Server) methodHandler(w http.ResponseWriter, req *request.In, reqParams
resultsErr error resultsErr error
) )
Methods: incCounter(req.Method)
switch req.Method {
case "getapplicationlog":
getapplicationlogCalled.Inc()
results, resultsErr = s.getApplicationLog(reqParams)
case "getbestblockhash": handler, ok := rpcHandlers[req.Method]
getbestblockhashCalled.Inc() if ok {
results = "0x" + s.chain.CurrentBlockHash().StringLE() results, resultsErr = handler(s, reqParams)
} else {
case "getblock":
getbestblockCalled.Inc()
var hash util.Uint256
param, ok := reqParams.Value(0)
if !ok {
resultsErr = response.ErrInvalidParams
break Methods
}
switch param.Type {
case request.StringT:
var err error
hash, err = param.GetUint256()
if err != nil {
resultsErr = response.ErrInvalidParams
break Methods
}
case request.NumberT:
num, err := s.blockHeightFromParam(param)
if err != nil {
resultsErr = response.ErrInvalidParams
break Methods
}
hash = s.chain.GetHeaderHash(num)
default:
resultsErr = response.ErrInvalidParams
break Methods
}
block, err := s.chain.GetBlock(hash)
if err != nil {
resultsErr = response.NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
break
}
if len(reqParams) == 2 && reqParams[1].Value == 1 {
results = result.NewBlock(block, s.chain)
} else {
writer := io.NewBufBinWriter()
block.EncodeBinary(writer.BinWriter)
results = hex.EncodeToString(writer.Bytes())
}
case "getblockcount":
getblockcountCalled.Inc()
results = s.chain.BlockHeight() + 1
case "getblockhash":
getblockHashCalled.Inc()
param, ok := reqParams.ValueWithType(0, request.NumberT)
if !ok {
resultsErr = response.ErrInvalidParams
break Methods
}
num, err := s.blockHeightFromParam(param)
if err != nil {
resultsErr = response.ErrInvalidParams
break Methods
}
results = s.chain.GetHeaderHash(num)
case "getblockheader":
getblockheaderCalled.Inc()
results, resultsErr = s.getBlockHeader(reqParams)
case "getblocksysfee":
getblocksysfeeCalled.Inc()
results, resultsErr = s.getBlockSysFee(reqParams)
case "getclaimable":
getclaimableCalled.Inc()
results, resultsErr = s.getClaimable(reqParams)
case "getconnectioncount":
getconnectioncountCalled.Inc()
results = s.coreServer.PeerCount()
case "getnep5balances":
getnep5balancesCalled.Inc()
results, resultsErr = s.getNEP5Balances(reqParams)
case "getnep5transfers":
getnep5transfersCalled.Inc()
results, resultsErr = s.getNEP5Transfers(reqParams)
case "getvalidators":
getvalidatorsCalled.Inc()
results, resultsErr = s.getValidators()
case "getversion":
getversionCalled.Inc()
results = result.Version{
Port: s.coreServer.Port,
Nonce: s.coreServer.ID(),
UserAgent: s.coreServer.UserAgent,
}
case "getpeers":
getpeersCalled.Inc()
peers := result.NewGetPeers()
peers.AddUnconnected(s.coreServer.UnconnectedPeers())
peers.AddConnected(s.coreServer.ConnectedPeers())
peers.AddBad(s.coreServer.BadPeers())
results = peers
case "getrawmempool":
getrawmempoolCalled.Inc()
mp := s.chain.GetMemPool()
hashList := make([]util.Uint256, 0)
for _, item := range mp.GetVerifiedTransactions() {
hashList = append(hashList, item.Tx.Hash())
}
results = hashList
case "getstorage":
getstorageCalled.Inc()
results, resultsErr = s.getStorage(reqParams)
case "validateaddress":
validateaddressCalled.Inc()
param, ok := reqParams.Value(0)
if !ok {
resultsErr = response.ErrInvalidParams
break Methods
}
results = validateAddress(param.Value)
case "getassetstate":
getassetstateCalled.Inc()
param, ok := reqParams.ValueWithType(0, request.StringT)
if !ok {
resultsErr = response.ErrInvalidParams
break Methods
}
paramAssetID, err := param.GetUint256()
if err != nil {
resultsErr = response.ErrInvalidParams
break
}
as := s.chain.GetAssetState(paramAssetID)
if as != nil {
results = result.NewAssetState(as)
} else {
resultsErr = response.NewRPCError("Unknown asset", "", nil)
}
case "getaccountstate":
getaccountstateCalled.Inc()
results, resultsErr = s.getAccountState(reqParams, false)
case "getcontractstate":
getcontractstateCalled.Inc()
results, resultsErr = s.getContractState(reqParams)
case "getrawtransaction":
getrawtransactionCalled.Inc()
results, resultsErr = s.getrawtransaction(reqParams)
case "gettransactionheight":
gettransactionheightCalled.Inc()
results, resultsErr = s.getTransactionHeight(reqParams)
case "gettxout":
gettxoutCalled.Inc()
results, resultsErr = s.getTxOut(reqParams)
case "getunclaimed":
getunclaimedCalled.Inc()
results, resultsErr = s.getUnclaimed(reqParams)
case "getunspents":
getunspentsCalled.Inc()
results, resultsErr = s.getAccountState(reqParams, true)
case "invoke":
results, resultsErr = s.invoke(reqParams)
case "invokefunction":
results, resultsErr = s.invokeFunction(reqParams)
case "invokescript":
results, resultsErr = s.invokescript(reqParams)
case "submitblock":
submitblockCalled.Inc()
results, resultsErr = s.submitBlock(reqParams)
case "sendrawtransaction":
sendrawtransactionCalled.Inc()
results, resultsErr = s.sendrawtransaction(reqParams)
default:
resultsErr = response.NewMethodNotFoundError(fmt.Sprintf("Method '%s' not supported", req.Method), nil) resultsErr = response.NewMethodNotFoundError(fmt.Sprintf("Method '%s' not supported", req.Method), nil)
} }
@ -369,6 +203,120 @@ Methods:
s.WriteResponse(req, w, results) s.WriteResponse(req, w, results)
} }
func (s *Server) getBestBlockHash(_ request.Params) (interface{}, error) {
return "0x" + s.chain.CurrentBlockHash().StringLE(), nil
}
func (s *Server) getBlockCount(_ request.Params) (interface{}, error) {
return s.chain.BlockHeight() + 1, nil
}
func (s *Server) getConnectionCount(_ request.Params) (interface{}, error) {
return s.coreServer.PeerCount(), nil
}
func (s *Server) getBlock(reqParams request.Params) (interface{}, error) {
var hash util.Uint256
param, ok := reqParams.Value(0)
if !ok {
return nil, response.ErrInvalidParams
}
switch param.Type {
case request.StringT:
var err error
hash, err = param.GetUint256()
if err != nil {
return nil, response.ErrInvalidParams
}
case request.NumberT:
num, err := s.blockHeightFromParam(param)
if err != nil {
return nil, response.ErrInvalidParams
}
hash = s.chain.GetHeaderHash(num)
default:
return nil, response.ErrInvalidParams
}
block, err := s.chain.GetBlock(hash)
if err != nil {
return nil, response.NewInternalServerError(fmt.Sprintf("Problem locating block with hash: %s", hash), err)
}
if len(reqParams) == 2 && reqParams[1].Value == 1 {
return result.NewBlock(block, s.chain), nil
}
writer := io.NewBufBinWriter()
block.EncodeBinary(writer.BinWriter)
return hex.EncodeToString(writer.Bytes()), nil
}
func (s *Server) getBlockHash(reqParams request.Params) (interface{}, error) {
param, ok := reqParams.ValueWithType(0, request.NumberT)
if !ok {
return nil, response.ErrInvalidParams
}
num, err := s.blockHeightFromParam(param)
if err != nil {
return nil, response.ErrInvalidParams
}
return s.chain.GetHeaderHash(num), nil
}
func (s *Server) getVersion(_ request.Params) (interface{}, error) {
return result.Version{
Port: s.coreServer.Port,
Nonce: s.coreServer.ID(),
UserAgent: s.coreServer.UserAgent,
}, nil
}
func (s *Server) getPeers(_ request.Params) (interface{}, error) {
peers := result.NewGetPeers()
peers.AddUnconnected(s.coreServer.UnconnectedPeers())
peers.AddConnected(s.coreServer.ConnectedPeers())
peers.AddBad(s.coreServer.BadPeers())
return peers, nil
}
func (s *Server) getRawMempool(_ request.Params) (interface{}, error) {
mp := s.chain.GetMemPool()
hashList := make([]util.Uint256, 0)
for _, item := range mp.GetVerifiedTransactions() {
hashList = append(hashList, item.Tx.Hash())
}
return hashList, nil
}
func (s *Server) validateAddress(reqParams request.Params) (interface{}, error) {
param, ok := reqParams.Value(0)
if !ok {
return nil, response.ErrInvalidParams
}
return validateAddress(param.Value), nil
}
func (s *Server) getAssetState(reqParams request.Params) (interface{}, error) {
param, ok := reqParams.ValueWithType(0, request.StringT)
if !ok {
return nil, response.ErrInvalidParams
}
paramAssetID, err := param.GetUint256()
if err != nil {
return nil, response.ErrInvalidParams
}
as := s.chain.GetAssetState(paramAssetID)
if as != nil {
return result.NewAssetState(as), nil
}
return nil, response.NewRPCError("Unknown asset", "", nil)
}
// getApplicationLog returns the contract log based on the specified txid. // getApplicationLog returns the contract log based on the specified txid.
func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, error) { func (s *Server) getApplicationLog(reqParams request.Params) (interface{}, error) {
param, ok := reqParams.Value(0) param, ok := reqParams.Value(0)
@ -730,8 +678,16 @@ func (s *Server) getContractState(reqParams request.Params) (interface{}, error)
return results, nil return results, nil
} }
func (s *Server) getAccountState(ps request.Params) (interface{}, error) {
return s.getAccountStateAux(ps, false)
}
func (s *Server) getUnspents(ps request.Params) (interface{}, error) {
return s.getAccountStateAux(ps, true)
}
// getAccountState returns account state either in short or full (unspents included) form. // getAccountState returns account state either in short or full (unspents included) form.
func (s *Server) getAccountState(reqParams request.Params, unspents bool) (interface{}, error) { func (s *Server) getAccountStateAux(reqParams request.Params, unspents bool) (interface{}, error) {
var resultsErr error var resultsErr error
var results interface{} var results interface{}
@ -759,7 +715,7 @@ func (s *Server) getAccountState(reqParams request.Params, unspents bool) (inter
} }
// getBlockSysFee returns the system fees of the block, based on the specified index. // getBlockSysFee returns the system fees of the block, based on the specified index.
func (s *Server) getBlockSysFee(reqParams request.Params) (util.Fixed8, error) { func (s *Server) getBlockSysFee(reqParams request.Params) (interface{}, error) {
param, ok := reqParams.ValueWithType(0, request.NumberT) param, ok := reqParams.ValueWithType(0, request.NumberT)
if !ok { if !ok {
return 0, response.ErrInvalidParams return 0, response.ErrInvalidParams
@ -843,7 +799,7 @@ func (s *Server) getUnclaimed(ps request.Params) (interface{}, error) {
} }
// getValidators returns the current NEO consensus nodes information and voting status. // getValidators returns the current NEO consensus nodes information and voting status.
func (s *Server) getValidators() (interface{}, error) { func (s *Server) getValidators(_ request.Params) (interface{}, error) {
var validators keys.PublicKeys var validators keys.PublicKeys
validators, err := s.chain.GetValidators() validators, err := s.chain.GetValidators()