From f22625f734bc302bdb65d7a19d62300806d8689f Mon Sep 17 00:00:00 2001 From: Brandon Odiwuor Date: Tue, 29 Aug 2023 14:59:14 +0300 Subject: [PATCH] Add offline signing tutorial --- doc/README.md | 1 + doc/offline-signing-tutorial.md | 193 ++++++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 doc/offline-signing-tutorial.md diff --git a/doc/README.md b/doc/README.md index c570432aa4d79b..446684b4821ea1 100644 --- a/doc/README.md +++ b/doc/README.md @@ -79,6 +79,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th - [Init Scripts (systemd/upstart/openrc)](init.md) - [Managing Wallets](managing-wallets.md) - [Multisig Tutorial](multisig-tutorial.md) +- [Offline Signing Tutorial](offline-signing-tutorial.md) - [P2P bad ports definition and list](p2p-bad-ports.md) - [PSBT support](psbt.md) - [Reduce Memory](reduce-memory.md) diff --git a/doc/offline-signing-tutorial.md b/doc/offline-signing-tutorial.md new file mode 100644 index 00000000000000..e4f23c19994684 --- /dev/null +++ b/doc/offline-signing-tutorial.md @@ -0,0 +1,193 @@ +# Offline Signing Tutorial + +Welcome to this tutorial on how to sign transactions offline using PSBT (Partially Signed Bitcoin Transactions). This tutorial will guide you through the process of securely signing Bitcoin transactions using an offline wallet and an online watch-only wallet. + +## Overview +In this tutorial, we have two hosts: [offline] which is totally offline and without a copy of the blockchain and [online] which is a regular online node, both running Bitcoin 25.0 + +In this example, we are going to create an `offline_wallet` on the [offline] host. We will then create a `watch_only_wallet` on the [online] host using descriptors imported from the `offline_wallet` and load funds to the wallet. we'll create a PSBT transaction using the `watch_only_wallet`, sign it with the `offline_wallet` then broadcast the transaction using the [online] host + +### Requirements +- [jq](https://jqlang.github.io/jq/) installation - This tutorial uses jq to process JSON. + +> [!NOTE] +> Tested using Signet with a connected host machine and an offline docker container (representing the offline wallet) both running Signet, should also work with Regtest and Mainnet + +### Create and Prepare the `offline_wallet` + +1. On the offline machine, create an offline wallet named `offline_wallet`. + +```sh +[offline]$ ./src/bitcoin-cli -signet -named createwallet wallet_name="offline_wallet" +{ + "name": "offline_wallet" +} +``` + +2. Export the offline wallet descriptors to a JSON file named `descriptors.json`. + +```sh +[offline]$ ./src/bitcoin-cli -signet -rpcwallet="offline_wallet" listdescriptors | jq -r '.descriptors' >> /path/to/descriptors.json +``` + +> [!NOTE] +> The `descriptors.json` file will be exported to the online machine (e.g. using a USB) to create a watch-only wallet. (This is an easier way to export the descriptors compared to manual export) + +### Create the online `watch_only_wallet` + +1. On the online machine, create an online watch-only wallet named `watch_only_wallet` without private keys (disable_private_keys=true) and should be blank with no keys or HD seed (blank=true). +- The `watch_only_wallet` wallet will be used to track transactions received to the `offline_wallet` and for creating PSBT transactions. + +```sh +[online]$ ./src/bitcoin-cli -signet -named createwallet wallet_name="watch_only_wallet" disable_private_keys=true blank=true +{ + "name": "watch_only_wallet" +} +``` + +2. Import the `offline_wallet` descriptors to the online `watch_only_wallet` using the `descriptors.json` file created on the offline wallet + +```sh +[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" importdescriptors "$(cat /path/to/descriptors.json)" +[ + { + "success": true + }, + { + "success": true + }, + { + "success": true + }, + { + "success": true + }, + { + "success": true + }, + { + "success": true + }, + { + "success": true + }, + { + "success": true + } +] +``` +> [!NOTE] +> Importing the multiple descriptors from the `offline_wallet` provides the ability to generate a variety of address types by the [online] `watch_only_wallets` + +### Load Funds to the `offline_wallet` +1. Generate an address for the `offline_wallet` using the `watch_only_wallet` to load funds. + +```sh +[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getnewaddress +tb1qtu5qgc6ddhmqm5yqjvhg83qgk2t4ewajg0h6yh +``` + +2. Visit a faucet like https://signet.bc-2.jp to load funds into the generated address. + +3. Confirm the received funds (to the offline_wallet) using the online watch_only_wallet. +```sh +[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" listunspent +[ + { + "txid": "0f3953dfc3eb8e753cd1633151837c5b9953992914ff32b7de08c47f1f29c762", + "vout": 1, + "address": "tb1qtu5qgc6ddhmqm5yqjvhg83qgk2t4ewajg0h6yh", + "label": "", + "scriptPubKey": "00145f2804634d6df60dd080932e83c408b2975cbbb2", + "amount": 0.01000000, + "confirmations": 4, + "spendable": true, + "solvable": true, + "desc": "wpkh([306c734f/84h/1h/0h/0/0]025932ccee7590158f7e08bb36290d135d30a0b045163da896e1cd7645ec4223a9)#xytvyr4a", + "parent_descs": [ + "wpkh([306c734f/84h/1h/0h]tpubDCJnY92ib4Zu3qd6wrBXEjG436tQdA2tDiJU2iSJYjkNS1darssPWKaBfojhjUF5vMLBcxbN2r93pmFMz2zyTEZuNx9JDo9rWqoHhATW3Uz/0/*)#7mh08dkg" + ], + "safe": true + } +] +``` + +### Create and Export a PSBT Transaction + +1. Create a PSBT transaction using the online `watch_only_wallet`, sending funds to the `online_receiving_wallet` address. (`walletcreatefundedpsbt inputs[], outputs[address: amount]`) +- Export the psbt transaction to `funded_psbt.txt` for easy portability to the `offline_wallet` + +```sh +[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" walletcreatefundedpsbt '[]' '[{"tb1q9k5w0nhnhyeh78snpxh0t5t7c3lxdeg3erez32": 0.009}]' | jq -r '.psbt' >> /path/to/funded_psbt.txt +[online]$ cat /path/to/funded_psbt.txt +cHNidP8BAHECAAAAAWLHKR9/xAjetzL/FCmZU5lbfINRMWPRPHWO68PfUzkPAQAAAAD9////AoA4AQAAAAAAFgAULajnzvO5M38eEwmu9dF+xH5m5RGs0g0AAAAAABYAFMaT0f/Wp2DCZzL6dkJ3GhWj4Y9vAAAAAAABAHECAAAAAY+dRPEBrGopkw4ugSzS9npzJDEIrE/bq1XXI0KbYnYrAQAAAAD+////ArKaXgAAAAAAFgAUwEc4LdoxSjbWo/2Ue+HS+QjwfiBAQg8AAAAAABYAFF8oBGNNbfYN0ICTLoPECLKXXLuyYW8CAAEBH0BCDwAAAAAAFgAUXygEY01t9g3QgJMug8QIspdcu7IiBgJZMszudZAVj34IuzYpDRNdMKCwRRY9qJbhzXZF7EIjqRgwbHNPVAAAgAEAAIAAAACAAAAAAAAAAAAAACICA7BlBnyAR4F2UkKuSX9MFhYCsn6j//z9i7lHDm1O0CU0GDBsc09UAACAAQAAgAAAAIABAAAAAAAAAAA= +``` + +### Decode and Analyze the PSBT Transaction + +1. Decode and analyze the PSBT transaction on the `offline_wallet` using the `funded_psbt.txt` file. + +```sh +[offline]$ ./src/bitcoin-cli -signet decodepsbt $(cat /path/to/funded_psbt.txt) +{ + ... +} +[offline]$ ./src/bitcoin-cli -signet analyzepsbt $(cat /path/to/funded_psbt.txt) +{ + "inputs": [ + { + "has_utxo": true, + "is_final": false, + "next": "signer", + "missing": { + "signatures": [ + "5f2804634d6df60dd080932e83c408b2975cbbb2" + ] + } + } + ], + "estimated_vsize": 141, + "estimated_feerate": 0.00100000, + "fee": 0.00014100, + "next": "signer" +} +``` + +### Process and Sign the PSBT Transaction + +1. Process, Sign and Finalize the PSBT transaction on the `offline_wallet`. +- Save the final PSBT hex to the `final_psbt.txt` file, to be exported and broadcasted by the `online_wallet` + +```sh +[offline]$ ./src/bitcoin-cli -signet -rpcwallet="offline_wallet" walletprocesspsbt $(cat /path/to/funded_psbt.txt) | jq -r .hex >> /path/to/final_psbt.txt + +[offline]$ cat ~/final_psbt.txt +0200000000010162c7291f7fc408deb732ff14299953995b7c83513163d13c758eebc3df53390f0100000000fdffffff028c4f010000000000160014dda0f427f67bfeca9f0e7252e458ee39b82c7e06a0bb0d00000000001600142da8e7cef3b9337f1e1309aef5d17ec47e66e5110247304402200d245ee92df8be0183c98fb26bcbc474307ccdb764877273644b4c4eb359138202206c4cf787f120828a812b47043902683e24d50a60216e3b2fe0f104be2806e54f0121025932ccee7590158f7e08bb36290d135d30a0b045163da896e1cd7645ec4223a900000000 +``` + +### Broadcast the Finalized PSBT Transaction +1. Broadcast the signed and finalized PSBT transaction (on the `final_psbt.txt` file) using the online wallet + +```sh +[online]$ ./src/bitcoin-cli -signet sendrawtransaction $(cat /path/to/final_psbt.txt) +c2430a0e46df472b04b0ca887bbcd5c4abf7b2ce2eb71de981444a80e2b96d52 +``` + +### Confirm Wallet Balances + +1. Confirm the updated balance of the offline wallet using the `watch_only_wallet`. + +```sh +[online]$ ./src/bitcoin-cli -signet -rpcwallet="watch_only_wallet" getbalances +{ + "mine": { + "trusted": 0.00085900, + "untrusted_pending": 0.00000000, + "immature": 0.00000000 + }, + "lastprocessedblock": { + "hash": "0000003065c0669fff27edb4a71928cb48e5a6cfcdf06f491a83fd86822d18a6", + "height": 159592 + } +} +``` \ No newline at end of file