Bitcoin Forum
November 12, 2024, 11:31:54 AM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Bitcoin Core: fundrawtransaction or PSBT for signing simple transactions offline  (Read 98 times)
tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
July 30, 2024, 01:07:37 AM
Merited by LoyceV (6), ABCbits (3), nc50lc (1)
 #1

I am currently using the Core Client 27.1. I only use the demon so far. If you think it is advisable, I can also switch to the GUI client. But let me first describe my scenario.

I have an offline/cold wallet on a Raspberry and a corresponding watch wallet (on a normal x86 computer). Communication between the systems takes place via cameras and QR codes. This worked quite well in tests. I can easily transfer 2k of data per QR code.

I would prefer to use only the BIP 84 addresses that the Core Client uses by default. And generally operate everything in standard mode. I only need normal Bitcoin transactions (no multisig or anything special). I would like to leave most of the work to the Core Client. I have already looked on the Internet and found this article by Pieter Wuille:

https://bitcoin.stackexchange.com/a/106204

The API call fundrawtransaction seems to be exactly what I'm looking for. But later Wuille says that it has been superseded by PSBT. I am now wondering which direction I should go in. PSBT seems to have a lot of possibilities and is therefore probably generally easier. But I just want to be able to send coins from A to B in a secure and controlled way. With devices that can only exchange QR codes.

How would you proceed?
tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
July 30, 2024, 01:16:44 PM
Last edit: July 30, 2024, 01:32:11 PM by tiffy
 #2

I looked further on the internet and found this series of articles:
https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/07_1_Creating_a_Partially_Signed_Bitcoin_Transaction.md

I found the section Create a PSBT the Easy Way to be the most suitable for me. But of course I have to try it out first.

HWI is discussed in the last article. I didn't know this tool before. I think it's a good thing but at the moment I have the feeling it adds just another layer of complexity to my already existing setup. Can't I just use walletprocesspsbt on my HW wallet (Raspberry with Bitcoind 27.1)? My approach would be roughly as follows:

1. Use walletcreatefundedpsbt with empty inputs on the watch-only Wallet.
2. Transfer the output of walletcreatefundedpsbt as a QR code to my HW Wallet.
3. Use walletprocesspsbt on the HW Wallet with the transfered output of walletcreatefundedpsbt.
4. Transfer the output of walletprocesspsbt as a QR code back to the watch-only Wallet.
5. Then there: finalizepsbt and sendrawtransaction

Does that make sense? Have I understood the scheme correctly?
achow101
Moderator
Legendary
*
Offline Offline

Activity: 3542
Merit: 6886


Just writing some code


View Profile WWW
July 30, 2024, 03:37:47 PM
 #3

Use PSBTs since they contain all of the extra information needed in order to sign. The raw transaction workflow will require you to provide that data separately.

nc50lc
Legendary
*
Offline Offline

Activity: 2590
Merit: 6372


Self-proclaimed Genius


View Profile
July 31, 2024, 05:47:05 AM
 #4

Does that make sense? Have I understood the scheme correctly?
That'll work, although the guide may be written for versions older than v26.0.
Since you're using v27.1, finalizepsbt wont be necessary when using walletprocesspsbt since it'll also output the finalized raw transaction hex that you can broadcast with the watching-only wallet.

█▀▀▀











█▄▄▄
▀▀▀▀▀▀▀▀▀▀▀
e
▄▄▄▄▄▄▄▄▄▄▄
█████████████
████████████▄███
██▐███████▄█████▀
█████████▄████▀
███▐████▄███▀
████▐██████▀
█████▀█████
███████████▄
████████████▄
██▄█████▀█████▄
▄█████████▀█████▀
███████████▀██▀
████▀█████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
c.h.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀█











▄▄▄█
▄██████▄▄▄
█████████████▄▄
███████████████
███████████████
███████████████
███████████████
███░░█████████
███▌▐█████████
█████████████
███████████▀
██████████▀
████████▀
▀██▀▀
tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
August 02, 2024, 02:18:51 AM
Merited by ABCbits (1)
 #5

As a precaution, I have now switched to the qt-client after realizing that it offers a complete workflow for PSBT files. I carried out two native SegWit transactions as a test. Both were signed on my HW wallet without any problems and then accepted by the network.

