Skip to content

Commit

Permalink
Fix Startup tests
Browse files Browse the repository at this point in the history
And make it optional to poll bitcoind until it's up.
  • Loading branch information
t-bast committed Sep 21, 2023
1 parent e5b9878 commit c73b928
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 23 deletions.
2 changes: 2 additions & 0 deletions eclair-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ eclair {
// - ignore: eclair will leave these utxos locked and start
startup-locked-utxos-behavior = "stop"
final-pubkey-refresh-delay = 3 seconds
// If true, eclair will poll bitcoind for 30 seconds at start-up before giving up.
wait-for-bitcoind-up = true
}

node-alias = "eclair"
Expand Down
30 changes: 18 additions & 12 deletions eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ class Setup(val datadir: File,
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) }
after(5 seconds) {
pollBitcoinStatus(bitcoinClient)
}
}
}

Expand All @@ -181,18 +183,22 @@ class Setup(val datadir: File,
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).")
if (chainHash != Block.RegtestGenesisBlock.hash) {
assert(!initialBlockDownload, s"bitcoind should be synchronized (initialblockdownload=$initialBlockDownload)")
assert(progress > 0.999, s"bitcoind should be synchronized (progress=$progress)")
assert(headers - blocks <= 1, s"bitcoind should be synchronized (headers=$headers blocks=$blocks)")
val bitcoinStatus = if (config.getBoolean("bitcoind.wait-for-bitcoind-up")) {
await(pollBitcoinStatus(bitcoinClient), 30 seconds, "bitcoind wasn't ready after 30 seconds")
} else {
await(getBitcoinStatus(bitcoinClient), 30 seconds, "bitcoind did not respond after 30 seconds")
}
logger.info(s"bitcoind version=${bitcoinStatus.version}")
assert(bitcoinStatus.version >= 230000, "Eclair requires Bitcoin Core 23.0 or higher")
assert(bitcoinStatus.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).")
if (bitcoinStatus.chainHash != Block.RegtestGenesisBlock.hash) {
assert(!bitcoinStatus.initialBlockDownload, s"bitcoind should be synchronized (initialblockdownload=${bitcoinStatus.initialBlockDownload})")
assert(bitcoinStatus.verificationProgress > 0.999, s"bitcoind should be synchronized (progress=${bitcoinStatus.verificationProgress})")
assert(bitcoinStatus.headerCount - bitcoinStatus.blockCount <= 1, s"bitcoind should be synchronized (headers=${bitcoinStatus.headerCount} blocks=${bitcoinStatus.blockCount})")
}
logger.info(s"current blockchain height=$blocks")
blockHeight.set(blocks)
(bitcoinClient, chainHash)
logger.info(s"current blockchain height=${bitcoinStatus.blockCount}")
blockHeight.set(bitcoinStatus.blockCount)
(bitcoinClient, bitcoinStatus.chainHash)
}

val instanceId = UUID.randomUUID()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package fr.acinq.eclair.integration

import akka.testkit.TestProbe
import com.typesafe.config.ConfigFactory
import com.typesafe.config.{Config, ConfigFactory}
import fr.acinq.eclair.blockchain.bitcoind.BitcoindService.BitcoinReq
import fr.acinq.eclair.blockchain.bitcoind.rpc.{Error, JsonRPCError}
import fr.acinq.eclair.{BitcoinDefaultWalletException, BitcoinWalletDisabledException, BitcoinWalletNotLoadedException, TestUtils}
Expand All @@ -30,41 +30,49 @@ import scala.jdk.CollectionConverters._

class StartupIntegrationSpec extends IntegrationSpec {

private def createConfig(wallet_opt: Option[String]): Config = {
val defaultConfig = ConfigFactory.parseMap(Map("eclair.bitcoind.wait-for-bitcoind-up" -> "false", "eclair.server.port" -> TestUtils.availablePort).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig)
wallet_opt match {
case Some(wallet) => ConfigFactory.parseMap(Map("eclair.bitcoind.wallet" -> wallet).asJava).withFallback(defaultConfig)
case None => defaultConfig
}
}

test("no bitcoind wallet configured and one wallet loaded") {
instantiateEclairNode("A", ConfigFactory.parseMap(Map("eclair.bitcoind.wallet" -> "", "eclair.server.port" -> TestUtils.availablePort).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("A", createConfig(wallet_opt = Some("")))
}

test("no bitcoind wallet configured and two wallets loaded") {
val sender = TestProbe()
sender.send(bitcoincli, BitcoinReq("createwallet", ""))
sender.send(bitcoincli, BitcoinReq("createwallet", "other_wallet"))
sender.expectMsgType[Any]
val thrown = intercept[BitcoinDefaultWalletException] {
instantiateEclairNode("C", ConfigFactory.parseMap(Map("eclair.bitcoind.wallet" -> "", "eclair.server.port" -> TestUtils.availablePort).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("C", createConfig(wallet_opt = Some("")))
}
assert(thrown == BitcoinDefaultWalletException(List(defaultWallet, "")))
assert(thrown == BitcoinDefaultWalletException(List(defaultWallet, "other_wallet")))
}

test("explicit bitcoind wallet configured and two wallets loaded") {
val sender = TestProbe()
sender.send(bitcoincli, BitcoinReq("createwallet", ""))
sender.send(bitcoincli, BitcoinReq("createwallet", "other_wallet"))
sender.expectMsgType[Any]
instantiateEclairNode("D", ConfigFactory.parseMap(Map("eclair.server.port" -> TestUtils.availablePort).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("D", createConfig(wallet_opt = Some(defaultWallet)))
}

test("explicit bitcoind wallet configured but not loaded") {
val sender = TestProbe()
sender.send(bitcoincli, BitcoinReq("createwallet", ""))
sender.send(bitcoincli, BitcoinReq("createwallet", "other_wallet"))
sender.expectMsgType[Any]
val thrown = intercept[BitcoinWalletNotLoadedException] {
instantiateEclairNode("E", ConfigFactory.parseMap(Map("eclair.bitcoind.wallet" -> "notloaded", "eclair.server.port" -> TestUtils.availablePort).asJava).withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("E", createConfig(wallet_opt = Some("not_loaded")))
}
assert(thrown == BitcoinWalletNotLoadedException("notloaded", List(defaultWallet, "")))
assert(thrown == BitcoinWalletNotLoadedException("not_loaded", List(defaultWallet, "other_wallet")))
}

test("bitcoind started with wallets disabled") {
restartBitcoind(startupFlags = "-disablewallet", loadWallet = false)
val thrown = intercept[BitcoinWalletDisabledException] {
instantiateEclairNode("F", ConfigFactory.load().getConfig("eclair").withFallback(withDefaultCommitment).withFallback(commonConfig))
instantiateEclairNode("F", createConfig(wallet_opt = Some("")))
}
assert(thrown == BitcoinWalletDisabledException(e = JsonRPCError(Error(-32601, "Method not found"))))
}
Expand Down

0 comments on commit c73b928

Please sign in to comment.