Implement getconnectioncount rpc (#5048)

* Implement getconnectioncount rpc

* Reduce waits in test, add documentation

* Fix docs

* Empty commit to re-run CI
This commit is contained in:
Chris Stewart 2023-04-19 16:47:54 -05:00 committed by GitHub
parent 3728b9a9d9
commit 447c6d03de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 75 additions and 11 deletions

View File

@ -1398,8 +1398,8 @@ object ConsoleCli {
}))
),
note(sys.props("line.separator") + "=== Network ==="),
cmd("getpeers")
.action((_, conf) => conf.copy(command = GetPeers))
cmd("getconnectioncount")
.action((_, conf) => conf.copy(command = GetConnectionCount))
.text(s"List the connected peers"),
cmd("stop")
.action((_, conf) => conf.copy(command = Stop))
@ -2197,8 +2197,8 @@ object ConsoleCli {
// besthash
case GetBestBlockHash => RequestParam("getbestblockhash")
// peers
case GetPeers => RequestParam("getpeers")
case Stop => RequestParam("stop")
case GetConnectionCount => RequestParam("getpeers")
case Stop => RequestParam("stop")
case SendRawTransaction(tx) =>
RequestParam("sendrawtransaction", Seq(up.writeJs(tx)))
// PSBTs
@ -2490,7 +2490,7 @@ object CliCommand {
case object GetDLCWalletAccounting extends AppServerCliCommand
// Node
case object GetPeers extends AppServerCliCommand
case object GetConnectionCount extends AppServerCliCommand
case object Stop extends AppServerCliCommand
// Chain

View File

@ -1688,7 +1688,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
}
}
"return the peer list" in {
"return the peer list" ignore {
val route =
nodeRoutes.handleCommand(ServerCommand("getpeers", Arr()))
@ -1889,5 +1889,19 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
assert(str == expected)
}
}
"getConnectedPeerCount" in {
(() => mockNode.getConnectionCount)
.expects()
.returning(Future.successful(1))
val route =
nodeRoutes.handleCommand(ServerCommand("getconnectioncount", Arr()))
Get() ~> route ~> check {
assert(contentType == `application/json`)
assert(responseAs[String] == """{"result":1,"error":null}""")
}
}
}
}

View File

@ -367,6 +367,10 @@ object BitcoindRpcBackendUtil extends Logging {
transactions: Vector[Transaction]): Future[Unit] = {
bitcoindRpcClient.broadcastTransactions(transactions)
}
override def getConnectionCount: Future[Int] = {
bitcoindRpcClient.getConnectionCount
}
}
}

View File

