1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-19 01:43:22 +01:00
eclair/docs/ManagingBitcoinCoreKeys.md
Fabrice Drouin 6f8713788c
Delegate Bitcoin Core's private key management to Eclair (#2613)
* Make Eclair manage bitcoin core's wallet private keys

We create an empty watch-only wallet and import public descriptors generated by Eclair.
Bitcoin Core can fund transaction and manage utxos, but can no longer sign transactions.

* Check that spent amounts and utxos are consistent before we sign a PSBT

PSBT utxo fields include the amount that are being spent by the PSBT inputs, but there is a "fee attack"
where using amounts that are lower than what is actually spent may make us sign a tx that spends much more
in fees than we think.

* Check that non-segwit uxto has been provided and inputs are signed with SIGHASH_ALL

* Verify that Bitcoin Core's fee match what we specified

When we call Bitcoin Core's `fundrawtransaction` RPC method, we check that the fee that we pay match the fee rate that we requested.
The fee is computed using the utxo information that Bitcoin Core adds to our PSBT before we sign it.

We can safely used this information because if Bitcoin Core lies about the value of the inputs that we're spending then the signature we produce will also not be valid (it commits to the value being spent).

When we're adding wallet inputs to "bump" the fees of a parent transaction we need to take the whole package into account when we verify the actual fee rate, which is why some internal methods were modified to return the package weight that was used as reference when `fundrawtransaction` was called.

* Check that fundrawtransaction does not add more than 1 change output

* Validate addresses and keys generated by bitcoin core

When eclair manages private keys, make sure that we can re-compute addresses and keys
generated by bitcoin core.

* Add a separate configuration file for Eclair's onchain signer

Eclair's onchain signer now has its own `eclair-signer.conf` configuration file in HOCON format.
It includes BIP39 mnemonic codes and passphrase, a wallet name and a timestamp.

When an `eclair-signer.conf` file is found, Eclair's API will return descriptors that can be imported into an
empty watch-only Bitcoin Wallet.
When wallet name in `eclair-signer.conf` matches the name of the Bitcoin Core wallet defined in `eclair.conf`
(`eclair.bitcoind.wallet`), Eclair will bypass Bitcoin Core and sign onchain transactions directly.

* Skip validation of local non-change outputs:

Local non-change outputs send to an external address, for splicing out funds for example.
We assume that these inputs are trusted i.e have been created by a trusted API call and our local
onchain key manager will not validate them during the signing process.

* Document why we use a separate, specific file for the onchain key manager

Using a new signer section is eclair.conf would be simpler but "leaks" because it becomes available everywhere
in the code through the actor system's settings instead of being contained to where it is actually needed
and could potentially be exposed through a bug that "exports" the configuration (through logs, ....)
though this is highly unlikely.

