From a230395f5f398043068c49a15b2c679770455e89 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Wed, 30 Nov 2022 15:44:40 +0100 Subject: [PATCH] Test change address type generation (#2513) Starting with bitcoind 23.0, a new `changetype` parameter was introduced. If not specified, bitcoind will generate a change output with a type that matches the main output to make it harder for chain analysis to detect which output is the change. The issue is that lightning requires segwit utxos: if an on-chain payment is sent to a non-segwit address, we still want our change output to use segwit, otherwise we won't be able to use it. We thus must set `addresstype` and `changetype` in `bitcoin.conf` to ensure we never generate legacy change addresses. --- README.md | 6 +++++- docs/Configure.md | 6 ++++-- .../bitcoind/BitcoinCoreClientSpec.scala | 19 ++++++++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6dae3b284..3ed77a074 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ This means that instead of re-implementing them, Eclair benefits from the verifi :warning: This also means that Eclair has strong requirements on how your Bitcoin Core node is configured (see below), and that you must back up your Bitcoin Core wallet as well as your Eclair node (see [here](#configure-bitcoin-core-wallet)): * Eclair needs a _synchronized_, _segwit-ready_, **_zeromq-enabled_**, _wallet-enabled_, _non-pruning_, _tx-indexing_ [Bitcoin Core](https://github.com/bitcoin/bitcoin) node. -* You must configure your Bitcoin node to use `bech32` (segwit) addresses. If your wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit` or `bech32`), you must send them to a `bech32` address before running Eclair. +* You must configure your Bitcoin node to use `bech32` or `bech32m` (segwit) addresses. If your wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit`, `bech32` or `bech32m`), you must send them to a `bech32` or `bech32m` address before running Eclair. * Eclair requires Bitcoin Core 23.0 or higher. If you are upgrading an existing wallet, you may need to create a new address and send all your funds to that address. Run bitcoind with the following minimal `bitcoin.conf`: @@ -70,6 +70,8 @@ server=1 rpcuser=foo rpcpassword=bar txindex=1 +addresstype=bech32 +changetype=bech32 zmqpubhashblock=tcp://127.0.0.1:29000 zmqpubrawtx=tcp://127.0.0.1:29000 ``` @@ -280,6 +282,8 @@ so you can easily run your Bitcoin node on both mainnet and testnet. For example ```conf server=1 txindex=1 +addresstype=bech32 +changetype=bech32 [main] rpcuser= diff --git a/docs/Configure.md b/docs/Configure.md index d172cb03c..3e3626610 100644 --- a/docs/Configure.md +++ b/docs/Configure.md @@ -33,6 +33,7 @@ Values do not need to be surrounded by quotes, except if they contain special ch ### Changing the data directory You can change the data directory with the `eclair.datadir` parameter: + ```sh eclair-node.sh -Declair.datadir="/path/to/custom/eclair/data/folder" ``` @@ -41,7 +42,7 @@ eclair-node.sh -Declair.datadir="/path/to/custom/eclair/data/folder" Note that HOCON allows you to have files include other files. This allows you to split your configuration file into several logical files, for easier management. For example, you could define a file `routing.conf` file with parameters -related to routing configuration, and include it from `eclair.conf`. +related to routing configuration, and include it from `eclair.conf`. ## Options reference @@ -234,13 +235,14 @@ You'll also have to make sure the node is accessible from the outside world (por ### Bitcoin Core cookie authentication -If you run Eclair and Bitcoin on the same computer an alternative way to handle the Bitcoin Core RPC authentication +If you run Eclair and Bitcoin on the same computer an alternative way to handle the Bitcoin Core RPC authentication. is to use the safecookie. To use safecookie authentication, you need to remove `rpcpassword=***` and `rpcuser=***` from your `bitcoin.conf` and add the following to `eclair.conf`: ```conf eclair.bitcoind.auth = "safecookie" eclair.bitcoind.cookie = "PATH TO THE COOKIE FILE" ``` + Setting `eclair.bitcoind.cookie` might not be necessary if Bitcoin is running on mainnet and using the default datadir. Eclair will need read access to Bitcoin Core's cookie file. 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 fd0395506..6e819b1a2 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 @@ -21,7 +21,7 @@ import akka.pattern.pipe import akka.testkit.TestProbe import fr.acinq.bitcoin import fr.acinq.bitcoin.scalacompat.Crypto.PublicKey -import fr.acinq.bitcoin.scalacompat.{Block, Btc, BtcDouble, ByteVector32, MilliBtcDouble, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, computeP2WpkhAddress} +import fr.acinq.bitcoin.scalacompat.{Block, Btc, BtcDouble, ByteVector32, MilliBtcDouble, OutPoint, Satoshi, SatoshiLong, Script, ScriptWitness, Transaction, TxIn, TxOut, computeP2PkhAddress, computeP2WpkhAddress} import fr.acinq.bitcoin.{Bech32, SigHash, SigVersion} import fr.acinq.eclair.blockchain.OnChainWallet.{FundTransactionResponse, MakeFundingTxResponse, OnChainBalance, SignTransactionResponse} import fr.acinq.eclair.blockchain.WatcherSpec.{createSpendManyP2WPKH, createSpendP2WPKH} @@ -961,4 +961,21 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A assert(Btc(receivedAmount.values).toMilliBtc == amount) } + test("generate segwit change outputs") { + val sender = TestProbe() + val bitcoinClient = new BitcoinCoreClient(bitcoinrpcclient) + + // Even when we pay a legacy address, our change output must use segwit, otherwise it won't be usable for lightning channels. + val pubKey = randomKey().publicKey + val legacyAddress = computeP2PkhAddress(pubKey, Block.RegtestGenesisBlock.hash) + bitcoinClient.sendToAddress(legacyAddress, 150_000 sat, 1).pipeTo(sender.ref) + val txId = sender.expectMsgType[ByteVector32] + bitcoinClient.getTransaction(txId).pipeTo(sender.ref) + val tx = sender.expectMsgType[Transaction] + // We have a change output. + assert(tx.txOut.length == 2) + assert(tx.txOut.count(txOut => txOut.publicKeyScript == Script.write(Script.pay2pkh(pubKey))) == 1) + assert(tx.txOut.count(txOut => Script.isNativeWitnessScript(txOut.publicKeyScript)) == 1) + } + } \ No newline at end of file