From a716d374ca056b456e9fce796c246a5884aa39e5 Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Thu, 20 Jun 2019 05:58:25 -0500 Subject: [PATCH] Attempt to sync with sendheaders (#537) * Attempt to sync with sendheaders Fix sync with headers by generating one block in regtest to get out of IBD Fix comment Add more comments Add missing actor system import more clean up * refactor test case to avoid sleeping the thread --- .../scala/org/bitcoins/node/SpvNodeTest.scala | 62 ++++++++++++++++++- .../org/bitcoins/node/networking/Client.scala | 5 +- .../bitcoins/testkit/node/NodeUnitTest.scala | 6 +- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/node-test/src/test/scala/org/bitcoins/node/SpvNodeTest.scala b/node-test/src/test/scala/org/bitcoins/node/SpvNodeTest.scala index d503d98684..6a143b2504 100644 --- a/node-test/src/test/scala/org/bitcoins/node/SpvNodeTest.scala +++ b/node-test/src/test/scala/org/bitcoins/node/SpvNodeTest.scala @@ -1,6 +1,8 @@ package org.bitcoins.node +import akka.actor.ActorSystem import org.bitcoins.core.crypto.DoubleSha256DigestBE +import org.bitcoins.rpc.client.common.BitcoindRpcClient import org.bitcoins.rpc.util.RpcUtil import org.bitcoins.testkit.node.NodeUnitTest import org.bitcoins.testkit.node.fixture.SpvNodeConnectedWithBitcoind @@ -9,6 +11,8 @@ import org.scalatest.FutureOutcome import scala.concurrent.Future import org.bitcoins.testkit.node.NodeTestUtil +import scala.concurrent.duration.DurationInt + class SpvNodeTest extends NodeUnitTest { override type FixtureParam = SpvNodeConnectedWithBitcoind @@ -31,7 +35,7 @@ class SpvNodeTest extends NodeUnitTest { bitcoind.generate(1).map(_.head) } - //check we have that hash inside of our chain project! + //sync our spv node expecting to get that generated hash val spvSyncF = for { _ <- hashF sync <- spvNode.sync() @@ -42,6 +46,62 @@ class SpvNodeTest extends NodeUnitTest { .awaitSync(spvNode, bitcoind) .map(_ => succeed) } + } + it must "stay in sync with a bitcoind instance" in { + spvNodeConnectedWithBitcoind: SpvNodeConnectedWithBitcoind => + val spvNode = spvNodeConnectedWithBitcoind.spvNode + val bitcoind = spvNodeConnectedWithBitcoind.bitcoind + + //we need to generate 1 block for bitcoind to consider + //itself out of IBD. bitcoind will not sendheaders + //when it believes itself, or it's peer is in IBD + val gen1F = bitcoind.generate(1) + + //this needs to be called to get our peer to send us headers + //as they happen with the 'sendheaders' message + //both our spv node and our bitcoind node _should_ both be at the genesis block (regtest) + //at this point so no actual syncing is happening + val initSyncF = gen1F.flatMap(_ => spvNode.sync()) + + //start generating a block every 10 seconds with bitcoind + //this should result in 5 blocks + val startGenF = initSyncF.map { _ => + //generate a block every 5 seconds + //until we have generated 5 total blocks + genBlockInterval(bitcoind) + } + + startGenF.flatMap { _ => + //we should expect 5 headers have been announced to us via + //the send headers message. + val has6BlocksF = RpcUtil.retryUntilSatisfiedF( + conditionF = () => spvNode.chainApi.getBlockCount.map(_ == 6), + duration = 1.seconds) + + has6BlocksF.map(_ => succeed) + } + } + + /** Helper method to generate blocks every interval */ + private def genBlockInterval(bitcoind: BitcoindRpcClient)( + implicit system: ActorSystem): Unit = { + + var counter = 0 + val desiredBlocks = 5 + val interval = 500.millis + + val genBlock = new Runnable { + override def run(): Unit = { + if (counter < desiredBlocks) { + bitcoind.generate(1) + counter = counter + 1 + } else { + //do nothing + } + } + } + + system.scheduler.schedule(interval, interval, genBlock) } } diff --git a/node/src/main/scala/org/bitcoins/node/networking/Client.scala b/node/src/main/scala/org/bitcoins/node/networking/Client.scala index 73dd88ef7b..0b964a5289 100644 --- a/node/src/main/scala/org/bitcoins/node/networking/Client.scala +++ b/node/src/main/scala/org/bitcoins/node/networking/Client.scala @@ -1,7 +1,6 @@ package org.bitcoins.node.networking import akka.actor.{Actor, ActorRef, ActorRefFactory, Props} -import akka.event.LoggingReceive import akka.io.{IO, Tcp} import akka.util.ByteString import org.bitcoins.core.config.NetworkParameters @@ -71,7 +70,7 @@ sealed abstract class ClientActor extends Actor with BitcoinSLogger { */ private def awaitNetworkRequest( peer: ActorRef, - unalignedBytes: ByteVector): Receive = LoggingReceive { + unalignedBytes: ByteVector): Receive = { case message: NetworkMessage => sendNetworkMessage(message, peer) case payload: NetworkPayload => val networkMsg = NetworkMessage(network, payload) @@ -83,7 +82,7 @@ sealed abstract class ClientActor extends Actor with BitcoinSLogger { } /** This context is responsible for initializing a tcp connection with a peer on the bitcoin p2p network */ - def receive = LoggingReceive { + def receive: Receive = { case cmd: Tcp.Command => //we only accept a Tcp.Connect/Tcp.Connected //message to the default receive on this actor diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala index fecbe8f23a..e8f5c81fba 100644 --- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala +++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeUnitTest.scala @@ -4,7 +4,6 @@ import java.net.InetSocketAddress import akka.actor.ActorSystem import org.bitcoins.core.config.NetworkParameters -import org.bitcoins.core.p2p.NetworkIpAddress import org.bitcoins.core.util.BitcoinSLogger import org.bitcoins.db.AppConfig import org.bitcoins.node.SpvNode @@ -15,6 +14,8 @@ import org.bitcoins.node.networking.peer.{ PeerMessageSender } import org.bitcoins.rpc.client.common.BitcoindRpcClient +import org.bitcoins.testkit.BitcoinSAppConfig +import org.bitcoins.testkit.BitcoinSAppConfig._ import org.bitcoins.testkit.chain.ChainUnitTest import org.bitcoins.testkit.fixtures.BitcoinSFixture import org.bitcoins.testkit.node.fixture.SpvNodeConnectedWithBitcoind @@ -29,9 +30,6 @@ import org.scalatest.{ import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} -import org.bitcoins.testkit.BitcoinSAppConfig -import org.bitcoins.testkit.BitcoinSAppConfig._ - trait NodeUnitTest extends BitcoinSFixture with MustMatchers