From 61d4882efd8137dfd342fab8bcd2652f941b9bfc Mon Sep 17 00:00:00 2001 From: Chris Stewart Date: Sat, 10 Sep 2022 11:11:21 -0500 Subject: [PATCH] Implement retry of fetching bitcoind version when calling `clientF` (#4760) * Implement retry of fetching bitcoind version when calling clientF * Change BitcoindRpcClient.version to be a method rather than val --- .../rpc/client/common/BitcoindRpcClient.scala | 2 +- .../bitcoins/rpc/client/common/Client.scala | 2 +- .../rpc/config/BitcoindRpcAppConfig.scala | 35 +++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala index 6c15ce8d22..7769c7d71d 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/BitcoindRpcClient.scala @@ -70,7 +70,7 @@ class BitcoindRpcClient(override val instance: BitcoindInstance)(implicit private val syncing = new AtomicBoolean(false) - override lazy val version: Future[BitcoindVersion] = { + override def version: Future[BitcoindVersion] = { instance match { case _: BitcoindInstanceRemote => getNetworkInfo.map(info => diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala index 424adb931b..e7535dbb51 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/client/common/Client.scala @@ -156,7 +156,7 @@ trait Client * cannot be started */ override def start(): Future[BitcoindRpcClient] = { - + logger.info(s"Client.start() instance=$instance") // if we're doing cookie based authentication, we might attempt // to read the cookie file before it's written. this ensures // we avoid that diff --git a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala index 7e5955de1e..17c1c585a8 100644 --- a/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala +++ b/bitcoind-rpc/src/main/scala/org/bitcoins/rpc/config/BitcoindRpcAppConfig.scala @@ -2,7 +2,9 @@ package org.bitcoins.rpc.config import akka.actor.ActorSystem import com.typesafe.config.Config +import org.bitcoins.asyncutil.AsyncUtil import org.bitcoins.commons.config.{AppConfig, ConfigOps} +import org.bitcoins.rpc.BitcoindException.InWarmUp import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion} import org.bitcoins.rpc.util.AppConfigFactoryActorSystem import org.bitcoins.tor.Socks5ProxyParams @@ -11,7 +13,8 @@ import org.bitcoins.tor.config.TorAppConfig import java.io.File import java.net.{InetSocketAddress, URI} import java.nio.file._ -import scala.concurrent.Future +import scala.concurrent.duration.DurationInt +import scala.concurrent.{Future, Promise} /** Configuration for a BitcoindRpcClient * @param directory The data directory of the Bitcoin-S instance @@ -173,7 +176,7 @@ case class BitcoindRpcAppConfig( //first get a generic rpc client so we can retrieve //the proper version of the remote running bitcoind val noVersionRpc = new BitcoindRpcClient(bitcoindInstance) - val versionF = noVersionRpc.version + val versionF = getBitcoindVersion(noVersionRpc) //if we don't retrieve the proper version, we can //end up with exceptions on an rpc client that actually supports @@ -185,6 +188,34 @@ case class BitcoindRpcAppConfig( } } } + + private def getBitcoindVersion( + client: BitcoindRpcClient): Future[BitcoindVersion] = { + val promise = Promise[BitcoindVersion]() + val interval = 1.second + val maxTries = 300 //5 minutes + for { + _ <- AsyncUtil.retryUntilSatisfiedF( + conditionF = { () => + val infoF = client.version + val res = infoF.map(promise.success).map(_ => true) + res.recover { case _: InWarmUp => + logger.info(s"Bitcoind still in warmup, trying again in $interval") + false + + } + }, + // retry for approximately 5 minutes + mode = AsyncUtil.Linear, + interval = interval, + maxTries = maxTries + ) + version <- promise.future + } yield { + logger.info(s"Retrieved bitcoind version=$version") + version + } + } } object BitcoindRpcAppConfig