@ -14,12 +14,12 @@ case class NodeRoutes(nodeApi: NodeApi)(implicit system: ActorSystem)
extends ServerRoute {
import system.dispatcher
def handleCommand: PartialFunction[ServerCommand, Route] = {
case ServerCommand("getpeers", _) =>
override def handleCommand: PartialFunction[ServerCommand, Route] = {
case ServerCommand("getconnectioncount", _) =>
complete {
Server.httpSuccess("TODO implement getpeers")
nodeApi.getConnectionCount
.map(count => Server.httpSuccess(count))
}
case ServerCommand("stop", _) =>
nodeApi match {
case node: Node =>

View File

@ -307,6 +307,10 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit
logger.warn(s"Cannot set IBD of BitcoindRpcClient, this is a noop")
Future.successful(this)
}
override def getConnectionCount: Future[Int] = {
super[P2PRpc].getConnectionCount
}
}
object BitcoindRpcClient {

View File

@ -22,4 +22,5 @@ trait NodeApi {
*/
def downloadBlocks(blockHashes: Vector[DoubleSha256Digest]): Future[Unit]
def getConnectionCount: Future[Int]
}

View File

@ -342,7 +342,7 @@ the `-p 9999:9999` port mapping on the docker container to adjust for this.
- `dropaddresslabels` `address` - drops all labels for the given address
### Network
- `getpeers` - List the connected peers
- `getconnectioncount` - Get the number of connected peers
- `stop` - Request a graceful shutdown of Bitcoin-S
- `sendrawtransaction` `tx` `Broadcasts the raw transaction`
- `tx` - Transaction serialized in hex

View File

@ -88,6 +88,8 @@ val exampleCallback = createCallback(exampleProcessBlock)
val blockFs = blockHashes.map(hash => bitcoind.getBlockRaw(hash))
Future.sequence(blockFs).map(_ => ())
}
override def getConnectionCount: Future[Int] = bitcoind.getConnectionCount
}
// Finally, we can initialize our wallet with our own node api

View File

@ -149,6 +149,7 @@ val syncF: Future[ChainApi] = configF.flatMap { _ =>
val wallet = Wallet(new NodeApi {
override def broadcastTransactions(txs: Vector[Transaction]): Future[Unit] = Future.successful(())
override def downloadBlocks(blockHashes: Vector[DoubleSha256Digest]): Future[Unit] = Future.successful(())
override def getConnectionCount: Future[Int] = Future.successful(0)
}, chainApi, ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
val walletF: Future[WalletApi] = configF.flatMap { _ =>
Wallet.initialize(wallet, None)

View File

@ -24,4 +24,10 @@ class DisconnectedPeerTest extends NodeUnitTest {
node.broadcastTransaction(tx)
}
}
it must "count 0 peer connections correctly" in { node =>
for {
connectionCount <- node.getConnectionCount
} yield assert(connectionCount == 0)
}
}

View File

@ -340,4 +340,24 @@ class NeutrinoNodeTest extends NodeTestWithCachedBitcoindPair {
succeed
}
}
it must "count peer connections correctly" in {
nodeConnectedWithBitcoind: NeutrinoNodeConnectedWithBitcoinds =>
val node = nodeConnectedWithBitcoind.node
val bitcoinds = nodeConnectedWithBitcoind.bitcoinds
for {
_ <- node.sync()
initConnectionCount <- node.getConnectionCount
_ = assert(initConnectionCount == 2)
nodeUri0 <- NodeTestUtil.getNodeURIFromBitcoind(bitcoinds(0))
_ <- bitcoinds(0).disconnectNode(nodeUri0)
_ <- AsyncUtil.nonBlockingSleep(1.seconds)
onePeerConnectionCount <- node.getConnectionCount
_ = assert(onePeerConnectionCount == 1)
nodeUri1 <- NodeTestUtil.getNodeURIFromBitcoind(bitcoinds(1))
_ <- bitcoinds(1).disconnectNode(nodeUri1)
_ <- AsyncUtil.nonBlockingSleep(1.seconds)
zeroPeerConnectionCount <- node.getConnectionCount
} yield assert(zeroPeerConnectionCount == 0)
}
}

View File

@ -213,6 +213,10 @@ trait Node extends NodeApi with ChainQueryApi with P2PLogger {
}
}
override def getConnectionCount: Future[Int] = {
Future.successful(peerManager.connectedPeerCount)
}
/** Gets the height of the given block */
override def getBlockHeight(
blockHash: DoubleSha256DigestBE): Future[Option[Int]] =

View File

@ -99,6 +99,9 @@ abstract class SyncUtil extends Logging {
()
}
}
override def getConnectionCount: Future[Int] =
bitcoindRpcClient.getConnectionCount
}
}
@ -156,6 +159,9 @@ abstract class SyncUtil extends Logging {
transactions: Vector[Transaction]): Future[Unit] = {
bitcoindRpcClient.broadcastTransactions(transactions)
}
override def getConnectionCount: Future[Int] =
bitcoindRpcClient.getConnectionCount
}
}

View File

@ -16,4 +16,6 @@ object MockNodeApi extends NodeApi {
override def downloadBlocks(
blockHashes: Vector[DoubleSha256Digest]): Future[Unit] = Future.unit
override def getConnectionCount: Future[Int] = Future.successful(0)
}