I simply have no idea and was therefore still surprised: The first PSBT was 3K in size, the second only 300 bytes. That is an enormous difference. I had rather expected 300 bytes, but had to learn that things work a little differently with SegWit. I found this comment:

https://bitcointalk.org/index.php?topic=5327085.msg56671443#msg56671443

Can PSBTs really get that big with Segwit? I would need dozens of QR codes in the event of an "incident". Is Segwit therefore perhaps problematic for air gaps? Which address type should I use instead? Or has the problem been solved in some way in the meantime?
nc50lc
Legendary
*
Offline Offline

Activity: 2590
Merit: 6372


Self-proclaimed Genius


View Profile
August 02, 2024, 04:36:02 AM
Merited by tiffy (1)
 #6

I carried out two native SegWit transactions as a test.
-snip-
I simply have no idea and was therefore still surprised: The first PSBT was 3K in size, the second only 300 bytes. That is an enormous difference. I had rather expected 300 bytes, but had to learn that things work a little differently with SegWit.
Since both are spending P2WPKH, there shouldn't be any major difference in the structure.
It could be the number of UTXO used as input in the first transaction, naturally, more inputs will result with higher psbt size.

Do you still have a copy of the PSBT that you've used?
If so, use analyzepsbt to see how many inputs each of those psbt has.

█▀▀▀











█▄▄▄
▀▀▀▀▀▀▀▀▀▀▀
e
▄▄▄▄▄▄▄▄▄▄▄
█████████████
████████████▄███
██▐███████▄█████▀
█████████▄████▀
███▐████▄███▀
████▐██████▀
█████▀█████
███████████▄
████████████▄
██▄█████▀█████▄
▄█████████▀█████▀
███████████▀██▀
████▀█████████
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
c.h.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
▀▀▀█











▄▄▄█
▄██████▄▄▄
█████████████▄▄
███████████████
███████████████
███████████████
███████████████
███░░█████████
███▌▐█████████
█████████████
███████████▀
██████████▀
████████▀
▀██▀▀
tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
August 02, 2024, 11:14:45 AM
 #7

Do you still have a copy of the PSBT that you've used?
If so, use analyzepsbt to see how many inputs each of those psbt has.


analyzepsbt of first unsigned transaction (psbt file is 3071 bytes in size):

Code:
{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "signer",
      "missing": {
        "signatures": [
          "73bb7f727392b7ea8a978ddd9da9234c299dee53"
        ]
      }
    }
  ],
  "estimated_vsize": 110,
  "estimated_feerate": 0.00003436,
  "fee": 0.00000378,
  "next": "signer"
}

analyzepsbt of second unsigned transaction (psbt file is 272 bytes in size):

Code:
{
  "inputs": [
    {
      "has_utxo": true,
      "is_final": false,
      "next": "signer",
      "missing": {
        "signatures": [
          "6dc3edc4f4a36f953dcd64649adf804eb69708cb"
        ]
      }
    }
  ],
  "estimated_vsize": 110,
  "estimated_feerate": 0.00003290,
  "fee": 0.00000362,
  "next": "signer"
}

It looks like both have exactly one input, right? But the first PSBT is significantly larger.

In both cases, 50 bytes are added to the PSTB when signing. I assume this is normal.
tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
August 02, 2024, 12:03:51 PM
Last edit: August 02, 2024, 12:25:03 PM by tiffy
 #8

I have now used decodepsbt to output the files in a readable JSON format. And what a difference!

I have to say that I basically did the same thing for both transactions from the user's point of view.

First, I transferred the entire credit balance from address 1 to address 2. First transaction. Then I transferred the entire credit balance from address 2 to address 3. Second transaction.

In the second transaction, I see an input and an output under non_witness_utxo. Mine.  I don't know what that means but it seems normal.

But with the first transaction, all kinds of other vins and vouts appear under non_witness_utxo. There are amounts that my transaction has nothing to do with. My data also appears there, of course, but so do many others.

Is there any way to prevent this? And how big can it get? Is there any limit? I need a new QR code every 2500 bytes. I therefore had to work with two QR codes for the first transaction. The whole thing gets even bigger with base64 and zstd only achieves a compression rate of approx. 80% for PSBT files.

