Skip to content

Commit

Permalink
Poll bitcoind at startup
Browse files Browse the repository at this point in the history
When we start, bitcoind may not be ready to handle requests if we restarted
it around the same time. We thus poll it for 30 seconds before giving up.
This is especially useful for tests (e.g. on regtest).
  • Loading branch information
t-bast committed Sep 7, 2023
1 parent 8d42052 commit 96df2e8
Showing 1 changed file with 21 additions and 9 deletions.
30 changes: 21 additions & 9 deletions eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,9 @@ class Setup(val datadir: File,
case "password" => BitcoinJsonRPCAuthMethod.UserPassword(config.getString("bitcoind.rpcuser"), config.getString("bitcoind.rpcpassword"))
}

val bitcoinClient = new BasicBitcoinJsonRPCClient(
rpcAuthMethod = rpcAuthMethod,
host = config.getString("bitcoind.host"),
port = config.getInt("bitcoind.rpcport"),
wallet = wallet)
val future = for {
case class BitcoinStatus(version: Int, chainHash: ByteVector32, initialBlockDownload: Boolean, verificationProgress: Double, blockCount: Long, headerCount: Long, unspentAddresses: List[String])

def getBitcoinStatus(bitcoinClient: BasicBitcoinJsonRPCClient): Future[BitcoinStatus] = for {
json <- bitcoinClient.invoke("getblockchaininfo").recover { case e => throw BitcoinRPCConnectionException(e) }
// Make sure wallet support is enabled in bitcoind.
wallets <- bitcoinClient.invoke("listwallets").recover { case e => throw BitcoinWalletDisabledException(e) }
Expand All @@ -164,9 +161,24 @@ class Setup(val datadir: File,
case "signet" => bitcoinClient.invoke("getrawtransaction", "ff1027486b628b2d160859205a3401fb2ee379b43527153b0b50a92c17ee7955") // coinbase of #5000
case "regtest" => Future.successful(())
}
} yield (progress, ibd, chainHash, bitcoinVersion, unspentAddresses, blocks, headers)
// blocking sanity checks
val (progress, initialBlockDownload, chainHash, bitcoinVersion, unspentAddresses, blocks, headers) = await(future, 30 seconds, "bitcoind did not respond after 30 seconds")
} yield BitcoinStatus(bitcoinVersion, chainHash, ibd, progress, blocks, headers, unspentAddresses)

def pollBitcoinStatus(bitcoinClient: BasicBitcoinJsonRPCClient): Future[BitcoinStatus] = {
getBitcoinStatus(bitcoinClient).transformWith {
case Success(status) => Future.successful(status)
case Failure(e) =>
logger.warn(s"failed to connect to bitcoind (${e.getMessage}), retrying...")
after(5 seconds) { pollBitcoinStatus(bitcoinClient) }
}
}

val bitcoinClient = new BasicBitcoinJsonRPCClient(
rpcAuthMethod = rpcAuthMethod,
host = config.getString("bitcoind.host"),
port = config.getInt("bitcoind.rpcport"),
wallet = wallet
)
val BitcoinStatus(bitcoinVersion, chainHash, initialBlockDownload, progress, blocks, headers, unspentAddresses) = await(pollBitcoinStatus(bitcoinClient), 30 seconds, "bitcoind did not respond after 30 seconds")
logger.info(s"bitcoind version=$bitcoinVersion")
assert(bitcoinVersion >= 230000, "Eclair requires Bitcoin Core 23.0 or higher")
assert(unspentAddresses.forall(address => !isPay2PubkeyHash(address)), "Your wallet contains non-segwit UTXOs. You must send those UTXOs to a bech32 address to use Eclair (check out our README for more details).")
Expand Down

0 comments on commit 96df2e8

Please sign in to comment.