lnd.xprv/docs/psbt.md
2020-03-31 10:00:12 +02:00

9.0 KiB

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 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.

$ 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":

$ 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:

$ 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.

...
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.

$ 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:

...
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.