Skip to content

Commit

Permalink
rpc: Add getnodeaddresses JSON-RPC support
Browse files Browse the repository at this point in the history
Add NodeAddresses function to rpcserverConnManager
interface for fetching known node addresses.
  • Loading branch information
lindlof committed Sep 9, 2020
1 parent 2547246 commit c1b6b40
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 0 deletions.
17 changes: 17 additions & 0 deletions btcjson/chainsvrcmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}

Expand Down Expand Up @@ -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)
Expand Down
26 changes: 26 additions & 0 deletions btcjson/chainsvrcmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
10 changes: 10 additions & 0 deletions btcjson/chainsvrresults.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
9 changes: 9 additions & 0 deletions rpcadapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
37 changes: 37 additions & 0 deletions rpcclient/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
39 changes: 39 additions & 0 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ var rpcHandlersBeforeInit = map[string]commandHandler{
"getmininginfo": handleGetMiningInfo,
"getnettotals": handleGetNetTotals,
"getnetworkhashps": handleGetNetworkHashPS,
"getnodeaddresses": handleGetNodeAddresses,
"getpeerinfo": handleGetPeerInfo,
"getrawmempool": handleGetRawMempool,
"getrawtransaction": handleGetRawTransaction,
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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.
Expand Down
12 changes: 12 additions & 0 deletions rpcserverhelp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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)},
Expand Down

0 comments on commit c1b6b40

Please sign in to comment.