I would like to have one QR code per transaction. Should I perhaps change the address format for air gapped wallets?

I only use my system myself and am used to suffering. But maybe I can make my life a little easier at this point.

I am grateful for your help and advice.

tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
August 02, 2024, 02:27:35 PM
 #9

Shouldn't legacy addresses according to BIP 44 solve this problem? The psbt file should remain small, shouldn't it? Do legacy addresses have any disadvantages for me apart from higher fees?
achow101
Moderator
Legendary
*
Offline Offline

Activity: 3542
Merit: 6886


Just writing some code


View Profile WWW
August 02, 2024, 04:27:36 PM
Merited by nc50lc (2), tiffy (2)
 #10

But with the first transaction, all kinds of other vins and vouts appear under non_witness_utxo. There are amounts that my transaction has nothing to do with. My data also appears there, of course, but so do many others.

Is there any way to prevent this?
No, it is there for security.

Transaction signing requires knowing the output script of the output being spent. Since this data is not part of transaction input, it must be provided as extra data, which is what PSBT does. Additionally, you probably want to know the amount of the output being spent to be able to verify the amounts and fees. However, with non-segwit signing, it is possible for whoever is providing the output script and the amount to provide the incorrect amount and trick you into signing a transaction that spends more coins to fees than you were expecting. Thus in order to prove that the amounts are correct, the PSBT must provide information that is directly committed to in the spending transaction. The only way to do that is by providing the full previous transaction so that its txid can be computed and compared to the txid in inputs of the spending transaction.

With segwit v0, this issue was partially resolved by having the signature commit to the amount of the previous output. However, an attack requiring multiple signing rounds was discovered where that was insufficient and you could still be tricked into spending more coins than expected. Thus the full previous transaction is also added for segwit v0 inputs for simplicity.

If your transaction uses non-segwit or segwit v0 inputs, then there is no way to avoid the non_witness_utxo.

Currently, the only input type that does not require the non_witness_utxo are Taproot (segwit v1). If your transaction spends taproot inputs, they will only contain the witness_utxo which will always be 45 bytes.

And how big can it get?
Very

Is there any limit?
PSBT does not define one, but it is likely that it will adhere to the consensus rules which limit the transaction size via the block size limit if 4 MB. Furthermore, transactions have a standardness size limit of 400 KB, so it is likely that the non_witness_utxo will not exceed that. However, as full previous transactions are included for non-segwit and segwit v0 inputs, if your transaction has multiple of them, and each one has a large previous transactions, then each input will contain those in their non_witness_utxo and the size of your PSBT will be quite large.

Should I perhaps change the address format for air gapped wallets?
As I mentioned above, Taproot.

Shouldn't legacy addresses according to BIP 44 solve this problem? The psbt file should remain small, shouldn't it? Do legacy addresses have any disadvantages for me apart from higher fees?
No, as I mentioned above,the problem is due to signing, not derivation paths which BIP 44 defines. Derivation path information is included in the PSBT, but it's relatively small.

tiffy (OP)
Jr. Member
*
Offline Offline

Activity: 42
Merit: 48


View Profile
August 02, 2024, 08:22:21 PM
Last edit: August 02, 2024, 10:21:12 PM by tiffy
 #11

You and nc50lc helped me again a lot. Nevertheless, I need to look into it more myself in order to fully understand what you have written.

What I generally understood:

The process of signing may require significantly more data than appears later in the transaction, as previous transactions may also be included here. The PSBT may then have to contain this additional transaction data. The size of the PSBT depends on how my inputs were added to the blockchain. I could use Taproot (Bech32m) to avoid the problem.

An average transaction is only 300 bytes in size. I could therefore mitigate the problem by converting the signed PSBT into a raw transaction on the offline device. Then at least the return path via a QR code would work. Do I see that correctly?

I'm a little reluctant to use Taproot because it's still so new and I know so little. I didn't even understand the normal Segwit. I think I'll stick with the Bitcoin Core standard addresses (native Segwit) and figure out how to deal with the big PSBT problem and my air gap later.

Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!