From 6f7850d2bca28fd9ee89ffcc3a53ff805e16b3c0 Mon Sep 17 00:00:00 2001 From: sstone Date: Thu, 27 Feb 2025 17:45:21 +0100 Subject: [PATCH] Add a "chain hash" property to the bitcoin rpc client --- eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala | 2 ++ .../bitcoind/rpc/BasicBitcoinJsonRPCClient.scala | 3 ++- .../bitcoind/rpc/BatchingBitcoinJsonRPCClient.scala | 2 ++ .../blockchain/bitcoind/rpc/BitcoinJsonRPCClient.scala | 3 +++ .../scala/fr/acinq/eclair/TestBitcoinCoreClient.scala | 2 +- .../blockchain/bitcoind/BitcoinCoreClientSpec.scala | 8 +++++--- .../eclair/blockchain/bitcoind/BitcoindService.scala | 4 ++-- .../blockchain/fee/BitcoinCoreFeeProviderSpec.scala | 2 +- .../channel/publish/ReplaceableTxPublisherSpec.scala | 2 +- .../eclair/router/AnnouncementsBatchValidationSpec.scala | 2 +- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala index d2affaea4..0a333cd52 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -24,6 +24,7 @@ import akka.pattern.after import akka.util.Timeout import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BlockId, ByteVector32, Satoshi, Script, addressToPublicKeyScript} +import fr.acinq.eclair.NodeParams.hashFromChain import fr.acinq.eclair.Setup.Seeds import fr.acinq.eclair.balance.{BalanceActor, ChannelsListener} import fr.acinq.eclair.blockchain._ @@ -177,6 +178,7 @@ class Setup(val datadir: File, } val bitcoinClient = new BasicBitcoinJsonRPCClient( + chainHash = hashFromChain(chain), rpcAuthMethod = rpcAuthMethod, host = config.getString("bitcoind.host"), port = config.getInt("bitcoind.rpcport"), diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala index 4c05b9803..f66e5bea7 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BasicBitcoinJsonRPCClient.scala @@ -16,6 +16,7 @@ package fr.acinq.eclair.blockchain.bitcoind.rpc +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.eclair.KamonExt import fr.acinq.eclair.blockchain.Monitoring.{Metrics, Tags} import fr.acinq.eclair.json._ @@ -32,7 +33,7 @@ import java.util.concurrent.atomic.AtomicReference import scala.concurrent.{ExecutionContext, Future} import scala.util.{Failure, Success, Try} -class BasicBitcoinJsonRPCClient(rpcAuthMethod: BitcoinJsonRPCAuthMethod, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false, override val wallet: Option[String] = None)(implicit sb: SttpBackend[Future, _]) extends BitcoinJsonRPCClient { +class BasicBitcoinJsonRPCClient(override val chainHash: BlockHash, rpcAuthMethod: BitcoinJsonRPCAuthMethod, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false, override val wallet: Option[String] = None)(implicit sb: SttpBackend[Future, _]) extends BitcoinJsonRPCClient { implicit val formats: Formats = DefaultFormats.withBigDecimal + ByteVector32Serializer + ByteVector32KmpSerializer + diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BatchingBitcoinJsonRPCClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BatchingBitcoinJsonRPCClient.scala index 6e3604123..5535c90ef 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BatchingBitcoinJsonRPCClient.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BatchingBitcoinJsonRPCClient.scala @@ -19,6 +19,7 @@ package fr.acinq.eclair.blockchain.bitcoind.rpc import akka.actor.{ActorSystem, Props} import akka.pattern.ask import akka.util.Timeout +import fr.acinq.bitcoin.scalacompat.BlockHash import fr.acinq.eclair.KamonExt import fr.acinq.eclair.blockchain.Monitoring.Metrics import org.json4s.JsonAST @@ -27,6 +28,7 @@ import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} class BatchingBitcoinJsonRPCClient(rpcClient: BasicBitcoinJsonRPCClient)(implicit system: ActorSystem, ec: ExecutionContext) extends BitcoinJsonRPCClient { + override def chainHash: BlockHash = rpcClient.chainHash override def wallet: Option[String] = rpcClient.wallet implicit val timeout: Timeout = Timeout(1 hour) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinJsonRPCClient.scala b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinJsonRPCClient.scala index 63468d9ca..2a1986357 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinJsonRPCClient.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/blockchain/bitcoind/rpc/BitcoinJsonRPCClient.scala @@ -16,12 +16,15 @@ package fr.acinq.eclair.blockchain.bitcoind.rpc +import fr.acinq.bitcoin.scalacompat.BlockHash import org.json4s.JsonAST.JValue import java.io.IOException import scala.concurrent.{ExecutionContext, Future} trait BitcoinJsonRPCClient { + def chainHash: BlockHash + def wallet: Option[String] def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala index 9389d3424..6e729471e 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestBitcoinCoreClient.scala @@ -30,7 +30,7 @@ import scala.concurrent.{ExecutionContext, Future} /** * Created by PM on 26/04/2016. */ -class TestBitcoinCoreClient()(implicit system: ActorSystem) extends BitcoinCoreClient(new BasicBitcoinJsonRPCClient(UserPassword("", ""), "", 0)(sb = null)) { +class TestBitcoinCoreClient()(implicit system: ActorSystem) extends BitcoinCoreClient(new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, UserPassword("", ""), "", 0)(sb = null)) { import scala.concurrent.ExecutionContext.Implicits.global diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala index 06a311863..72c97a6df 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoinCoreClientSpec.scala @@ -22,7 +22,7 @@ import akka.testkit.TestProbe import fr.acinq.bitcoin import fr.acinq.bitcoin.psbt.{Psbt, UpdateFailure} import fr.acinq.bitcoin.scalacompat.Crypto.{PublicKey, der2compact} -import fr.acinq.bitcoin.scalacompat.{Block, BlockId, Btc, BtcDouble, Crypto, DeterministicWallet, KotlinUtils, MilliBtcDouble, MnemonicCode, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, addressFromPublicKeyScript, addressToPublicKeyScript, computeBIP84Address, computeP2PkhAddress, computeP2WpkhAddress} +import fr.acinq.bitcoin.scalacompat.{Block, BlockHash, BlockId, Btc, BtcDouble, Crypto, DeterministicWallet, KotlinUtils, MilliBtcDouble, MnemonicCode, OP_DROP, OP_PUSHDATA, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxId, TxIn, TxOut, addressFromPublicKeyScript, addressToPublicKeyScript, computeBIP84Address, computeP2PkhAddress, computeP2WpkhAddress} import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion} import fr.acinq.eclair.TestUtils.randomTxId import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse, OnChainBalance, ProcessPsbtResponse} @@ -199,6 +199,8 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A def makeEvilBitcoinClient(changePosMod: Int => Int, txMod: Transaction => Transaction): BitcoinCoreClient = { val badRpcClient = new BitcoinJsonRPCClient { + override def chainHash: BlockHash = bitcoinClient.rpcClient.chainHash + override def wallet: Option[String] = if (useEclairSigner) Some("eclair") else None override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] = method match { @@ -389,7 +391,7 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A (0 to 9).foreach { satoshi => val apiAmount = JDecimal(BigDecimal(s"0.0000000$satoshi")) - val rpcClient = new BasicBitcoinJsonRPCClient(rpcAuthMethod = UserPassword("foo", "bar"), host = "localhost", port = 0) { + val rpcClient = new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = UserPassword("foo", "bar"), host = "localhost", port = 0) { override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] = method match { case "getbalances" => Future(JObject("mine" -> JObject("trusted" -> apiAmount, "untrusted_pending" -> apiAmount)))(ec) case "getmempoolinfo" => Future(JObject("mempoolminfee" -> JDecimal(0.0002)))(ec) @@ -1775,7 +1777,7 @@ class BitcoinCoreClientWithEclairSignerSpec extends BitcoinCoreClientSpec { private def createWallet(seed: ByteVector): (BitcoinCoreClient, LocalOnChainKeyManager) = { val name = s"eclair_${seed.toHex.take(16)}" val onChainKeyManager = new LocalOnChainKeyManager(name, seed, TimestampSecond.now(), Block.RegtestGenesisBlock.hash) - val jsonRpcClient = new BasicBitcoinJsonRPCClient(rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(name)) + val jsonRpcClient = new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(name)) (new BitcoinCoreClient(jsonRpcClient, onChainKeyManager_opt = Some(onChainKeyManager)), onChainKeyManager) } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala index 417b6427d..f9bd4d797 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/bitcoind/BitcoindService.scala @@ -123,7 +123,7 @@ trait BitcoindService extends Logging { } else { UserPassword("foo", "bar") } - bitcoinrpcclient = new BasicBitcoinJsonRPCClient(rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(defaultWallet)) + bitcoinrpcclient = new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(defaultWallet)) bitcoincli = system.actorOf(Props(new Actor { override def receive: Receive = { case BitcoinReq(method) => bitcoinrpcclient.invoke(method).pipeTo(sender()) @@ -217,7 +217,7 @@ trait BitcoindService extends Logging { def createWallet(walletName: String, sender: TestProbe = TestProbe()): BitcoinJsonRPCClient = { sender.send(bitcoincli, BitcoinReq("createwallet", walletName)) sender.expectMsgType[JValue] - new BasicBitcoinJsonRPCClient(rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(walletName)) + new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(walletName)) } def getNewAddress(sender: TestProbe = TestProbe(), rpcClient: BitcoinJsonRPCClient = bitcoinrpcclient, addressType_opt: Option[String] = None): String = { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala index 5987527da..9031cf5a6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/blockchain/fee/BitcoinCoreFeeProviderSpec.scala @@ -99,7 +99,7 @@ class BitcoinCoreFeeProviderSpec extends TestKitBaseClass with BitcoindService w } private def createMockBitcoinClient(fees: Map[Int, FeeratePerKB], mempoolMinFee: FeeratePerKB): BasicBitcoinJsonRPCClient = { - new BasicBitcoinJsonRPCClient(rpcAuthMethod = UserPassword("", ""), host = "localhost", port = 0) { + new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = UserPassword("", ""), host = "localhost", port = 0) { override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] = method match { case "estimatesmartfee" => val blocks = params(0).asInstanceOf[Int] diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala index 29543194e..9acc21ad4 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/publish/ReplaceableTxPublisherSpec.scala @@ -1842,7 +1842,7 @@ class ReplaceableTxPublisherWithEclairSignerSpec extends ReplaceableTxPublisherS val entropy = ByteVector.fromValidHex("01" * 32) val seed = MnemonicCode.toSeed(MnemonicCode.toMnemonics(entropy), walletName) val keyManager = new LocalOnChainKeyManager(walletName, seed, TimestampSecond.now(), Block.RegtestGenesisBlock.hash) - val walletRpcClient = new BasicBitcoinJsonRPCClient(rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(walletName)) + val walletRpcClient = new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = bitcoinrpcauthmethod, host = "localhost", port = bitcoindRpcPort, wallet = Some(walletName)) val walletClient = new BitcoinCoreClient(walletRpcClient, onChainKeyManager_opt = Some(keyManager)) with OnchainPubkeyCache { lazy val pubkey = { getP2wpkhPubkey().pipeTo(probe.ref) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala index b5d7775a4..f15fc38ab 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/router/AnnouncementsBatchValidationSpec.scala @@ -49,7 +49,7 @@ class AnnouncementsBatchValidationSpec extends AnyFunSuite { implicit val system = ActorSystem("test") implicit val sttpBackend = OkHttpFutureBackend() - val bitcoinClient = new BitcoinCoreClient(new BasicBitcoinJsonRPCClient(rpcAuthMethod = UserPassword("foo", "bar"), host = "localhost", port = 18332)) + val bitcoinClient = new BitcoinCoreClient(new BasicBitcoinJsonRPCClient(Block.RegtestGenesisBlock.hash, rpcAuthMethod = UserPassword("foo", "bar"), host = "localhost", port = 18332)) val channels = for (i <- 0 until 50) yield { // let's generate a block every 10 txs so that we can compute short ids