rpc: Add getnodeaddresses JSON-RPC support

Add NodeAddresses function to rpcserverConnManager
interface for fetching known node addresses.
This commit is contained in:
Mikael Lindlof 2020-05-31 13:30:50 +01:00 committed by John C. Vernaleo
parent 9ef973c282
commit fff96610aa
7 changed files with 150 additions and 0 deletions

View file

@ -557,6 +557,22 @@ func NewGetNetworkHashPSCmd(numBlocks, height *int) *GetNetworkHashPSCmd {
}
}
// GetNodeAddressesCmd defines the getnodeaddresses JSON-RPC command.
type GetNodeAddressesCmd struct {
Count *int32 `jsonrpcdefault:"1"`
}
// NewGetNodeAddressesCmd returns a new instance which can be used to issue a
// getnodeaddresses JSON-RPC command.
//
// The parameters which are pointers indicate they are optional. Passing nil
// for optional parameters will use the default value.
func NewGetNodeAddressesCmd(count *int32) *GetNodeAddressesCmd {
return &GetNodeAddressesCmd{
Count: count,
}
}
// GetPeerInfoCmd defines the getpeerinfo JSON-RPC command.
type GetPeerInfoCmd struct{}
@ -974,6 +990,7 @@ func init() {
MustRegisterCmd("getnetworkinfo", (*GetNetworkInfoCmd)(nil), flags)
MustRegisterCmd("getnettotals", (*GetNetTotalsCmd)(nil), flags)
MustRegisterCmd("getnetworkhashps", (*GetNetworkHashPSCmd)(nil), flags)
MustRegisterCmd("getnodeaddresses", (*GetNodeAddressesCmd)(nil), flags)
MustRegisterCmd("getpeerinfo", (*GetPeerInfoCmd)(nil), flags)
MustRegisterCmd("getrawmempool", (*GetRawMempoolCmd)(nil), flags)
MustRegisterCmd("getrawtransaction", (*GetRawTransactionCmd)(nil), flags)

View file

@ -753,6 +753,32 @@ func TestChainSvrCmds(t *testing.T) {
Height: btcjson.Int(123),
},
},
{
name: "getnodeaddresses",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getnodeaddresses")
},
staticCmd: func() interface{} {
return btcjson.NewGetNodeAddressesCmd(nil)
},
marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[],"id":1}`,
unmarshalled: &btcjson.GetNodeAddressesCmd{
Count: btcjson.Int32(1),
},
},
{
name: "getnodeaddresses optional",
newCmd: func() (interface{}, error) {
return btcjson.NewCmd("getnodeaddresses", 10)
},
staticCmd: func() interface{} {
return btcjson.NewGetNodeAddressesCmd(btcjson.Int32(10))
},
marshalled: `{"jsonrpc":"1.0","method":"getnodeaddresses","params":[10],"id":1}`,
unmarshalled: &btcjson.GetNodeAddressesCmd{
Count: btcjson.Int32(10),
},
},
{
name: "getpeerinfo",
newCmd: func() (interface{}, error) {

View file

@ -365,6 +365,16 @@ type GetNetworkInfoResult struct {
Warnings string `json:"warnings"`
}
// GetNodeAddressesResult models the data returned from the getnodeaddresses
// command.
type GetNodeAddressesResult struct {
// Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen
Time int64 `json:"time"`
Services uint64 `json:"services"` // The services offered
Address string `json:"address"` // The address of the node
Port uint16 `json:"port"` // The port of the node
}
// GetPeerInfoResult models the data returned from the getpeerinfo command.
type GetPeerInfoResult struct {
ID int32 `json:"id"`

View file

@ -223,6 +223,15 @@ func (cm *rpcConnManager) RelayTransactions(txns []*mempool.TxDesc) {
cm.server.relayTransactions(txns)
}
// NodeAddresses returns an array consisting node addresses which can
// potentially be used to find new nodes in the network.
//
// This function is safe for concurrent access and is part of the
// rpcserverConnManager interface implementation.
func (cm *rpcConnManager) NodeAddresses() []*wire.NetAddress {
return cm.server.addrManager.AddressCache()
}
// rpcSyncMgr provides a block manager for use with the RPC server and
// implements the rpcserverSyncManager interface.
type rpcSyncMgr struct {

View file

@ -281,6 +281,43 @@ func (c *Client) GetNetworkInfo() (*btcjson.GetNetworkInfoResult, error) {
return c.GetNetworkInfoAsync().Receive()
}
// FutureGetNodeAddressesResult is a future promise to deliver the result of a
// GetNodeAddressesAsync RPC invocation (or an applicable error).
type FutureGetNodeAddressesResult chan *response
// Receive waits for the response promised by the future and returns data about
// known node addresses.
func (r FutureGetNodeAddressesResult) Receive() ([]btcjson.GetNodeAddressesResult, error) {
res, err := receiveFuture(r)
if err != nil {
return nil, err
}
// Unmarshal result as an array of getnodeaddresses result objects.
var nodeAddresses []btcjson.GetNodeAddressesResult
err = json.Unmarshal(res, &nodeAddresses)
if err != nil {
return nil, err
}
return nodeAddresses, nil
}
// GetNodeAddressesAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetNodeAddresses for the blocking version and more details.
func (c *Client) GetNodeAddressesAsync(count *int32) FutureGetNodeAddressesResult {
cmd := btcjson.NewGetNodeAddressesCmd(count)
return c.sendCmd(cmd)
}
// GetNodeAddresses returns data about known node addresses.
func (c *Client) GetNodeAddresses(count *int32) ([]btcjson.GetNodeAddressesResult, error) {
return c.GetNodeAddressesAsync(count).Receive()
}
// FutureGetPeerInfoResult is a future promise to deliver the result of a
// GetPeerInfoAsync RPC invocation (or an applicable error).
type FutureGetPeerInfoResult chan *response

View file

@ -156,6 +156,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"getmininginfo": handleGetMiningInfo,
"getnettotals": handleGetNetTotals,
"getnetworkhashps": handleGetNetworkHashPS,
"getnodeaddresses": handleGetNodeAddresses,
"getpeerinfo": handleGetPeerInfo,
"getrawmempool": handleGetRawMempool,
"getrawtransaction": handleGetRawTransaction,
@ -2477,6 +2478,40 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru
return hashesPerSec.Int64(), nil
}
// handleGetNodeAddresses implements the getnodeaddresses command.
func handleGetNodeAddresses(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
c := cmd.(*btcjson.GetNodeAddressesCmd)
count := int32(1)
if c.Count != nil {
count = *c.Count
if count <= 0 {
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCInvalidParameter,
Message: "Address count out of range",
}
}
}
nodes := s.cfg.ConnMgr.NodeAddresses()
if n := int32(len(nodes)); n < count {
count = n
}
addresses := make([]*btcjson.GetNodeAddressesResult, 0, count)
for _, node := range nodes[:count] {
address := &btcjson.GetNodeAddressesResult{
Time: node.Timestamp.Unix(),
Services: uint64(node.Services),
Address: node.IP.String(),
Port: node.Port,
}
addresses = append(addresses, address)
}
return addresses, nil
}
// handleGetPeerInfo implements the getpeerinfo command.
func handleGetPeerInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
peers := s.cfg.ConnMgr.ConnectedPeers()
@ -4298,6 +4333,10 @@ type rpcserverConnManager interface {
// RelayTransactions generates and relays inventory vectors for all of
// the passed transactions to all connected peers.
RelayTransactions(txns []*mempool.TxDesc)
// NodeAddresses returns an array consisting node addresses which can
// potentially be used to find new nodes in the network.
NodeAddresses() []*wire.NetAddress
}
// rpcserverSyncManager represents a sync manager for use with the RPC server.

View file

@ -452,6 +452,17 @@ var helpDescsEnUS = map[string]string{
"getnettotalsresult-totalbytessent": "Total bytes sent",
"getnettotalsresult-timemillis": "Number of milliseconds since 1 Jan 1970 GMT",
// GetNodeAddressesResult help.
"getnodeaddressesresult-time": "Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen",
"getnodeaddressesresult-services": "The services offered",
"getnodeaddressesresult-address": "The address of the node",
"getnodeaddressesresult-port": "The port of the node",
// GetNodeAddressesCmd help.
"getnodeaddresses--synopsis": "Return known addresses which can potentially be used to find new nodes in the network",
"getnodeaddresses-count": "How many addresses to return. Limited to the smaller of 2500 or 23% of all known addresses",
"getnodeaddresses--result0": "List of node addresses",
// GetPeerInfoResult help.
"getpeerinforesult-id": "A unique node ID",
"getpeerinforesult-addr": "The ip address and port of the peer",
@ -726,6 +737,7 @@ var rpcResultTypes = map[string][]interface{}{
"getmininginfo": {(*btcjson.GetMiningInfoResult)(nil)},
"getnettotals": {(*btcjson.GetNetTotalsResult)(nil)},
"getnetworkhashps": {(*int64)(nil)},
"getnodeaddresses": {(*[]btcjson.GetNodeAddressesResult)(nil)},
"getpeerinfo": {(*[]btcjson.GetPeerInfoResult)(nil)},
"getrawmempool": {(*[]string)(nil), (*btcjson.GetRawMempoolVerboseResult)(nil)},
"getrawtransaction": {(*string)(nil), (*btcjson.TxRawResult)(nil)},