psbt: Taproot fields for PSBT #22558

pull achow101 wants to merge 18 commits into bitcoin:master from achow101:taproot-psbt changing 17 files +708 −31
  1. achow101 commented at 8:47 PM on July 26, 2021: member

    Implements the Taproot fields for PSBT described in BIP 371.

  2. DrahtBot added the label Descriptors on Jul 26, 2021
  3. DrahtBot added the label RPC/REST/ZMQ on Jul 26, 2021
  4. DrahtBot added the label Wallet on Jul 26, 2021
  5. DrahtBot commented at 12:28 PM on July 27, 2021: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #23578 (Add external signer taproot support by Sjors)
    • #23502 (wallet: Avoid underpaying transaction fees when signing taproot spends by achow101)
    • #21283 (Implement BIP 370 PSBTv2 by achow101)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  6. DrahtBot cross-referenced this on Jul 27, 2021 from issue psbt: Actually use SIGHASH_DEFAULT for PSBT signing by achow101
  7. DrahtBot cross-referenced this on Jul 27, 2021 from issue rpc: Allow walletprocesspsbt to sign without finalizing by achow101
  8. DrahtBot cross-referenced this on Jul 27, 2021 from issue Consolidate XOnlyPubKey lookup hack by achow101
  9. DrahtBot cross-referenced this on Jul 27, 2021 from issue wallet: Make a tr() descriptor by default by achow101
  10. DrahtBot cross-referenced this on Jul 27, 2021 from issue A few follow-ups for taproot signing by sipa
  11. DrahtBot cross-referenced this on Jul 27, 2021 from issue rpc, gui: bumpfee signer support by Sjors
  12. DrahtBot cross-referenced this on Jul 27, 2021 from issue Implement BIP 370 PSBTv2 by achow101
  13. DrahtBot cross-referenced this on Jul 28, 2021 from issue Allow fundrawtransaction and walletcreatefundedpsbt to take external inputs by achow101
  14. DrahtBot cross-referenced this on Jul 28, 2021 from issue [BIP 174] PSBT version, proprietary, and xpub fields by achow101
  15. mjdietzx commented at 2:24 PM on September 1, 2021: contributor

    Concept and Approach ACK. I was experimenting with a basic taproot n-of-m multisig using a single OP_CHECKSIGADD based script on top of this branch. Taproot fields in the PSBTs I was creating (and attempting to sign - although I haven't got that working yet) looked good when I inspected them. I did some very light testing of this, mostly sanity checks

  16. achow101 force-pushed on Sep 1, 2021
  17. achow101 force-pushed on Sep 1, 2021
  18. achow101 force-pushed on Sep 20, 2021
  19. DrahtBot cross-referenced this on Sep 22, 2021 from issue doc: Fix RPC result documentation by MarcoFalke
  20. DrahtBot cross-referenced this on Sep 22, 2021 from issue Avoid unnecessary signing provider copies on descriptor expansion by Empact
  21. achow101 force-pushed on Sep 29, 2021
  22. DrahtBot cross-referenced this on Nov 1, 2021 from issue Replace MakeSpan helper with Span deduction guide by sipa
  23. DrahtBot cross-referenced this on Nov 14, 2021 from issue wallet: Avoid underpaying transaction fees when signing taproot spends by achow101
  24. achow101 force-pushed on Nov 16, 2021
  25. achow101 cross-referenced this on Nov 17, 2021 from issue trezor: Implement Taproot support by achow101
  26. DrahtBot cross-referenced this on Nov 18, 2021 from issue scripted-diff: Use clang-tidy syntax for C++ named arguments by MarcoFalke
  27. Sjors commented at 3:53 PM on November 22, 2021: member

    Needs rebase due to silent merge conflict in descriptor.cpp.

  28. achow101 force-pushed on Nov 22, 2021
  29. Sjors cross-referenced this on Nov 23, 2021 from issue Add external signer taproot support by Sjors
  30. achow101 force-pushed on Nov 25, 2021
  31. achow101 force-pushed on Nov 25, 2021
  32. DrahtBot cross-referenced this on Nov 27, 2021 from issue wallet: Split stuff from rpcwallet by MarcoFalke
  33. in src/psbt.h:71 in 64dc0962d3 outdated
      64 | @@ -56,6 +65,12 @@ struct PSBTInput
      65 |      CScriptWitness final_script_witness;
      66 |      std::map<CPubKey, KeyOriginInfo> hd_keypaths;
      67 |      std::map<CKeyID, SigPair> partial_sigs;
      68 | +    std::vector<unsigned char> m_tap_key_sig;
      69 | +    std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> m_tap_script_sigs;
      70 | +    std::map<std::pair<CScript, int>, std::set<std::vector<unsigned char>, ShortestVectorFirstComparator>> m_tap_scripts;
      71 | +    std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> m_tap_keypaths;
    


    Sjors commented at 5:59 AM on December 5, 2021:

    keypath is ambiguous, maybe call this m_tap_bip32_paths?

    Also, maybe add a comment above these new entries that refers to BIP 341.


    achow101 commented at 8:40 PM on December 6, 2021:

    Done

  34. in src/script/sign.h:79 in 57622204c8 outdated
      73 | @@ -74,6 +74,7 @@ struct SignatureData {
      74 |      std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
      75 |      std::vector<unsigned char> taproot_key_path_sig; /// Schnorr signature for key path spending
      76 |      std::map<std::pair<XOnlyPubKey, uint256>, std::vector<unsigned char>> taproot_script_sigs; ///< (Partial) schnorr signatures, indexed by XOnlyPubKey and leaf_hash.
      77 | +    std::map<XOnlyPubKey, std::pair<std::set<uint256>, KeyOriginInfo>> taproot_misc_pubkeys;
    


    Sjors commented at 6:17 AM on December 5, 2021:

    57622204c81628f790a5355d2f7197d8ed23ebc1 : worth documenting that "misc" may include the inner key (with an empty set of hashes).


    achow101 commented at 8:40 PM on December 6, 2021:

    Added some docs for this

  35. in src/rpc/rawtransaction.cpp:1136 in 48d5949aa9 outdated
    1080 | @@ -1081,6 +1081,43 @@ static RPCHelpMan decodepsbt()
    1081 |                                  {
    1082 |                                      {RPCResult::Type::STR_HEX, "", "hex-encoded witness data (if any)"},
    1083 |                                  }},
    1084 | +                                {RPCResult::Type::STR_HEX, "taproot_key_path_sig", /* optional */ true, "hex-encoded signature for the Taproot key path spend"},
    


    Sjors commented at 6:35 AM on December 5, 2021:

    48d5949aa94410b12263df9b7a3cbc4d7cd50b6f: having a fully decoded example in a functional test case would be handy


    achow101 commented at 7:42 PM on December 6, 2021:

    Is there not? There are tests added which check for the presence of the taproot fields in psbts spending taproot inputs.


    Sjors commented at 3:04 AM on December 7, 2021:

    I noticed the presence checking tests, though perhaps checking against the fully decoded result could reveal more subtle issues.

  36. in src/psbt.cpp:371 in 833ecb8dec outdated
     356 | @@ -357,10 +357,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
     357 |      input.FromSignatureData(sigdata);
     358 |  
     359 |      // If we have a witness signature, put a witness UTXO.
     360 | -    // TODO: For segwit v1, we should remove the non_witness_utxo
     361 |      if (sigdata.witness) {
     362 |          input.witness_utxo = utxo;
     363 | -        // input.non_witness_utxo = nullptr;
     364 | +        // We can remove the non_witness_utxo if and only if there are no non-segwit or segwit v0
     365 | +        // inputs in this transaction, so we can deal with this later.
    


    Sjors commented at 6:39 AM on December 5, 2021:

    833ecb8dec1a10e3bc1b8d5bcaf0b6839277f582 "later" -> "in FillPSBT"?


    achow101 commented at 8:40 PM on December 6, 2021:

    Done

  37. in src/wallet/wallet.cpp:1911 in 833ecb8dec outdated
    1893 | @@ -1894,6 +1894,30 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
    1894 |          }
    1895 |      }
    1896 |  
    1897 | +    // Figure out if any witness_utxos should be dropped
    


    Sjors commented at 6:42 AM on December 5, 2021:

    833ecb8dec1a10e3bc1b8d5bcaf0b6839277f582: non_witness_utxos (also below)

    Don't do this for SIGHASH_SINGLE and SIGNHASH_ANYONECANPAY, since new non-taproot inputs might be added later? Or should whoever adds such an input just add them back in? Maybe add a functional test for this.


    achow101 commented at 8:41 PM on December 6, 2021:

    It only matters for SIGHASH_ANYONECANPAY. I've added a check for that.

  38. in src/wallet/wallet.cpp:1927 in 833ecb8dec outdated
    1908 | +        if (wit_ver == 0) {
    1909 | +            // Segwit v0, so we cannot drop any witness_utxos
    1910 | +            to_drop.clear();
    1911 | +            break;
    1912 | +        }
    1913 | +        to_drop.push_back(i);
    


    Sjors commented at 6:49 AM on December 5, 2021:

    833ecb8dec1a10e3bc1b8d5bcaf0b6839277f582: maybe only do this if there actually is a non_witness_utxo? Otherwise you might as well use a go_drop bool and loop over all inputs after this loop. Then you also wouldn't need to track the index.


    achow101 commented at 8:41 PM on December 6, 2021:

    Done

  39. in src/script/sign.cpp:153 in 9b86c58d95 outdated
     148 | @@ -149,6 +149,7 @@ static bool CreateTaprootScriptSig(const BaseSignatureCreator& creator, Signatur
     149 |      auto it = sigdata.taproot_script_sigs.find(lookup_key);
     150 |      if (it != sigdata.taproot_script_sigs.end()) {
     151 |          sig_out = it->second;
     152 | +        return true;
    


    Sjors commented at 6:52 AM on December 5, 2021:

    9b86c58d95539056981c2a04a7345b992b1ce70c: this seems like a bug fix, is there a test you could add that demonstrates this?


    achow101 commented at 7:59 PM on December 6, 2021:

    The existing tests already cover this case (try reverting this commit, the tests will fail).


    Sjors commented at 3:41 AM on December 7, 2021:

    On your latest rebase f7b61d2, when I revert 9b86c58d95539056981c2a04a7345b992b1ce70c, then indeed wallet_taproot.py fails. Still, having the fix and test in the same commit would be much easier to folllow. Moving this bit from the test over to this commit does the trick:

    -            res = self.psbt_offline.walletprocesspsbt(psbt)
    -            assert(res['complete'])
    +            res = self.psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
    +
    +            // Check that pre-existing signatures in CreateTaprootScriptSig are actually used,
    +            // if a signature is found for the given key and leaf hash.
    +            decoded = self.psbt_offline.decodepsbt(res["psbt"])
    

    achow101 commented at 4:38 AM on December 7, 2021:

    I've moved the change that causes the test failure into the previous commit.

    The test isn't for this bug specifically, so I don't think it needs any special mention. The test was written first, and it just so happens that it triggered this bug.

  40. Sjors commented at 6:54 AM on December 5, 2021: member

    Mostly happy with 58af8917bd80b0a918df1a5d38c4b63beae5306f

  41. achow101 force-pushed on Dec 5, 2021
  42. DrahtBot cross-referenced this on Dec 6, 2021 from issue Split up rpcwallet by meshcollider
  43. sipa commented at 7:46 PM on December 6, 2021: member

    In order to make this more testable, would it make sense to add support for OP_CHECKSIGADD-based multisig to descriptors first?

  44. achow101 commented at 7:58 PM on December 6, 2021: member

    In order to make this more testable, would it make sense to add support for OP_CHECKSIGADD-based multisig to descriptors first?

    I think it is fine without those.

  45. achow101 force-pushed on Dec 6, 2021
  46. achow101 force-pushed on Dec 6, 2021
  47. in src/script/sign.h:68 in 11c1e17fd6 outdated
      64 | @@ -65,6 +65,7 @@ typedef std::pair<CPubKey, std::vector<unsigned char>> SigPair;
      65 |  struct SignatureData {
      66 |      bool complete = false; ///< Stores whether the scriptSig and scriptWitness are complete
      67 |      bool witness = false; ///< Stores whether the input this SigData corresponds to is a witness input
      68 | +    TxoutType spk_type = TxoutType::NONSTANDARD; ///< Stores the type of scriptPubKey the input spends
    


    Sjors commented at 3:59 AM on December 7, 2021:

    11c1e17fd622e962d9d3987322a2b51b3181a1db : this is set, but otherwise unused.


    achow101 commented at 4:38 AM on December 7, 2021:

    Removed

  48. Sjors commented at 4:00 AM on December 7, 2021: member

    utACK bd75271a53054bb1bc7d880d5fbf667be4ab5e41

    Having a (draft) PR on top of this that implements OP_CHECKSIGADD is certainly not harmful.

  49. achow101 force-pushed on Dec 7, 2021
  50. achow101 force-pushed on Dec 8, 2021
  51. Sjors commented at 3:10 AM on December 9, 2021: member

    re-utACK 57d354a0d7ba99478eab1afc4304202a07ef4bf7

  52. DrahtBot cross-referenced this on Dec 9, 2021 from issue PSBT: hash preimages fields by darosior
  53. DrahtBot cross-referenced this on Dec 9, 2021 from issue scripted-diff: Use named args in RPC docs by MarcoFalke
  54. achow101 marked this as ready for review on Dec 10, 2021
  55. DrahtBot added the label Needs rebase on Dec 10, 2021
  56. achow101 force-pushed on Dec 11, 2021
  57. DrahtBot removed the label Needs rebase on Dec 11, 2021
  58. Sjors commented at 7:17 AM on December 13, 2021: member

    re-utACK 8a675a00053db4621f7f27cf22e8d65713dff03b

  59. DrahtBot added the label Needs rebase on Dec 13, 2021
  60. achow101 force-pushed on Dec 13, 2021
  61. DrahtBot removed the label Needs rebase on Dec 13, 2021
  62. laanwj added this to the "Blockers" column in a project

  63. DrahtBot cross-referenced this on Jan 4, 2022 from issue doc: Mark proprietary array optional by MarcoFalke
  64. stepansnigirev cross-referenced this on Jan 6, 2022 from issue Specter not showing taproot derivation on Trezor by Quenos
  65. DrahtBot cross-referenced this on Jan 12, 2022 from issue Add (sorted)multi_a descriptor for k-of-n multisig inside tr by sipa
  66. DrahtBot cross-referenced this on Jan 24, 2022 from issue Deprecate SubtractFeeFromOutputs by achow101
  67. DrahtBot cross-referenced this on Jan 26, 2022 from issue Signing support for Miniscript Descriptors by darosior
  68. michaelfolkson commented at 11:12 AM on February 1, 2022: contributor

    Concept ACK, Approach ACK.

    Will hopefully find the time to test with a hardware wallet, HWI (single sig PSBT as Taproot multisig descriptor not yet merged) and do a code review/comparison with the BIP.

    Would certainly be nice to get this in and PR author has added high priority label. External projects are waiting on it.

    edit: What hardware wallets can I test this with? Testnet/Signet coins and new PSBT fields? Just Coldcard?

  69. achow101 referenced this in commit 985ec9705c on Feb 1, 2022
  70. mmilata cross-referenced this on Feb 2, 2022 from issue ci: add hwi tests for core and legacy builds by vdovhanych
  71. Sjors cross-referenced this on Feb 19, 2022 from issue ledger: Support Bitcoin App 2.0 by achow101
  72. prusnak commented at 3:21 PM on February 19, 2022: contributor

    edit: What hardware wallets can I test this with? @michaelfolkson Trezor supports Taproot with HWI (master).

  73. prusnak commented at 3:22 PM on February 19, 2022: contributor

    Shall we try to merge this in time for 23.0? @achow101 @laanwj @MarcoFalke

  74. MarcoFalke commented at 3:47 PM on February 19, 2022: member

    This can't be merged because it needs rebase for several weeks due to a silent conflict

  75. michaelfolkson commented at 4:14 PM on February 19, 2022: contributor

    Don't know anything about the silent conflict but we are past the feature freeze of February 15th too. Hopefully we can get a bunch of new Taproot stuff (e.g. #24043) in 24.0.

  76. prusnak commented at 4:25 PM on February 19, 2022: contributor

    we are past the feature freeze of February 15th too.

    ACK

  77. achow101 force-pushed on Feb 19, 2022
  78. Sjors commented at 2:59 PM on February 21, 2022: member

    This also needs review from more people (I'll re-ACK the rebase once those arrive).

  79. prusnak commented at 3:04 PM on February 21, 2022: contributor

    Hopefully we can get a bunch of new Taproot stuff (e.g. #24043) in 24.0.

    Let's add this PR (#22558) and PR #24043 to the 24.0 Milestone, so they receive enough eyes?

  80. gruve-p commented at 3:11 PM on February 21, 2022: contributor

    Approach ACK

  81. achow101 added this to the milestone 24.0 on Feb 22, 2022
  82. Sjors cross-referenced this on Feb 25, 2022 from issue taproot wallet shows empty history of transactions by bitcoin-eagle
  83. in src/psbt.h:581 in b704884935 outdated
     577 | +                        throw std::ios_base::failure("Input Taproot key signature key is more than one byte type");
     578 | +                    }
     579 | +                    s >> m_tap_key_sig;
     580 | +                    if (m_tap_key_sig.size() < 64) {
     581 | +                        throw std::ios_base::failure("Input Taproot key path signature is shorter than 64 bytes");
     582 | +                    } else if (m_tap_key_sig.size() > 65) {
    


    Empact commented at 3:37 PM on March 2, 2022:

    nit: would these sizes be useful extracted as constants?


    laanwj commented at 2:24 PM on June 22, 2022:

    Agree, there's quite some magic values here (also repeated), having constants makes it easier to review. (or maybe expanding it, like 1 + 32 + 32, as it's mentioned in the BIP) (oh, nm, that's for PSBT_IN_TAP_SCRIPT_SIG's keydata, not here)

  84. in src/psbt.h:850 in b704884935 outdated
     844 | +                    } else if (key.size() != 1) {
     845 | +                        throw std::ios_base::failure("Output Taproot internal key key is more than one byte type");
     846 | +                    }
     847 | +                    UnserializeFromVector(s, m_tap_internal_key);
     848 | +                    break;
     849 | +                }
    


    Empact commented at 3:38 PM on March 2, 2022:

    nit: some of these blocks are not strictly necessary, e.g. in this case.


    laanwj commented at 2:53 PM on June 22, 2022:

    Why this block isn't necessary?

  85. achow101 cross-referenced this on Mar 3, 2022 from issue Trezor1 not signing mixed taproot+wpkh inputs? by jb55
  86. jb55 commented at 7:33 PM on March 3, 2022: contributor

    Concept ACK. Testing this now because HWI isn't signing one of my taproot inputs :(

  87. sipa commented at 7:52 PM on March 3, 2022: member

    @achow101 I wonder if you're still open to modifications of BIP371.

    Thinking about later integration with MuSig(2), I think it's somewhat unfortunate that the currently suggested PSBT_IN_TAP_BIP32_DERIVATION field conveys both (a) which keys are participating in which leaves and (b) how those are derived. Post-MuSig2, I expect that often keys will be present that aren't directly BIP32-derived, but are a MuSig* aggregate of BIP32-derived keys. It's not impossible to integrate that on top here, but it'd involve some duplication.

    My suggestion would be to have these fields:

    • PSBT_IN_TAP_KEY_SIG: unmodified
    • PSBT_IN_TAP_SCRIPT_SIG: unmodified
    • PSBT_IN_TAP_LEAF_SCRIPT: unmodified
    • PSBT_IN_TAP_KEY_TWEAK: concatenation of PSBT_IN_TAP_INTERNAL_KEY and PSBT_IN_TAP_MERKLE_ROOT; it conveys "the output key is a tweak of this key with this Merkle root".
    • PSBT_IN_TAP_KEY_IN_SCRIPT: like PSBT_IN_TAP_BIP32_DERIVATION now, but without the BIP32 path; it just conveys "this key occurs in these leaves".
    • PSBT_IN_TAP_BIP32_DERIVATION: like PSBT_IN_TAP_BIP32_DERIVATION, but without the list of leaf hashes. It can be used for (a) the output key directly (b) the internal key (provided in PSBT_IN_TAP_KEY_TWEAK) of (c) a key occurring in a leaf script (provided by PSBT_IN_TAP_KEY_IN_SCRIPT).

    I'm also happy to take this to the ML if you think this deserves more discussion.

    Ping @sanket1729 @darosior @jonasnick.

  88. achow101 commented at 8:01 PM on March 3, 2022: member

    I wonder if you're still open to modifications of BIP371.

    BIP 371 is already in use in production, notably by Ledger. So I think it might be too late for any modifications.

    cc @bigspider

  89. sipa commented at 8:26 PM on March 3, 2022: member

    Ok, no reason to change things in that case.

  90. jb55 commented at 9:39 PM on March 3, 2022: contributor

    tACK b704884935766748cf533577c1babacfb6d4b5a5

    Was able to get a mixed taproot keypath + wpkh spend working on HWI with this PR

    Haven't looked through the code that much, only tested behavior and I was happy with the result.

  91. bigspider commented at 12:20 AM on March 4, 2022: none

    Thanks @achow101 for the ping. At this time, since we only support BIP-86 addresses, the only taproot field we rely on is PSBT_IN_TAP_BIP32_DERIVATION, where we assume that the list of hashes is indeed empty (so the expected value is a single byte 0x00, followed by 4 bytes for the fingerprint, followed by the derivation steps.

  92. prusnak commented at 7:59 AM on March 4, 2022: contributor

    where we assume that the list of hashes is indeed empty

    So it seems that @sipa's suggestion can be implemented in a compatible way that does not break your usage of PSBT_IN_TAP_BIP32_DERIVATION

  93. DrahtBot added the label Needs rebase on Mar 4, 2022
  94. bigspider commented at 3:28 PM on March 4, 2022: none

    Leaving the 0x00 would not break anything as I understand it. If desired in order to have a clean standard, I suppose we can have a reasonable upgrade path by letting the next version of the app to skip the 0x00 if present and keeping this loose check for some time.

  95. achow101 force-pushed on Mar 4, 2022
  96. DrahtBot removed the label Needs rebase on Mar 4, 2022
  97. sanket1729 commented at 12:24 PM on March 7, 2022: contributor

    ... I expect that often keys will be present that aren't directly BIP32-derived, but are a MuSig* aggregate of BIP32-derived keys

    I was thinking most keys would be BIP32 derived keys of a Musig2 aggregate like musig2(A,B,C)/* or BIP32 derived keys of a Musig2 aggregate of BIP32-derived keys, like musig2(A/*, B/*, C/*)/*? The case you mention seems like musgi2(A/*, B/*, C/*)

  98. michaelfolkson cross-referenced this on Mar 7, 2022 from issue Possible modifications to BIP 371 by michaelfolkson
  99. michaelfolkson commented at 12:43 PM on March 7, 2022: contributor

    @achow101 I wonder if you're still open to modifications of BIP371.

    Seems like we're in multi threaded conversation territory here with discussion of possible BIP 371 changes and review of this PR as is. I've opened an issue (#24492) to discuss possible BIP 371 changes in case that helps.

    I'm also happy to take this to the ML if you think this deserves more discussion.

    Or alternatively I'll close the issue and possible BIP 371 changes can be taken to the mailing list. I definitely think an email to the mailing list is a good idea once those proposed changes have been solidified.

  100. michaelfolkson commented at 7:38 PM on March 11, 2022: contributor

    Seems like we're in multi threaded conversation territory here with discussion of possible BIP 371 changes and review of this PR as is. I've opened an issue (https://github.com/bitcoin/bitcoin/issues/24492) to discuss possible BIP 371 changes in case that helps. @sipa's proposed changes won't be made to BIP 371 due to uncertainty over whether other projects have already deployed. Closed the issue.

  101. Sjors commented at 10:10 AM on March 16, 2022: member

    re-utACK 28868805bbf263d75cbd02eb7d510f1e343b979f

  102. Sjors cross-referenced this on Apr 15, 2022 from issue Awesome multisig PR labyrinth guide by Sjors
  103. guggero cross-referenced this on Apr 23, 2022 from issue psbt: add support for new Taproot fields by guggero
  104. guggero cross-referenced this on Apr 28, 2022 from issue taproot: add PSBT signing support for Taproot, fix remote signing Taproot support by guggero
  105. guggero commented at 1:57 PM on April 30, 2022: contributor

    I'm currently testing this PR with/against our PSBT implementation in lnd. I was able to get a BIP86 key spend working :tada:

    But I can't seem to get bitcoind to recognize and sign for a key spend path with a merkle root provided. Perhaps that's not the scope for this PR? If so then I apologize.

    According to my question and the answer I got here, it should be enough to set the following fields:

        {
          "witness_utxo": {
            "amount": 4.00000000,
            "scriptPubKey": {
              "asm": "1 5a7730b9788468ac1b90baac80005da4965496e4d88bcbac95bd3c83cd906f3a",
              "desc": "addr(bcrt1ptfmnpwtcs352cxush2kgqqza5jt9f9hymz9uhty4h57g8nvsduaq6s9ypp)#q562pd9u",
              "hex": "51205a7730b9788468ac1b90baac80005da4965496e4d88bcbac95bd3c83cd906f3a",
              "address": "bcrt1ptfmnpwtcs352cxush2kgqqza5jt9f9hymz9uhty4h57g8nvsduaq6s9ypp",
              "type": "witness_v1_taproot"
            }
          },
          "taproot_bip32_derivs": [
            {
              "pubkey": "63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f",
              "master_fingerprint": "00000000",
              "path": "m/86'/0'/0'/0/0",
              "leaf_hashes": [
              ]
            }
          ],
          "taproot_internal_key": "63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f",
          "taproot_merkle_root": "6c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d38"
        }
    

    Full PSBT:

    cHNidP8BAHECAAAAAT/GF0O3okL4iQV80uYewSbhqa7qWoD2nG489WsPxw9xAAAAAAD/////AoCT3BQAAAAAFgAUKpx5R067Qv191nSkawzjIGJAQ+ri6PoCAAAAABYAFIyIwvqKctH/eWgjlieETO9w55xoAAAAAAABASsAhNcXAAAAACJRIFp3MLl4hGisG5C6rIAAXaSWVJbk2IvLrJW9PIPNkG86IRZjzFLwbgqR4+ZFZjGqBwIh1YzNHtjFtmOdT4h4bc1QDxkAAAAAAFYAAIAAAACAAAAAgAAAAAAAAAAAARcgY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA8BGCBsLkuwHjFquq7iiNacBsxgjO3v1uGgaBN4bE7FG24dOAAAIgICZ5Cr1jOOzCBlO+GZ+Y3VSYA26Z/kFrcSYqzM00TKPjQY1G/d61QAAIABAACAAAAAgAEAAAADAAAAAA==
    

    But when I use bitcoin-cli walletprocesspsbt with that PSBT (the private key is definitely in the wallet, it's the same key I used for the previous BIP86 key spend), then I just get the same PSBT and "complete": false back.

    Is this me doing something wrong or is this out of scope for this PR?

  106. achow101 commented at 3:58 PM on April 30, 2022: member

    @guggero Are you using a legacy or a descriptor wallet? Is the taproot output script being watched by the wallet (i.e. you imported the descriptor for it)?

  107. guggero commented at 8:30 AM on May 2, 2022: contributor

    It's a descriptor wallet but I didn't add that specific output descriptor to it. It's the same internal key as was used in the BIP86 test, so the key is there. I assumed the PSBT would be sufficient as the "assembly instruction" for the signature, since the private key is known to the wallet. But I guess I have to learn more about how descriptor wallets work in this context. I'll try again with the correct descriptor imported and watched by the wallet, that will very likely resolve my issue. Thanks!

  108. Sjors commented at 11:02 AM on May 2, 2022: member

    since the private key is known to the wallet.

    Afaik we don't sign anything unless we explicitly watch the scriptPubKey, which (for descriptor wallets) is only the case if a descriptor has been imported. In addition, that descriptor must have the private key: a descriptor with just the xpub won't work even if we have the corresponding seed. See also #23417 and #23544.

  109. achow101 commented at 2:19 PM on May 2, 2022: member

    Afaik we don't sign anything unless we explicitly watch the scriptPubKey, which (for descriptor wallets) is only the case if a descriptor has been imported.

    No, descriptor wallets will sign if it sees any keys that it owns in the BIP32 derivation paths. I just forgot to update that to search the taproot BIP32 derivation paths too.

  110. achow101 commented at 3:32 PM on May 2, 2022: member

    @guggero I've pushed some commits that should fix that problem. Can you try again?

  111. guggero commented at 12:44 PM on May 3, 2022: contributor

    Thank you very much, this fixed the "key spend with script root" test case. Is script path signing expected to work as well?

    I tried it and got a wrong result. But again, this could be due to me still using the internal and script leaf key from the BIP86 descriptor. But I guess the result is still kind of unexpected. Since I supplied a leaf hash in the BIP32 derivation info and a script with a control block, I don't expect a signature to be put into the final script witness:

    $ bitcoin-cli walletprocesspsbt cHNidP8BAFICAAAAAV0virKr77xOIRw1FU3mHJUQ6oO7UmoEgIUUsED3ZRiuAQAAAAD/////AYCy5g4AAAAAFgAUy79OrU4hd2M3xvJMufO1pLdEWcUAAAAAAAEBKwCj4REAAAAAIlEgLWIhk/X61lqdbrKkZqR9AsFvT4JFt4lmaYWbtsDTy3ciFcBjzFLwbgqR4+ZFZjGqBwIh1YzNHtjFtmOdT4h4bc1QDyMgY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA+swCEWY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA85ARuXHYQK/Sy6fb774buzt5a3DU2Va/o8Pz27k/FkM3v/AAAAAFYAAIAAAACAAAAAgAAAAAAAAAAAARcgY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA8BGCAblx2ECv0sun2+++G7s7eWtw1NlWv6PD89u5PxZDN7/wAA
    {
      "psbt": "cHNidP8BAFICAAAAAV0virKr77xOIRw1FU3mHJUQ6oO7UmoEgIUUsED3ZRiuAQAAAAD/////AYCy5g4AAAAAFgAUy79OrU4hd2M3xvJMufO1pLdEWcUAAAAAAAEBKwCj4REAAAAAIlEgLWIhk/X61lqdbrKkZqR9AsFvT4JFt4lmaYWbtsDTy3cBCEIBQGcgRxlVx6JBG4e3xDCw24Pm8QBFlHpvISfrlUAP1ajvKnh9aAAKCDqGBk5BysaADcNy+KFoBGtRk5GrmhgOwVoAAA==",
      "complete": true
    }
    

    <details> <summary>decoded input PSBT</summary> <pre> { "tx": { "txid": "0faa6cef74415fa47d8ba4c5fbc16ef13ffa6d5bebf5e13f3f07efe255ed54e2", "hash": "0faa6cef74415fa47d8ba4c5fbc16ef13ffa6d5bebf5e13f3f07efe255ed54e2", "version": 2, "size": 82, "vsize": 82, "weight": 328, "locktime": 0, "vin": [ { "txid": "ae1865f740b0148580046a52bb83ea10951ce64d15351c214ebcefabb28a2f5d", "vout": 1, "scriptSig": { "asm": "", "hex": "" }, "sequence": 4294967295 } ], "vout": [ { "value": 2.50000000, "n": 0, "scriptPubKey": { "asm": "0 cbbf4ead4e21776337c6f24cb9f3b5a4b74459c5", "desc": "addr(bcrt1qewl5at2wy9mkxd7x7fxtnua45jm5gkw9fxuurq)#0jsdd5lg", "hex": "0014cbbf4ead4e21776337c6f24cb9f3b5a4b74459c5", "address": "bcrt1qewl5at2wy9mkxd7x7fxtnua45jm5gkw9fxuurq", "type": "witness_v0_keyhash" } } ] }, "global_xpubs": [ ], "psbt_version": 0, "proprietary": [ ], "unknown": { }, "inputs": [ { "witness_utxo": { "amount": 3.00000000, "scriptPubKey": { "asm": "1 2d622193f5fad65a9d6eb2a466a47d02c16f4f8245b7896669859bb6c0d3cb77", "desc": "addr(bcrt1p943zryl4ltt948twk2jxdfraqtqk7nuzgkmcjenfskdmdsxnedmsfzxf2p)#nyv7jhkl", "hex": "51202d622193f5fad65a9d6eb2a466a47d02c16f4f8245b7896669859bb6c0d3cb77", "address": "bcrt1p943zryl4ltt948twk2jxdfraqtqk7nuzgkmcjenfskdmdsxnedmsfzxf2p", "type": "witness_v1_taproot" } }, "taproot_scripts": [ { "script": "2063cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500fac", "leaf_ver": 192, "control_blocks": [ "c063cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f" ] } ], "taproot_bip32_derivs": [ { "pubkey": "63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f", "master_fingerprint": "00000000", "path": "m/86'/0'/0'/0/0", "leaf_hashes": [ "1b971d840afd2cba7dbefbe1bbb3b796b70d4d956bfa3c3f3dbb93f164337bff" ] } ], "taproot_internal_key": "63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f", "taproot_merkle_root": "1b971d840afd2cba7dbefbe1bbb3b796b70d4d956bfa3c3f3dbb93f164337bff" } ], "outputs": [ { } ], "fee": 0.50000000 } </pre> </details>

    <details> <summary>decoded output PSBT</summary> <pre> { "tx": { "txid": "0faa6cef74415fa47d8ba4c5fbc16ef13ffa6d5bebf5e13f3f07efe255ed54e2", "hash": "0faa6cef74415fa47d8ba4c5fbc16ef13ffa6d5bebf5e13f3f07efe255ed54e2", "version": 2, "size": 82, "vsize": 82, "weight": 328, "locktime": 0, "vin": [ { "txid": "ae1865f740b0148580046a52bb83ea10951ce64d15351c214ebcefabb28a2f5d", "vout": 1, "scriptSig": { "asm": "", "hex": "" }, "sequence": 4294967295 } ], "vout": [ { "value": 2.50000000, "n": 0, "scriptPubKey": { "asm": "0 cbbf4ead4e21776337c6f24cb9f3b5a4b74459c5", "desc": "addr(bcrt1qewl5at2wy9mkxd7x7fxtnua45jm5gkw9fxuurq)#0jsdd5lg", "hex": "0014cbbf4ead4e21776337c6f24cb9f3b5a4b74459c5", "address": "bcrt1qewl5at2wy9mkxd7x7fxtnua45jm5gkw9fxuurq", "type": "witness_v0_keyhash" } } ] }, "global_xpubs": [ ], "psbt_version": 0, "proprietary": [ ], "unknown": { }, "inputs": [ { "witness_utxo": { "amount": 3.00000000, "scriptPubKey": { "asm": "1 2d622193f5fad65a9d6eb2a466a47d02c16f4f8245b7896669859bb6c0d3cb77", "desc": "addr(bcrt1p943zryl4ltt948twk2jxdfraqtqk7nuzgkmcjenfskdmdsxnedmsfzxf2p)#nyv7jhkl", "hex": "51202d622193f5fad65a9d6eb2a466a47d02c16f4f8245b7896669859bb6c0d3cb77", "address": "bcrt1p943zryl4ltt948twk2jxdfraqtqk7nuzgkmcjenfskdmdsxnedmsfzxf2p", "type": "witness_v1_taproot" } }, "final_scriptwitness": [ "6720471955c7a2411b87b7c430b0db83e6f10045947a6f2127eb95400fd5a8ef2a787d68000a083a86064e41cac6800dc372f8a168046b519391ab9a180ec15a" ] } ], "outputs": [ { } ], "fee": 0.50000000 } </pre> </details>

  112. sipa commented at 2:17 PM on May 3, 2022: member

    @guggero I haven't inspected things in detail, but I suspect that what's going on is that you've simply provided sufficient information in the PSBT to construct a key-path spend, so that's what it constructs (as it's smaller in witness size).

  113. achow101 commented at 2:25 PM on May 3, 2022: member

    @sipa is correct. We will always try to create a key path spend if enough information is available to do so. You've provided the internal key and the derivation path for the internal key, even if it also has a leaf hash.

  114. guggero commented at 2:43 PM on May 3, 2022: contributor

    Ah, that makes a lot of sense, thank you for your answers, @sipa and @achow101 . Without the internal key and merkle root fields I get the expected witness stack :tada:

    <details> <summary>Here's my full test protocol.</summary>

    1. import descriptor (importdescriptors '[{"desc":"tr(tprv8ZgxMBicQKsPekctUrTRdca69GwGek7eoSafZ23pNYEsyHctxwWfUjgsq8UKwo3cLDpViLRv84bxtsZevZ6w4ZJqtMMqDZbnVreNZYbe6bu/86'"'"'/0'"'"'/0'"'"'/0/0)#53fkwtjk","timestamp":"now"}]')

    2. BIP 86 key spend

      • send coins to bcrt1pwr5wkkq5jfq8655dk929mar3588qncd0j24csyq22awcjwzh88mq5uhwph (BIP86 key spend, internal key 63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f)
      • create PSBT that references that output
      • sign with walletprocesspsbt cHNidP8BAHECAAAAAeFJXY+feoKbYaGLcgspwL36Hwl9Ehr5sF4Zy7nj4TpQAAAAAAAAAAAAAo3j+gIAAAAAFgAUD1vsYoxpaHURXVbiu/mxgWarqwiAdNIaAAAAABYAFCqceUdOu0L9fdZ0pGsM4yBiQEPqAAAAAAABASsAZc0dAAAAACJRIHDo61gUkkB9Uo2xVF30caHOCeGvkquIEApXXYk4Vzn2IRZjzFLwbgqR4+ZFZjGqBwIh1YzNHtjFtmOdT4h4bc1QDxkAAAAAAFYAAIAAAACAAAAAgAAAAAAAAAAAAAAA
    3. script root key spend

      • send coins to bcrt1ptfmnpwtcs352cxush2kgqqza5jt9f9hymz9uhty4h57g8nvsduaq6s9ypp (script root key spend, internal key 63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f, merkle root 6c2e4bb01e316abaaee288d69c06cc608cedefd6e1a06813786c4ec51b6e1d38)
      • create PSBT that references that output
      • sign with walletprocesspsbt cHNidP8BAHECAAAAAT/GF0O3okL4iQV80uYewSbhqa7qWoD2nG489WsPxw9xAAAAAAD/////AoCT3BQAAAAAFgAUKpx5R067Qv191nSkawzjIGJAQ+ri6PoCAAAAABYAFIyIwvqKctH/eWgjlieETO9w55xoAAAAAAABASsAhNcXAAAAACJRIFp3MLl4hGisG5C6rIAAXaSWVJbk2IvLrJW9PIPNkG86IRZjzFLwbgqR4+ZFZjGqBwIh1YzNHtjFtmOdT4h4bc1QDxkAAAAAAFYAAIAAAACAAAAAgAAAAAAAAAAAARcgY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA8BGCBsLkuwHjFquq7iiNacBsxgjO3v1uGgaBN4bE7FG24dOAAAIgICZ5Cr1jOOzCBlO+GZ+Y3VSYA26Z/kFrcSYqzM00TKPjQY1G/d61QAAIABAACAAAAAgAEAAAADAAAAAA==
    4. script spend

      • send coins to bcrt1p943zryl4ltt948twk2jxdfraqtqk7nuzgkmcjenfskdmdsxnedmsfzxf2p (script spend, internal key 63cc52f06e0a91e3e6456631aa070221d58ccd1ed8c5b6639d4f88786dcd500f, merkle root 1b971d840afd2cba7dbefbe1bbb3b796b70d4d956bfa3c3f3dbb93f164337bff)
      • create PSBT that references that output
      • sign with walletprocesspsbt cHNidP8BAFICAAAAAV0virKr77xOIRw1FU3mHJUQ6oO7UmoEgIUUsED3ZRiuAQAAAAD/////AcBg0hEAAAAAFgAUy79OrU4hd2M3xvJMufO1pLdEWcUAAAAAAAEBKwCj4REAAAAAIlEgLWIhk/X61lqdbrKkZqR9AsFvT4JFt4lmaYWbtsDTy3ciFcBjzFLwbgqR4+ZFZjGqBwIh1YzNHtjFtmOdT4h4bc1QDyMgY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA+swCEWY8xS8G4KkePmRWYxqgcCIdWMzR7YxbZjnU+IeG3NUA85ARuXHYQK/Sy6fb774buzt5a3DU2Va/o8Pz27k/FkM3v/AAAAAFYAAIAAAACAAAAAgAAAAAAAAAAAAAA=

    </details>

    tACK d5674f1

  115. S3RK commented at 7:14 AM on May 4, 2022: contributor

    I was also testing this PR and found one minor issue. analyzepsbt command doesn't correctly determine next role as "signer" for taproot inputs. This is due to the fact that SignTaproot doesn't fill SignatureData::missing_sigs.

    I'm not sure what is the best way to fix this as it's not always possible to know which signatures are missing for taproot inputs. Based on my current understanding, I propose:

    1. fill in SignatureData::missing_sigs as accurate as possible based on known information. Avoid providing wrong hints (e.g. when internal key is invalid)
    2. remove the check requiring missing_sigs to be non empty in src/node/psbt.cpp:77. I think the idea was to guide users as to what they need to proceed with the input. But this check is too strict for taproot as we don't always have this information, but still can determine that "signer" is the next role
  116. DrahtBot added the label Needs rebase on May 18, 2022
  117. achow101 force-pushed on May 18, 2022
  118. DrahtBot removed the label Needs rebase on May 18, 2022
  119. laanwj commented at 6:28 AM on June 14, 2022: member

    I was also testing this PR and found one minor issue. analyzepsbt command doesn't correctly determine next role as "signer" for taproot inputs.

    Is resolving this is a blocker for the PR or, is it something better done in a follow-up?

  120. achow101 commented at 3:13 AM on June 15, 2022: member

    Is resolving this is a blocker for the PR or, is it something better done in a follow-up?

    I think it can be done in a followup.

  121. Sjors commented at 9:11 AM on June 15, 2022: member

    @guggero I've pushed some commits that should fix that problem. Can you try again?

    Those two new commits could use a test case.

  122. in src/wallet/scriptpubkeyman.cpp:2187 in 2b006944f4 outdated
    2179 | @@ -2180,6 +2180,19 @@ TransactionError DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTransaction&
    2180 |                      *keys = Merge(*keys, *pk_keys);
    2181 |                  }
    2182 |              }
    2183 | +            for (const auto& pk_pair : input.m_tap_bip32_paths) {
    2184 | +                const XOnlyPubKey& pubkey = pk_pair.first;
    2185 | +                for (unsigned char prefix : {0x02, 0x03}) {
    2186 | +                    unsigned char b[33] = {prefix};
    2187 | +                    std::copy(pubkey.begin(), pubkey.end(), b + 1);
    


    laanwj commented at 1:45 PM on June 22, 2022:

    Should we assert the length of pubkey here to make sure this doesn't ever overflow the buffer?


    achow101 commented at 3:33 PM on June 23, 2022:

    XOnlyPubKey can only be 32 bytes, so I don't think it matters? It internally contains a uint256.

  123. in src/script/standard.cpp:655 in 2b006944f4 outdated
     648 | +    assert(IsComplete());
     649 | +    std::vector<std::tuple<uint8_t, uint8_t, CScript>> tuples;
     650 | +    if (m_branch.size()) {
     651 | +        const auto& leaves = m_branch[0]->leaves;
     652 | +        for (const auto& leaf : leaves) {
     653 | +            uint8_t depth = (uint8_t)leaf.merkle_branch.size();
    


    laanwj commented at 1:53 PM on June 22, 2022:

    Will this size always fit in a byte? Might want to assert here.


    achow101 commented at 7:02 PM on June 23, 2022:

    Added an assert.

  124. in src/psbt.h:620 in 2b006944f4 outdated
     615 | +                    } else if ((key.size() - 2) % 32 != 0) {
     616 | +                        throw std::ios_base::failure("Input Taproot leaf script key's control block size is not valid");
     617 | +                    }
     618 | +                    std::vector<unsigned char> script_v;
     619 | +                    s >> script_v;
     620 | +                    assert(!script_v.empty());
    


    laanwj commented at 2:39 PM on June 22, 2022:

    Is using an assert here dangerous? I mean, the application shouldn't crash on an invalid PSBT.


    Sjors commented at 3:18 PM on June 22, 2022:

    From commit 088e8366765dc7002e9cbcb45654e0709e233cd5. It's also not clear to me why this would be safe.


    achow101 commented at 7:03 PM on June 23, 2022:

    Changed the assert to just a check that script_v is not empty, and it will throw if it is.

  125. achow101 force-pushed on Jun 23, 2022
  126. achow101 commented at 7:02 PM on June 23, 2022: member

    Those two new commits could use a test case.

    Done.

  127. achow101 force-pushed on Jun 23, 2022
  128. Sjors commented at 1:11 PM on June 24, 2022: member

    mwallet_taproot.py CI failure, probably not spurious?

  129. in src/psbt.cpp:223 in 1db84e9aec outdated
     217 | @@ -177,6 +218,16 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
     218 |      for (const auto& key_pair : hd_keypaths) {
     219 |          sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
     220 |      }
     221 | +    if (!m_tap_internal_key.IsNull()) {
     222 | +        sigdata.tr_spenddata.internal_key = m_tap_internal_key;
     223 | +    }
     224 | +    if (!m_tap_tree.IsEmpty()) {
     225 | +        TaprootSpendData spenddata = m_tap_tree.GetSpendData();
    


    MarcoFalke commented at 1:17 PM on June 24, 2022:
     node1 stderr script/standard.cpp:498:53: runtime error: load of value 21, which is not a valid value for type 'bool'
        [#0](/github-metadata-backup-bitcoin-bitcoin/0/) 0x55ba8cce31d5 in TaprootBuilder::GetSpendData() const src/./src/script/standard.cpp:498:53
        [#1](/github-metadata-backup-bitcoin-bitcoin/1/) 0x55ba8cc138e9 in PSBTOutput::FillSignatureData(SignatureData&) const src/./src/psbt.cpp:225:49
    
    SUMMARY: UndefinedBehaviorSanitizer: invalid-bool-load script/standard.cpp:498:53 in 
    

    https://cirrus-ci.com/task/5083471289778176?logs=ci#L3013


    Sjors commented at 1:25 PM on June 24, 2022:

    Indeed, somehow m_parity got set to 21. Digging to see how that was achieved.


    Sjors commented at 1:34 PM on June 24, 2022:

    My guess is that it's unitialized because GetSpendData() was called before Finalize(). We should probably have an assert for that.


    achow101 commented at 3:27 PM on June 24, 2022:

    I've added a call to Finalize after parsing, so hopefully it works now.


    Sjors commented at 4:09 PM on June 24, 2022:
    'Finalize' has type 'const TaprootBuilder', but function is not marked const
            m_tap_tree.Finalize(m_tap_internal_key)
    

    achow101 commented at 6:41 PM on June 24, 2022:

    Fixed.

  130. achow101 force-pushed on Jun 24, 2022
  131. achow101 force-pushed on Jun 24, 2022
  132. achow101 force-pushed on Jun 24, 2022
  133. in src/psbt.h:620 in d94fffe683 outdated
     617 | @@ -618,7 +618,7 @@ struct PSBTInput
     618 |                      std::vector<unsigned char> script_v;
     619 |                      s >> script_v;
     620 |                      if (script_v.empty()) {
     621 | -                        throw std::ios_base:failure("Input Taproot leaf script must be at least 1 byte");
     622 | +                        throw std::ios_base::failure("Input Taproot leaf script must be at least 1 byte");
    


    Sjors commented at 1:48 PM on June 27, 2022:

    d94fffe683e2bffc0417e5bf72c2c78a9166e1e3: nit if you have to touch earlier commits, belongs in 324bba0d0b863f7bc3825d1efc3d405eb3894536


    achow101 commented at 8:44 PM on June 27, 2022:

    Done

  134. in test/functional/rpc_psbt.py:726 in d94fffe683 outdated
     722 | @@ -723,5 +723,46 @@ def test_psbt_input_keys(psbt_input, keys):
     723 |          )
     724 |          assert_equal(psbt2["fee"], psbt3["fee"])
     725 |  
     726 | +        self.log.info("Test signing inputs that the wallet has keys for but is not watching the scripts")
    


    Sjors commented at 1:57 PM on June 27, 2022:

    I assume this works for individual private keys, but not for master keys?

    I also seems to work if you have an xpriv and the descriptor has been expanded far enough. Might be good to add a test case for that behaviour too.


    achow101 commented at 8:45 PM on June 27, 2022:

    I assume this works for individual private keys, but not for master keys?

    Yes, we're not doing the dumb thing from legacy wallets where the seed key is a legitimate key we can receive at.

    I also seems to work if you have an xpriv and the descriptor has been expanded far enough. Might be good to add a test case for that behaviour too.

    Yes, that's the point, the test already covers that? Unless you mean something else.


    Sjors commented at 10:13 AM on June 28, 2022:

    Yes, we're not doing the dumb thing from legacy wallets where the seed key is a legitimate key we can receive at.

    That's not what I mean. I was referering to be able to sign with any key that derives from the seed, assuming a derivation path is given.

    Yes, that's the point, the test already covers that? Unless you mean something else.

    The test imports a single private key into the descriptor-less wallet, not an xpriv.


    achow101 commented at 2:46 PM on June 28, 2022:

    We will only sign with child keys. Anything that requires deriving other child keys from master keys is not supported.

  135. in test/functional/rpc_psbt.py:755 in d94fffe683 outdated
     750 | +        if self.options.descriptors:
     751 | +            eckey = ECKey()
     752 | +            eckey.generate()
     753 | +            privkey = bytes_to_wif(eckey.get_bytes())
     754 | +
     755 | +            desc = descsum_create("tr(50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0,pk({}))".format(eckey.get_pubkey().get_bytes().hex()))
    


    Sjors commented at 1:59 PM on June 27, 2022:

    d94fffe683e2bffc0417e5bf72c2c78a9166e1e3 where does the 5092…03ac0 keypath come from? I assume it's intentionally unspendable, but that's not super clear now.


    achow101 commented at 8:46 PM on June 27, 2022:

    From wallet_taproot.py, which got it from the BIP. I've refactored that into test_framework/key.py so that it can be shared.

  136. in src/wallet/scriptpubkeyman.cpp:2190 in 58a1a0c7a3 outdated
    2185 | +                for (unsigned char prefix : {0x02, 0x03}) {
    2186 | +                    unsigned char b[33] = {prefix};
    2187 | +                    std::copy(pubkey.begin(), pubkey.end(), b + 1);
    2188 | +                    CPubKey fullpubkey;
    2189 | +                    fullpubkey.Set(b, b + 33);
    2190 | +                    std::unique_ptr<FlatSigningProvider> pk_keys = GetSigningProvider(fullpubkey);
    


    Sjors commented at 2:14 PM on June 27, 2022:

    58a1a0c7a3f813c887d349ea3670584aff3773ad : we could probably use a GetSigningProvider specifically for XOnlyPubKey, but that can wait.

  137. in src/script/sign.cpp:233 in 37f6d29df5 outdated
     229 | @@ -230,16 +230,16 @@ static bool SignTaproot(const SigningProvider& provider, const BaseSignatureCrea
     230 |      // Try key path spending.
     231 |      {
     232 |          KeyOriginInfo info;
     233 | -        if (provider.GetKeyOriginByXOnly(spenddata.internal_key, info)) {
     234 | -            auto it = sigdata.taproot_misc_pubkeys.find(spenddata.internal_key);
     235 | +        if (provider.GetKeyOriginByXOnly(sigdata.tr_spenddata.internal_key, info)) {
    


    Sjors commented at 2:36 PM on June 27, 2022:

    37f6d29df5405d0cbebbb4368a6dcbc95c8f00e5 : maybe just squash this entire commit into f5e58b6b3dfa1622d7c03f82318ef06eb6c6818c or f7c7be9794d868a91c25a743f00b3fd351589d5f and add a comment along the lines of the commit message?


    achow101 commented at 8:47 PM on June 27, 2022:

    IMO it's a separate enough change that it should be its own commit.

  138. in src/script/standard.cpp:654 in d94fffe683 outdated
     649 | +    assert(IsComplete());
     650 | +    std::vector<std::tuple<uint8_t, uint8_t, CScript>> tuples;
     651 | +    if (m_branch.size()) {
     652 | +        const auto& leaves = m_branch[0]->leaves;
     653 | +        for (const auto& leaf : leaves) {
     654 | +            assert(leaf.merkle_branch.size() < TAPROOT_CONTROL_MAX_NODE_COUNT);
    


    Sjors commented at 2:45 PM on June 27, 2022:

    4542ba12866c5f9e7bb0da186800f2f5e450bea6: <= TAPROOT_CONTROL_MAX_NODE_COUNT ? See also TaprootBuilder::Insert. In descriptor.cpp we check branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT.


    achow101 commented at 8:47 PM on June 27, 2022:

    Fixed.

  139. Sjors approved
  140. Sjors commented at 2:53 PM on June 27, 2022: member

    utACK d94fffe683e2bffc0417e5bf72c2c78a9166e1e3 modulo <= question

  141. achow101 force-pushed on Jun 27, 2022
  142. achow101 force-pushed on Jun 27, 2022
  143. Move individual KeyOriginInfo de/ser to separate function
    To make it easier to de/serialize individual KeyOriginInfo for PSBTs,
    separate the actual de/serialization of KeyOriginInfo to its own
    function.
    
    This is an additional separation where any length prefix is processed by
    the caller.
    ce911204e4
  144. Add TaprootBuilder::GetTreeTuples
    GetTreeTuples returns the leaves in DFS order as tuples of depth, leaf
    version, and script. This is a representation of the tree that can be
    serialized.
    d43923c381
  145. Add serialization methods to XOnlyPubKey
    It is useful to have serialzation methods for XOnlyPubKey. These will
    serialize the internal uint256, so it is not prefixed with the length as
    CPubKey does.
    d557eff2ad
  146. Implement de/ser of PSBT's Taproot fields 05e2cc9a30
  147. Fill PSBT Taproot input data to/from SignatureData 52e3f2f88e
  148. Fetch key origins for Taproot keys 4d1223e512
  149. Store TaprootBuilder in SigningProviders instead of TaprootSpendData
    TaprootSpendData can be gotten from TaprootBuilder, however for PSBT, we
    also need TaprootBuilders directly (for the outputs). So we store the
    TaprootBuilder in the FlatSigningProvider and when the TaprootSpendData
    is needed, we generate it on the fly using the stored builder.
    3ae5b6af21
  150. Assert that TaprootBuilder is Finalized during GetSpendData
    GetSpendData needs to be finalized in order to be used. To avoid future
    bugs, assert `!m_output_key.IsNull()` as m_output_key is only set during
    Finalize.
    25b6ae46e7
  151. Fill PSBT Taproot output data to/from SignatureData ac7747585f
  152. Implement decodepsbt for Taproot fields 7dccdd3157
  153. psbt: Remove non_witness_utxo for segwit v1+
    If all inputs are segwit v1+, the non_witness_utxos can be removed.
    103c6fd279
  154. tests: Test taproot fields for PSBT 0ad21e7c55
  155. taproot: Use pre-existing signatures if available
    Actually use pre-existing signatures in CreateTaprootScriptSig if a
    signature is found for the given key and leaf hash.
    496a1bbe5e
  156. psbt, test: Check for taproot fields in taproot psbt test 1ece9a3715
  157. psbt: Implement merge for Taproot fields 5f12fe3f36
  158. sign: Use sigdata taproot spenddata when signing
    The taproot spenddata stored in a sigdata is the combination of data
    existing previously (e.g. in a PSBT) and the data stored in a
    SigningProvider. In order to use the external data when signing, we need
    to be using the sigdata's spenddata.
    6cff82722f
  159. wallet: also search taproot pubkeys in FillPSBT
    When filling a PSBT, we search the listed pubkeys in order to determine
    whether the current DescriptorScriptPubKeyMan could sign the transaction
    even if it is not watching the scripts. With Taproot, the taproot
    pubkeys need to be searched as well.
    a73b56888a
  160. test: Test signing psbts without explicitly having scripts b80de4c505
  161. achow101 force-pushed on Jun 27, 2022
  162. laanwj commented at 2:19 PM on June 28, 2022: member

    Code review ACK b80de4c505bf6377f2e476133dce6f2a803f1fa1

  163. laanwj merged this on Jun 28, 2022
  164. laanwj closed this on Jun 28, 2022

  165. sidhujag referenced this in commit 097323eeed on Jun 28, 2022
  166. MarcoFalke commented at 8:39 AM on June 30, 2022: member
  167. bitcoin deleted a comment on Jun 30, 2022
  168. Sjors commented at 11:39 AM on June 30, 2022: member

    @MarcoFalke that's a different one than we found: #22558#pullrequestreview-1018466595

    (not that that's great news)

  169. in src/psbt.h:869 in b80de4c505
     864 | +                        uint8_t leaf_ver;
     865 | +                        CScript script;
     866 | +                        s_tree >> depth;
     867 | +                        s_tree >> leaf_ver;
     868 | +                        s_tree >> script;
     869 | +                        m_tap_tree->Add((int)depth, script, (int)leaf_ver, true /* track */);
    


    Sjors commented at 1:28 PM on June 30, 2022:

    This is the only place where we call TaprootBuilder::Add (in this PR). We're not checking leaf_ver here, so with a corrupt PSBT the leaf_version & ~TAPROOT_LEAF_MASK assert gets hit.

  170. achow101 cross-referenced this on Jun 30, 2022 from issue psbt: Check Taproot tree depth and leaf versions by achow101
  171. azuchi referenced this in commit e505a537b3 on Jul 7, 2022
  172. MarcoFalke commented at 10:08 AM on July 19, 2022: member
  173. achow101 commented at 3:48 PM on July 19, 2022: member
  174. fanquake referenced this in commit 6900162aea on Jul 19, 2022
  175. sidhujag referenced this in commit 0420a41b55 on Jul 20, 2022
  176. fanquake referenced this in commit 28cf756971 on Oct 26, 2022
  177. sidhujag referenced this in commit b2fd8cd7be on Oct 27, 2022
  178. bitcoin locked this on Jul 19, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-05-20 06:53 UTC