From 99eb7c63329e8c04d7c3d5b4931524e9df0d1cfa Mon Sep 17 00:00:00 2001 From: t-bast Date: Thu, 24 Sep 2020 14:35:17 +0200 Subject: [PATCH 1/4] Don't swallow bitcoind exceptions We wrap these exceptions but preserve the original one. --- eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala | 8 ++++---- .../src/main/scala/fr/acinq/eclair/gui/FxApp.scala | 2 +- 2 files changed, 5 insertions(+), 5 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 b4572081e3..a48c8a68f1 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -145,9 +145,9 @@ class Setup(datadir: File, host = config.getString("bitcoind.host"), port = config.getInt("bitcoind.rpcport")) val future = for { - json <- bitcoinClient.invoke("getblockchaininfo").recover { case _ => throw BitcoinRPCConnectionException } + json <- bitcoinClient.invoke("getblockchaininfo").recover { case e => throw BitcoinRPCConnectionException(e) } // Make sure wallet support is enabled in bitcoind. - _ <- bitcoinClient.invoke("getbalance").recover { case _ => throw BitcoinWalletDisabledException } + _ <- bitcoinClient.invoke("getbalance").recover { case e => throw BitcoinWalletDisabledException(e) } progress = (json \ "verificationprogress").extract[Double] ibd = (json \ "initialblockdownload").extract[Boolean] blocks = (json \ "blocks").extract[Long] @@ -396,9 +396,9 @@ object Kit { case object BitcoinZMQConnectionTimeoutException extends RuntimeException("could not connect to bitcoind using zeromq") -case object BitcoinRPCConnectionException extends RuntimeException("could not connect to bitcoind using json-rpc") +case class BitcoinRPCConnectionException(e: Throwable) extends RuntimeException("could not connect to bitcoind using json-rpc", e) -case object BitcoinWalletDisabledException extends RuntimeException("bitcoind must have wallet support enabled") +case class BitcoinWalletDisabledException(e: Throwable) extends RuntimeException("bitcoind wallet not available", e) case object EmptyAPIPasswordException extends RuntimeException("must set a password for the json-rpc api") diff --git a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala index 892d331072..733b10e0e9 100644 --- a/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala +++ b/eclair-node-gui/src/main/scala/fr/acinq/eclair/gui/FxApp.scala @@ -52,7 +52,7 @@ class FxApp extends Application with Logging { def onError(t: Throwable): Unit = t match { case e@TCPBindException(port) => notifyPreloader(new ErrorNotification("Setup", s"Could not bind to port $port", e)) - case e@BitcoinRPCConnectionException => + case e: BitcoinRPCConnectionException => notifyPreloader(new ErrorNotification("Setup", "Could not connect to Bitcoin Core using JSON-RPC.", e)) notifyPreloader(new AppNotification(InfoAppNotification, "Make sure that Bitcoin Core is up and running and RPC parameters are correct.")) case e@BitcoinZMQConnectionTimeoutException => From 30fa0f0d9119985f4e305f12d1501487fffe7736 Mon Sep 17 00:00:00 2001 From: t-bast Date: Thu, 24 Sep 2020 16:27:42 +0200 Subject: [PATCH 2/4] Allow configuring bitcoin core wallet It makes sense to allow users to use a different wallet from the default one. There's one important caveat: once set, users shouldn't change it while they have open channels. We mention it clearly in the documentation. --- README.md | 14 ++++++++++---- eclair-core/src/main/resources/reference.conf | 4 ++++ .../src/main/scala/fr/acinq/eclair/Setup.scala | 7 ++++++- .../bitcoind/rpc/BasicBitcoinJsonRPCClient.scala | 10 +++++++--- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 2ab14add81..fa9aedfe50 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,19 @@ You will find detailed guides and frequently asked questions there. ### Configuring Bitcoin Core -:warning: Eclair requires Bitcoin Core 0.18.1, 0.19.1 or 0.20.1. If you are upgrading an existing wallet, you need to create a new address and send all your funds to that address. +:warning: Eclair requires Bitcoin Core 0.18.1, 0.19.1 or 0.20.1. If you are upgrading an existing wallet, you may need to create a new address and send all your funds to that address. Eclair needs a _synchronized_, _segwit-ready_, **_zeromq-enabled_**, _wallet-enabled_, _non-pruning_, _tx-indexing_ [Bitcoin Core](https://github.com/bitcoin/bitcoin) node. -Eclair will use any BTC it finds in the default Bitcoin Core wallet to fund any channels you choose to open. Eclair will return BTC from closed channels to this wallet. You can have multiple Bitcoin Core wallets but make sure that the default one is always available. -Any BTC found in the wallet can be used to fund the channels you choose to open and the BTC from closed channels will return to this wallet. + +Eclair will use the default loaded Bitcoin Core wallet to fund any channels you choose to open. +If you want to use a different wallet from the default one, you must set `eclair.bitcoind.wallet` accordingly in your `eclair.conf`. + +:warning: once a wallet is configured, you must be very careful if you want to change it: changing the wallet when you have channels open may result in a loss of funds (or a complex recovery procedure). + +Eclair will return BTC from closed channels to the wallet configured. +Any BTC found in the wallet can be used to fund the channels you choose to open. You can configure your Bitcoin Node to use either `p2sh-segwit` addresses or `bech32` addresses, Eclair is compatible with both modes. -If your Bitcoin Core wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit` or `bech32`), you must send them to a `p2sh-segwit` or `bech32` address. +If your wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit` or `bech32`), you must send them to a `p2sh-segwit` or `bech32` address. Run bitcoind with the following minimal `bitcoin.conf`: diff --git a/eclair-core/src/main/resources/reference.conf b/eclair-core/src/main/resources/reference.conf index 80bc4d0ccf..046dbe4e82 100644 --- a/eclair-core/src/main/resources/reference.conf +++ b/eclair-core/src/main/resources/reference.conf @@ -27,6 +27,10 @@ eclair { rpcport = 8332 rpcuser = "foo" rpcpassword = "bar" + // Name of the bitcoind wallet that should be used to fund channels. + // Once set you should NOT change it if your node has channels open, otherwise you may lose funds. + // NB: leave empty to automatically select the default loaded wallet. + wallet = "" zmqblock = "tcp://127.0.0.1:29000" zmqtx = "tcp://127.0.0.1:29000" } 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 a48c8a68f1..b420ae8daa 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/Setup.scala @@ -139,11 +139,16 @@ class Setup(datadir: File, val bitcoin = nodeParams.watcherType match { case BITCOIND => + val wallet = { + val name = config.getString("bitcoind.wallet") + if (!name.isBlank) Some(name) else None + } val bitcoinClient = new BasicBitcoinJsonRPCClient( user = config.getString("bitcoind.rpcuser"), password = config.getString("bitcoind.rpcpassword"), host = config.getString("bitcoind.host"), - port = config.getInt("bitcoind.rpcport")) + port = config.getInt("bitcoind.rpcport"), + wallet = wallet) val future = for { json <- bitcoinClient.invoke("getblockchaininfo").recover { case e => throw BitcoinRPCConnectionException(e) } // Make sure wallet support is enabled in bitcoind. 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 c74b958735..b3d2cc336c 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 @@ -21,13 +21,13 @@ import com.softwaremill.sttp.json4s._ import fr.acinq.bitcoin.ByteVector32 import fr.acinq.eclair.KamonExt import fr.acinq.eclair.blockchain.Monitoring.{Metrics, Tags} -import org.json4s.{CustomSerializer, DefaultFormats} import org.json4s.JsonAST.{JString, JValue} import org.json4s.jackson.Serialization +import org.json4s.{CustomSerializer, DefaultFormats} import scala.concurrent.{ExecutionContext, Future} -class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false)(implicit http: SttpBackend[Future, Nothing]) extends BitcoinJsonRPCClient { +class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = "127.0.0.1", port: Int = 8332, ssl: Boolean = false, wallet: Option[String] = None)(implicit http: SttpBackend[Future, Nothing]) extends BitcoinJsonRPCClient { // necessary to properly serialize ByteVector32 into String readable by bitcoind object ByteVector32Serializer extends CustomSerializer[ByteVector32](_ => ( { @@ -35,9 +35,13 @@ class BasicBitcoinJsonRPCClient(user: String, password: String, host: String = " }, { case x: ByteVector32 => JString(x.toHex) })) + implicit val formats = DefaultFormats.withBigDecimal + ByteVector32Serializer private val scheme = if (ssl) "https" else "http" - private val serviceUri = uri"$scheme://$host:$port/wallet/" // wallet/ specifies to use the default bitcoind wallet, named "" + private val serviceUri = wallet match { + case Some(name) => uri"$scheme://$host:$port/wallet/$name" + case None => uri"$scheme://$host:$port" + } implicit val serialization = Serialization override def invoke(method: String, params: Any*)(implicit ec: ExecutionContext): Future[JValue] = From ba9da7fe87223cad6f458d114145726ca2323d0c Mon Sep 17 00:00:00 2001 From: t-bast Date: Mon, 28 Sep 2020 09:50:38 +0200 Subject: [PATCH 3/4] Add bitcoin core wallet section in README --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fa9aedfe50..f3f57b84f8 100644 --- a/README.md +++ b/README.md @@ -45,15 +45,8 @@ You will find detailed guides and frequently asked questions there. Eclair needs a _synchronized_, _segwit-ready_, **_zeromq-enabled_**, _wallet-enabled_, _non-pruning_, _tx-indexing_ [Bitcoin Core](https://github.com/bitcoin/bitcoin) node. -Eclair will use the default loaded Bitcoin Core wallet to fund any channels you choose to open. -If you want to use a different wallet from the default one, you must set `eclair.bitcoind.wallet` accordingly in your `eclair.conf`. - -:warning: once a wallet is configured, you must be very careful if you want to change it: changing the wallet when you have channels open may result in a loss of funds (or a complex recovery procedure). - -Eclair will return BTC from closed channels to the wallet configured. -Any BTC found in the wallet can be used to fund the channels you choose to open. -You can configure your Bitcoin Node to use either `p2sh-segwit` addresses or `bech32` addresses, Eclair is compatible with both modes. -If your wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit` or `bech32`), you must send them to a `p2sh-segwit` or `bech32` address. +You can configure your Bitcoin node to use either `p2sh-segwit` addresses or `bech32` addresses, Eclair is compatible with both modes. +If your wallet has "non-segwit UTXOs" (outputs that are neither `p2sh-segwit` or `bech32`), you must send them to a `p2sh-segwit` or `bech32` address before running eclair. Run bitcoind with the following minimal `bitcoin.conf`: @@ -106,11 +99,22 @@ name | description eclair.bitcoind.rpcpassword | Bitcoin Core RPC password | bar eclair.bitcoind.zmqblock | Bitcoin Core ZMQ block address | "tcp://127.0.0.1:29000" eclair.bitcoind.zmqtx | Bitcoin Core ZMQ tx address | "tcp://127.0.0.1:29000" + eclair.bitcoind.wallet | Bitcoin Core wallet name | "" Quotes are not required unless the value contains special characters. Full syntax guide [here](https://github.com/lightbend/config/blob/master/HOCON.md). → see [`reference.conf`](eclair-core/src/main/resources/reference.conf) for full reference. There are many more options! +#### Configure Bitcoin Core wallet + +Eclair will use the default loaded Bitcoin Core wallet to fund any channels you choose to open. +If you want to use a different wallet from the default one, you must set `eclair.bitcoind.wallet` accordingly in your `eclair.conf`. + +:warning: once a wallet is configured, you must be very careful if you want to change it: changing the wallet when you have channels open may result in a loss of funds (or a complex recovery procedure). + +Eclair will return BTC from closed channels to the wallet configured. +Any BTC found in the wallet can be used to fund the channels you choose to open. + #### Java Environment Variables Some advanced parameters can be changed with java environment variables. Most users won't need this and can skip this section. From 2073537c310a6e23134eda8b8a7670a367091381 Mon Sep 17 00:00:00 2001 From: t-bast Date: Mon, 28 Sep 2020 11:47:56 +0200 Subject: [PATCH 4/4] fixup! Add bitcoin core wallet section in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f3f57b84f8..099395a6e6 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Quotes are not required unless the value contains special characters. Full synta Eclair will use the default loaded Bitcoin Core wallet to fund any channels you choose to open. If you want to use a different wallet from the default one, you must set `eclair.bitcoind.wallet` accordingly in your `eclair.conf`. -:warning: once a wallet is configured, you must be very careful if you want to change it: changing the wallet when you have channels open may result in a loss of funds (or a complex recovery procedure). +:warning: Once a wallet is configured, you must be very careful if you want to change it: changing the wallet when you have channels open may result in a loss of funds (or a complex recovery procedure). Eclair will return BTC from closed channels to the wallet configured. Any BTC found in the wallet can be used to fund the channels you choose to open.