diff --git a/addrmgr/addrmanager.go b/addrmgr/addrmanager.go
index 2487ae53..cf97a905 100644
--- a/addrmgr/addrmanager.go
+++ b/addrmgr/addrmanager.go
@@ -74,6 +74,13 @@ type localAddress struct {
score AddressPriority
}
+// LocalAddr represents network address information for a local address.
+type LocalAddr struct {
+ Address string
+ Port uint16
+ Score int32
+}
+
// AddressPriority type is used to describe the hierarchy of local address
// discovery methods.
type AddressPriority int
@@ -536,7 +543,7 @@ func (a *AddrManager) deserializePeers(filePath string) error {
if v.refs > 0 && v.tried {
return fmt.Errorf("address %s after serialisation "+
- "which is both new and tried!", k)
+ "which is both new and tried", k)
}
}
@@ -1022,6 +1029,25 @@ func (a *AddrManager) HasLocalAddress(na *wire.NetAddress) bool {
return ok
}
+// FetchLocalAddresses fetches a summary of local addresses information for
+// the getnetworkinfo rpc.
+func (a *AddrManager) FetchLocalAddresses() []LocalAddr {
+ a.lamtx.Lock()
+ defer a.lamtx.Unlock()
+
+ addrs := make([]LocalAddr, 0, len(a.localAddresses))
+ for _, addr := range a.localAddresses {
+ la := LocalAddr{
+ Address: addr.na.IP.String(),
+ Port: addr.na.Port,
+ }
+
+ addrs = append(addrs, la)
+ }
+
+ return addrs
+}
+
const (
// Unreachable represents a publicly unreachable connection state
// between two addresses.
diff --git a/docs/json_rpc_api.mediawiki b/docs/json_rpc_api.mediawiki
index 033fba88..196bd05d 100644
--- a/docs/json_rpc_api.mediawiki
+++ b/docs/json_rpc_api.mediawiki
@@ -202,6 +202,10 @@ the method name for further details such as parameter and return information.
|Y
|Returns the estimated network hashes per second for the block heights provided by the parameters.
|-
+|[[#getnetworkinfo|getnetworkinfo]]
+|Y
+|Returns a JSON object containing network-related information.
+|-
|[[#getpeerinfo|getpeerinfo]]
|N
|Returns information about each connected network peer as an array of json objects.
@@ -950,6 +954,45 @@ the method name for further details such as parameter and return information.
----
+====getnetworkinfo====
+{|
+!Method
+|getnetworkinfo
+|-
+!Parameters
+|None
+|-
+!Description
+|Returns a JSON object containing network-related information.
+|-
+!Returns
+|(json object)
+: address: (string) The local address being listened on.
+: port: (numeric) The port being listened on for the associated local address.
+: score: (numeric) Reserved.
+: name: (string) The name of the network interface.
+: limited: (boolean) True if only connections to the network are allowed.
+: proxy: (string) The proxy set for the network.
+: proxyrandomizecredentials: (boolean) True if randomized credentials are set for the proxy.
+: reachable: (boolean) True if connections can be made to or from the network.
+: version: (numeric) The version of the node as a numeric.
+: subversion: (string) The subversion of the node, as advertised to peers.
+: protocolversion: (numeric) The protocol version of the node.
+: timeoffset: (numeric) The node clock offset in seconds.
+: connections: (numeric) The total number of open connections for the node.
+: networks: (json array) An array of objects describing IPV4, IPV6 and Onion network interface states.
+: relayfee: (numeric) The minimum required transaction fee for the node.
+: localaddresses: (json array) An array of objects describing local addresses being listened on by the node.
+: localservices: (string) The services supported by the node, as advertised in its version message.
+
+{"version": n, "subversion": "major.minor.patch", "protocolversion": n, "timeoffset": n, "connections": n, "networks": [{"name": "network", "limited": true or false, "reachable": true or false, "proxy": "host:port","proxyrandomizecredentials": true or false }, ...], "relayfee": n.nn., "localaddresses": [{ "address": "ip", "port": n, "score": n }, ...], "localservices": "services"}
+|-
+!Example Return
+|{"version": 1050000, "subversion": "1.5.0", "protocolversion": 6, "timeoffset": 0, "connections": 4, "networks": [{"name": "IPV4", "limited": true, "reachable": true, "proxy": "127.0.0.1:9050", "proxyrandomizecredentials": false}, {"name": "IPV6", "limited": false, "reachable": false, "proxy": "", "proxyrandomizecredentials": false}, {"name": "Onion", "limited": false, "reachable": false, "proxy": "", "proxyrandomizecredentials": false}], "relayfee": 0.0001, "localaddresses": [{"address": "fd87:d87e:eb43:d208:593b:4305:c8e5:2e77", "port": 9108, "score": 0}], "localservices": "0000000000000005"}
+|}
+
+----
+
====getpeerinfo====
{|
!Method
diff --git a/rpc/jsonrpc/types/chainsvrresults.go b/rpc/jsonrpc/types/chainsvrresults.go
index 010c448f..1cc268ee 100644
--- a/rpc/jsonrpc/types/chainsvrresults.go
+++ b/rpc/jsonrpc/types/chainsvrresults.go
@@ -287,12 +287,14 @@ type NetworksResult struct {
// command.
type GetNetworkInfoResult struct {
Version int32 `json:"version"`
+ SubVersion string `json:"subversion"`
ProtocolVersion int32 `json:"protocolversion"`
TimeOffset int64 `json:"timeoffset"`
Connections int32 `json:"connections"`
Networks []NetworksResult `json:"networks"`
RelayFee float64 `json:"relayfee"`
LocalAddresses []LocalAddressesResult `json:"localaddresses"`
+ LocalServices string `json:"localservices"`
}
// GetNetTotalsResult models the data returned from the getnettotals command.
diff --git a/rpcserver.go b/rpcserver.go
index 000e006c..9e53efba 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -210,6 +210,7 @@ var rpcHandlersBeforeInit = map[types.Method]commandHandler{
"getmininginfo": handleGetMiningInfo,
"getnettotals": handleGetNetTotals,
"getnetworkhashps": handleGetNetworkHashPS,
+ "getnetworkinfo": handleGetNetworkInfo,
"getpeerinfo": handleGetPeerInfo,
"getrawmempool": handleGetRawMempool,
"getrawtransaction": handleGetRawTransaction,
@@ -299,7 +300,6 @@ var rpcAskWallet = map[string]struct{}{
var rpcUnimplemented = map[string]struct{}{
"estimatepriority": {},
"getblocktemplate": {},
- "getnetworkinfo": {},
}
// Commands that are available to a limited user
@@ -331,6 +331,7 @@ var rpcLimited = map[string]struct{}{
"getinfo": {},
"getnettotals": {},
"getnetworkhashps": {},
+ "getnetworkinfo": {},
"getrawmempool": {},
"getrawtransaction": {},
"gettxout": {},
@@ -3359,6 +3360,35 @@ func handleGetNetworkHashPS(s *rpcServer, cmd interface{}, closeChan <-chan stru
return hashesPerSec.Int64(), nil
}
+// handleGetNetworkInfo implements the getnetworkinfo command.
+func handleGetNetworkInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
+ networks := cfg.generateNetworkInfo()
+ lAddrs := s.server.addrManager.FetchLocalAddresses()
+ localAddrs := make([]types.LocalAddressesResult, len(lAddrs))
+ for idx, entry := range lAddrs {
+ addr := types.LocalAddressesResult{
+ Address: entry.Address,
+ Port: entry.Port,
+ }
+ localAddrs[idx] = addr
+ }
+
+ info := types.GetNetworkInfoResult{
+ Version: int32(1000000*version.Major + 10000*version.Minor +
+ 100*version.Patch),
+ SubVersion: userAgentVersion,
+ ProtocolVersion: int32(maxProtocolVersion),
+ TimeOffset: int64(s.server.timeSource.Offset().Seconds()),
+ Connections: s.server.ConnectedCount(),
+ RelayFee: cfg.minRelayTxFee.ToCoin(),
+ Networks: networks,
+ LocalAddresses: localAddrs,
+ LocalServices: fmt.Sprintf("%016x", uint64(s.server.services)),
+ }
+
+ return info, nil
+}
+
// handleGetPeerInfo implements the getpeerinfo command.
func handleGetPeerInfo(s *rpcServer, cmd interface{}, closeChan <-chan struct{}) (interface{}, error) {
peers := s.server.Peers()
diff --git a/rpcserverhelp.go b/rpcserverhelp.go
index 654c6d86..4a155a96 100644
--- a/rpcserverhelp.go
+++ b/rpcserverhelp.go
@@ -609,6 +609,32 @@ var helpDescsEnUS = map[string]string{
"getnetworkhashps-height": "Perform estimate ending with this height or -1 for current best chain block height",
"getnetworkhashps--result0": "Estimated hashes per second",
+ // GetNetworkInfoCmd help.
+ "getnetworkinfo--synopsis": "Returns a JSON object containing network-related information.",
+
+ // LocalAddressesResult help.
+ "localaddressesresult-address": "The local address being listened on",
+ "localaddressesresult-port": "The port being listened on for the associated local address",
+ "localaddressesresult-score": "Reserved",
+
+ // NetworksResult help.
+ "networksresult-name": "The name of the network interface",
+ "networksresult-limited": "True if only connections to the network are allowed",
+ "networksresult-proxy": "The proxy set for the network",
+ "networksresult-proxyrandomizecredentials": "True if randomized credentials are set for the proxy",
+ "networksresult-reachable": "True if connections can be made to or from the network",
+
+ // GetNetworkInfoResult help.
+ "getnetworkinforesult-version": "The version of the node as a numeric",
+ "getnetworkinforesult-subversion": "The subversion of the node, as advertised to peers",
+ "getnetworkinforesult-protocolversion": "The protocol version of the node",
+ "getnetworkinforesult-timeoffset": "The node clock offset in seconds",
+ "getnetworkinforesult-connections": "The total number of open connections for the node",
+ "getnetworkinforesult-networks": "An array of objects describing IPV4, IPV6 and Onion network interface states",
+ "getnetworkinforesult-relayfee": "The minimum required transaction fee for the node.",
+ "getnetworkinforesult-localaddresses": "An array of objects describing local addresses being listened on by the node",
+ "getnetworkinforesult-localservices": "The services supported by the node, as advertised in its version message",
+
// GetNetTotalsCmd help.
"getnettotals--synopsis": "Returns a JSON object containing network traffic statistics.",
@@ -990,6 +1016,7 @@ var rpcResultTypes = map[types.Method][]interface{}{
"getmininginfo": {(*types.GetMiningInfoResult)(nil)},
"getnettotals": {(*types.GetNetTotalsResult)(nil)},
"getnetworkhashps": {(*int64)(nil)},
+ "getnetworkinfo": {(*[]types.GetNetworkInfoResult)(nil)},
"getpeerinfo": {(*[]types.GetPeerInfoResult)(nil)},
"getrawmempool": {(*[]string)(nil), (*types.GetRawMempoolVerboseResult)(nil)},
"getrawtransaction": {(*string)(nil), (*types.TxRawResult)(nil)},