docs: add PSBT funding tutorial
This commit is contained in:
parent
c4f20dada4
commit
2f371556da
216
docs/psbt.md
Normal file
216
docs/psbt.md
Normal file
@ -0,0 +1,216 @@
|
||||
# PSBT
|
||||
|
||||
This document describes various use cases around the topic of Partially Signed
|
||||
Bitcoin Transactions (PSBTs). Currently only channel funding is possible with
|
||||
PSBTs but more features are planned.
|
||||
|
||||
See [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) for
|
||||
a full description of the PSBT format and the different _roles_ that a
|
||||
participant in a PSBT can have.
|
||||
|
||||
## Opening a channel by using a PSBT
|
||||
|
||||
This is a step-by-step guide on how to open a channel with `lnd` by using a PSBT
|
||||
as the funding transaction.
|
||||
We will use `bitcoind` to create and sign the transaction just to keep the
|
||||
example simple. Of course any other PSBT compatible wallet could be used and the
|
||||
process would likely be spread out over multiple signing steps. The goal of this
|
||||
example is not to cover each and every possible edge case but to help users of
|
||||
`lnd` understand what inputs the `lncli` utility expects.
|
||||
|
||||
The goal is to open a channel of 1'234'567 satoshis to the node
|
||||
`03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac` by using
|
||||
a PSBT. That means, `lnd` can have a wallet balance of `0` and is still able to
|
||||
open a channel. We'll jump into an example right away.
|
||||
|
||||
The new funding flow has a small caveat: _Time matters_.
|
||||
|
||||
When opening a channel using the PSBT flow, we start the negotiation
|
||||
with the remote peer immediately so we can obtain their multisig key they are
|
||||
going to use for the channel. Then we pause the whole process until we get a
|
||||
fully signed transaction back from the user. Unfortunately there is no reliable
|
||||
way to know after how much time the remote node starts to clean up and "forgets"
|
||||
about the pending channel. If the remote node is an `lnd` node, we know it's
|
||||
after 10 minutes. **So as long as the whole process takes less than 10 minutes,
|
||||
everything should work fine.**
|
||||
|
||||
### 1. Use the new `--psbt` flag in `lncli openchannel`
|
||||
|
||||
The new `--psbt` flag in the `openchannel` command starts an interactive dialog
|
||||
between `lncli` and the user. Below the command you see an example output from
|
||||
a regtest setup. Of course all values will be different.
|
||||
|
||||
```bash
|
||||
$ lncli openchannel --node_key 03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac --local_amt 1234567 --psbt
|
||||
|
||||
Starting PSBT funding flow with pending channel ID fc7853889a04d33b8115bd79ebc99c5eea80d894a0bead40fae5a06bcbdccd3d.
|
||||
PSBT funding initiated with peer 03db1e56e5f76bc4018cf6f03d1bb98a7ae96e3f18535e929034f85e7f1ca2b8ac.
|
||||
Please create a PSBT that sends 0.01234567 BTC (1234567 satoshi) to the funding address bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q.
|
||||
|
||||
Example with bitcoind:
|
||||
bitcoin-cli walletcreatefundedpsbt [] '[{"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q":0.01234567}]'
|
||||
|
||||
Or if you are using a wallet that can fund a PSBT directly (currently not
|
||||
possible with bitcoind), you can use this PSBT that contains the same address
|
||||
and amount: cHNidP8BADUCAAAAAAGH1hIAAAAAACIAILxii7ESlHKdKpP5ZGFqcxiUIudUZBuSedTcB2+geh4fAAAAAAAA
|
||||
|
||||
Paste the funded PSBT here to continue the funding flow.
|
||||
Base64 encoded PSBT:
|
||||
```
|
||||
|
||||
The command line now waits until a PSBT is entered. We'll create one in the next
|
||||
step. Make sure to use a new shell window/tab for the next commands and leave
|
||||
the prompt from the `openchannel` running as is.
|
||||
|
||||
### 2. Use `bitcoind` to create a funding transaction
|
||||
|
||||
The output of the last command already gave us an example command to use with
|
||||
`bitcoind`. We'll go ahead and execute it now. The meaning of this command is
|
||||
something like "bitcoind, give me a PSBT that sends the given amount to the
|
||||
given address, choose any input you see fit":
|
||||
|
||||
```bash
|
||||
$ bitcoin-cli walletcreatefundedpsbt [] '[{"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q":0.01234567}]'
|
||||
|
||||
{
|
||||
"psbt": "cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA",
|
||||
"fee": 0.00003060,
|
||||
"changepos": 1
|
||||
}
|
||||
```
|
||||
|
||||
We see that `bitcoind` has given us a transaction that would pay `3060` satoshi
|
||||
in fees. Fee estimation/calculation can be changed with parameters of the
|
||||
`walletcreatefundedpsbt` command. To see all options, use
|
||||
`bitcoin-cli help walletcreatefundedpsbt`.
|
||||
|
||||
If we want to know what exactly is in this PSBT, we can look at it with the
|
||||
`decodepsbt` command:
|
||||
|
||||
```bash
|
||||
$ bitcoin-cli decodepsbt cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
|
||||
|
||||
{
|
||||
"tx": {
|
||||
"txid": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a",
|
||||
"hash": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a",
|
||||
"version": 2,
|
||||
"size": 125,
|
||||
"vsize": 125,
|
||||
"weight": 500,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "3ff673717cfb451658e260ecacc6e9cb39112e0440bd5e7cea87017eff2d4bbc",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01234567,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 bc628bb11294729d2a93f964616a73189422e754641b9279d4dc076fa07a1e1f",
|
||||
"hex": "0020bc628bb11294729d2a93f964616a73189422e754641b9279d4dc076fa07a1e1f",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_scripthash",
|
||||
"addresses": [
|
||||
"bcrt1qh33ghvgjj3ef625nl9jxz6nnrz2z9e65vsdey7w5msrklgr6rc0sv0s08q"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 48.98759093,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 bfba4c71068726c99ce9051924456ed09c3ce1bc",
|
||||
"hex": "0014bfba4c71068726c99ce9051924456ed09c3ce1bc",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"bcrt1qh7aycugxsunvn88fq5vjg3tw6zwrecduvvgre5"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 48.99996720,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 77a6275d5717b094ed65c12092c3fea645fba8eb",
|
||||
"hex": "001477a6275d5717b094ed65c12092c3fea645fba8eb",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "bcrt1qw7nzwh2hz7cffmt9cysf9sl75ezlh28tzl4n4e"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
}
|
||||
],
|
||||
"fee": 0.00003060
|
||||
}
|
||||
```
|
||||
|
||||
This tells us that we got a PSBT with a big input, the channel output and a
|
||||
change output for the rest. Everything is there but the signatures/witness data,
|
||||
which is exactly what we need.
|
||||
|
||||
### 3. Verify and sign the PSBT
|
||||
|
||||
Now that we have a valid PSBT that has everything but the final
|
||||
signatures/witness data, we can paste it into the prompt in `lncli` that is
|
||||
still waiting for our input.
|
||||
|
||||
```bash
|
||||
...
|
||||
Base64 encoded PSBT: cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
|
||||
|
||||
PSBT verified by lnd, please continue the funding flow by signing the PSBT by
|
||||
all required parties/devices. Once the transaction is fully signed, paste it
|
||||
again here.
|
||||
|
||||
Base64 encoded PSBT:
|
||||
```
|
||||
|
||||
We can now go ahead and sign the transaction. We are going to use `bitcoind` for
|
||||
this again, but in practice this would now happen on a hardware wallet and
|
||||
perhaps `bitcoind` would only know the public keys and couldn't sign for the
|
||||
transaction itself. Again, this is only an example and can't reflect all
|
||||
real-world use cases.
|
||||
|
||||
```bash
|
||||
$ bitcoin-cli walletprocesspsbt cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAAAA
|
||||
|
||||
{
|
||||
"psbt": "cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAQhrAkcwRAIgHKQbenZYvgADRd9TKGVO36NnaIgW3S12OUg8XGtSrE8CICmeaYoJ/U7Ecm+/GneY8i2hu2QCaQnuomJgzn+JAnrDASEDUBmCLcsybA5qXSRBBdZ0Uk/FQiay9NgOpv4D26yeJpAAAAA=",
|
||||
"complete": true
|
||||
}
|
||||
```
|
||||
|
||||
Interpreting the output, we now have a complete, final, and signed transaction
|
||||
inside the PSBT. Let's give it to `lncli` to continue:
|
||||
|
||||
```bash
|
||||
...
|
||||
Base64 encoded PSBT: cHNidP8BAH0CAAAAAbxLLf9+AYfqfF69QAQuETnL6cas7GDiWBZF+3xxc/Y/AAAAAAD+////AofWEgAAAAAAIgAgvGKLsRKUcp0qk/lkYWpzGJQi51RkG5J51NwHb6B6Hh+1If0jAQAAABYAFL+6THEGhybJnOkFGSRFbtCcPOG8AAAAAAABAR8wBBAkAQAAABYAFHemJ11XF7CU7WXBIJLD/qZF+6jrAQhrAkcwRAIgHKQbenZYvgADRd9TKGVO36NnaIgW3S12OUg8XGtSrE8CICmeaYoJ/U7Ecm+/GneY8i2hu2QCaQnuomJgzn+JAnrDASEDUBmCLcsybA5qXSRBBdZ0Uk/FQiay9NgOpv4D26yeJpAAAAA=
|
||||
{
|
||||
"funding_txid": "374504e4246a93a45b4a2c2bc31d8adc8525aa101c7b9065db6dc01c4bdfce0a"
|
||||
}
|
||||
```
|
||||
|
||||
Success! We now have the final transaction ID of the published funding
|
||||
transaction. Now we only have to wait for some confirmations, then we can start
|
||||
using the freshly created channel.
|
Loading…
Reference in New Issue
Block a user