* Additional changes to delegate bitcoin core keys to eclair (#2726)

Refactor the `BitcoinCoreClient` and `LocalOnChainKeyManager` to:

- rely less on exceptions
- use more idiomatic scala (reduce dependency on kotlin types)
- provide more detailed logs

We also simplify the `useEclairSigner` field in `BitcoinCoreClient`.
The complexity of handling the case where there was an on-chain key
manager but for a different wallet than the one configured isn't
something that should be used, so it wasn't worth supporting.

Some checks were inconsistent and are now unified:

- checking the exact `scriptPubKey` in our outputs in TODO and TODO
- we allow using `fundTransaction` with a tx that already includes a
  change output (which may happen when RBF-ing a transaction)
- `getP2wpkhPubkeyHashForChange` didn't verify the returned key

We completely separate the two cases in `signPsbt`, because otherwise
in the non eclair-backed case, we were calling bitcoind's `processpsbt`
twice for no good reason, which is bad for performance.

We also decouple the `OnChainKeyManager` from the `BitcoinCoreClient`.
This lets users keep running their eclair node with a bitcoin client that
owns the private key while configuring the on-chain key manager for a
future bitcoin client that will leverage this on-chain key manager.

Users can use the eclair APIs to get the master xpub and descriptors to
properly configure their next bitcoin core node, and switch to it once it
has synchronized the descriptors.

* Simplify replaceable tx funding

We were previously signing twice (with makes a call to `bitcoind`),
just to get the final weights and adjust the change outputs. This was
unnecessary, as we can adjust the weights before adding inputs.

We were also duplicating the checks where we verify that `bitcoind` is
malicious. We only need to check that once, during the final signing step.

---------

Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
2023-09-21 15:54:28 +02:00

5.3 KiB

Using Eclair to manage your Bitcoin Core wallet's private keys

You can configure Eclair to control (and never expose) the private keys of your Bitcoin Core wallet. This feature was designed to take advantage of deployment where your Eclair node runs in a "trusted" runtime environment, but is also very useful if your Bitcoin and Eclair nodes run on different machines for example, with a setup for the Bitcoin host that is less secure than for Eclair (because it is shared among several services for example).

Configuring Eclair and Bitcoin Core to use a new Eclair-backed bitcoin wallet

Follow these steps to delegate on-chain key management to eclair:

1. Generate a BIP39 mnemonic code and passphrase

You can use any BIP39-compatible tool, including most hardware wallets.

2. Create an eclair-signer.conf configuration file add it to eclair's data directory

A signer configuration file uses the HOCON format that we already use for eclair.conf and must include the following options:

key description
eclair.signer.wallet wallet name
eclair.signer.mnemonics BIP39 mnemonic words
eclair.signer.passphrase passphrase
eclair.signer.timestamp wallet creation UNIX timestamp. Bitcoin core will rescan the blockchain from this UNIX timestamp. Set it to the wallet creation timestamp for simplicity, or a later date if you only have recent UTXOs and you know what you are doing.

This is an example of eclair-signer.conf configuration file:

{
   eclair {
      signer {
         wallet = "eclair"
         mnemonics = "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title"
         passphrase = ""
         timestamp = 1686055705
      }
   }
}

3. Use Eclair to generate descriptors and import them into a new bitcoin wallet

Restart eclair, without changing eclair.bitcoind.wallet (so it uses the default wallet or the previously used bitcoin wallet for existing nodes).

Create a new empty, decriptor-enabled wallet on your new Bitcoin Core node.

⚠️ The name must match the one that you set in eclair-signer.conf (here we use "eclair")

$ bitcoin-cli -named createwallet wallet_name=eclair disable_private_keys=true blank=true descriptors=true load_on_startup=true

Generate the descriptors with your Eclair node and import them into a Bitcoin node with the following commands:

$ eclair-cli getdescriptors | jq --raw-output -c > descriptors.json
$ cat descriptors.json | xargs -0 bitcoin-cli -rpcwallet=eclair importdescriptors

Bitcoin core will import descriptors and rescan the blockchain from the time set in eclair-signer.conf. This can take a long time (if you're moving an old existing node to a new setup for example) and your Bitcoin Core node will not be usable until it's done.

4. Configure Eclair to use the wallet you created and restart Eclair

In your eclair.conf, set eclair.bitcoind.wallet to the name of the wallet in eclair-signer.conf, and restart Eclair.

You now have a Bitcoin Core watch-only wallet for which only your Eclair node can sign transactions. This Bitcoin Core wallet can safely be copied to another Bitcoin Core node to monitor your on-chain funds.

⚠️ this means that your Bitcoin Core wallet cannot send funds on its own (since it cannot access private keys to sign transactions). To send funds on-chain you must use eclair-cli sendonchain.

⚠️ to backup the private keys of this wallet you must either backup your mnemonic code and passphrase, or backup the eclair-signer.conf file in your eclair directory (default is ~/.eclair) along with your channels and node seed files.

⚠️ You can also initialize a backup on-chain wallet with the same mnemonic code and passphrase (on a hardware wallet for example), but be warned that using them may interfere with your node's operations (for example you may end up double-spending funding transactions generated by your node).

You can also use eclair-cli getmasterxpub to get a BIP32 extended public key that you can import into any compatible Bitcoin wallet to create a watch-only wallet (Electrum for example) that you can use to monitor your Bitcoin Core balance.