psbt_tests.cpp raw

   1  // Copyright (c) 2022 The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or https://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <psbt.h>
   6  
   7  #include <boost/test/unit_test.hpp>
   8  #include <test/util/setup_common.h>
   9  
  10  BOOST_FIXTURE_TEST_SUITE(psbt_tests, BasicTestingSetup)
  11  
  12  static PSBTProprietary MakeProprietary(uint64_t subtype, uint8_t key_data, uint8_t value)
  13  {
  14      return PSBTProprietary{
  15          .subtype = subtype,
  16          .identifier = {'p', 's', 'b', 't'},
  17          .key = {key_data},
  18          .value = {value},
  19      };
  20  }
  21  
  22  void CheckTimeLock(const std::string& base64_psbt, std::optional<uint32_t> timelock)
  23  {
  24      util::Result<PartiallySignedTransaction> psbt = DecodeBase64PSBT(base64_psbt);
  25      BOOST_CHECK(psbt);
  26  
  27      std::optional<uint32_t> computed_timelock = psbt->ComputeTimeLock();
  28      std::optional<CMutableTransaction> tx = psbt->GetUnsignedTx();
  29      if (timelock) {
  30          BOOST_CHECK(computed_timelock);
  31          BOOST_CHECK_EQUAL(*computed_timelock, *timelock);
  32          BOOST_CHECK(tx);
  33          BOOST_CHECK_EQUAL(tx->nLockTime, *timelock);
  34      } else {
  35          BOOST_CHECK(!computed_timelock);
  36          BOOST_CHECK(!tx);
  37      }
  38  }
  39  
  40  BOOST_AUTO_TEST_CASE(psbt2_timelock_test)
  41  {
  42      CheckTimeLock("cHNidP8BAgQCAAAAAQQBAQEFAQIB+wQCAAAAAAEOIAsK2SFBnByHGXNdctxzn56p4GONH+TB7vD5lECEgV/IAQ8EAAAAAAABAwgACK8vAAAAAAEEFgAUxDD2TEdW2jENvRoIVXLvKZkmJywAAQMIi73rCwAAAAABBBYAFE3Rk6yWSlasG54cyoRU/i9HT4UTAA==", 0);
  43      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAAAAQ4gOhs7PIN9ZInqejHY5sfdUDwAG+8+BpWOdXSAjWjKeKUBDwQAAAAAAAEDCE+TNXcAAAAAAQQWABQLE1LKzQPPaqG388jWOIZxs0peEQA=", 0);
  44      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEgQQJwAAAAEOIDobOzyDfWSJ6nox2ObH3VA8ABvvPgaVjnV0gI1oynilAQ8EAAAAAAABAwhPkzV3AAAAAAEEFgAUCxNSys0Dz2qht/PI1jiGcbNKXhEA", 10000);
  45      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEgQQJwAAAAEOIDobOzyDfWSJ6nox2ObH3VA8ABvvPgaVjnV0gI1oynilAQ8EAAAAAAESBCgjAAAAAQMIT5M1dwAAAAABBBYAFAsTUsrNA89qobfzyNY4hnGzSl4RAA==", 10000);
  46      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEgQQJwAAAAEOIDobOzyDfWSJ6nox2ObH3VA8ABvvPgaVjnV0gI1oynilAQ8EAAAAAAERBIyNxGIBEgQoIwAAAAEDCE+TNXcAAAAAAQQWABQLE1LKzQPPaqG388jWOIZxs0peEQA=", 10000);
  47      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEQSLjcRiARIEECcAAAABDiA6Gzs8g31kiep6Mdjmx91QPAAb7z4GlY51dICNaMp4pQEPBAAAAAABEQSMjcRiARIEKCMAAAABAwhPkzV3AAAAAAEEFgAUCxNSys0Dz2qht/PI1jiGcbNKXhEA", 10000);
  48      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEQSLjcRiAAEOIDobOzyDfWSJ6nox2ObH3VA8ABvvPgaVjnV0gI1oynilAQ8EAAAAAAERBIyNxGIBEgQoIwAAAAEDCE+TNXcAAAAAAQQWABQLE1LKzQPPaqG388jWOIZxs0peEQA=", 1657048460);
  49      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEQSLjcRiARIEECcAAAABDiA6Gzs8g31kiep6Mdjmx91QPAAb7z4GlY51dICNaMp4pQEPBAAAAAABEQSMjcRiAAEDCE+TNXcAAAAAAQQWABQLE1LKzQPPaqG388jWOIZxs0peEQA=", 1657048460);
  50      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAAAAQ4gOhs7PIN9ZInqejHY5sfdUDwAG+8+BpWOdXSAjWjKeKUBDwQAAAAAAREEjI3EYgABAwhPkzV3AAAAAAEEFgAUCxNSys0Dz2qht/PI1jiGcbNKXhEA", 1657048460);
  51      CheckTimeLock("cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAfsEAgAAAAABDiAPdY2/vU2nwWyKMwnDyB4RAPVh6mRttbAXUsSF4b3enwEPBAEAAAABEgQQJwAAAAEOIDobOzyDfWSJ6nox2ObH3VA8ABvvPgaVjnV0gI1oynilAQ8EAAAAAAERBIyNxGIAAQMIT5M1dwAAAAABBBYAFAsTUsrNA89qobfzyNY4hnGzSl4RAA==", std::nullopt);
  52  }
  53  
  54  BOOST_AUTO_TEST_CASE(psbt2_addinput)
  55  {
  56      FastRandomContext rng(/*fDeterministic=*/true);
  57  
  58      CMutableTransaction mtx;
  59      PartiallySignedTransaction psbt(mtx, /*version=*/2);
  60      psbt.m_tx_modifiable.emplace();
  61      psbt.m_tx_modifiable->set(0, true);
  62      BOOST_CHECK_EQUAL(psbt.inputs.size(), 0);
  63  
  64      // Same PSBT version is required
  65      uint256 txid;
  66      rng.fillrand(MakeWritableByteSpan(txid));
  67      PSBTInput psbtin_v0(/*psbt_version=*/0, Txid::FromUint256(txid), /*prev_out=*/0);
  68      BOOST_CHECK(!psbt.AddInput(psbtin_v0));
  69      BOOST_CHECK_EQUAL(psbt.inputs.size(), 0);
  70      rng.fillrand(MakeWritableByteSpan(txid));
  71      PSBTInput psbtin(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
  72      BOOST_CHECK(psbt.AddInput(psbtin));
  73      BOOST_CHECK_EQUAL(psbt.inputs.size(), 1);
  74  
  75      // Duplicates are not allowed
  76      BOOST_CHECK(!psbt.AddInput(psbtin));
  77      BOOST_CHECK_EQUAL(psbt.inputs.size(), 1);
  78  
  79      // Input with a unique txid is allowed
  80      rng.fillrand(MakeWritableByteSpan(txid));
  81      PSBTInput psbtin2(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
  82      BOOST_CHECK(psbt.AddInput(psbtin2));
  83      BOOST_CHECK_EQUAL(psbt.inputs.size(), 2);
  84  
  85      // Disabling inputs modifiable flag prevents adding new inputs
  86      psbt.m_tx_modifiable->set(0, false);
  87      rng.fillrand(MakeWritableByteSpan(txid));
  88      PSBTInput psbtin3(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
  89      BOOST_CHECK(!psbt.AddInput(psbtin3));
  90      BOOST_CHECK_EQUAL(psbt.inputs.size(), 2);
  91      psbt.m_tx_modifiable->set(0, true);
  92  
  93      // Make sure that timelock compatibility checks are working
  94      // No previous required timelocks, new input with both height and time timelocks is allowed
  95      rng.fillrand(MakeWritableByteSpan(txid));
  96      PSBTInput psbtin4(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
  97      psbtin4.time_locktime = LOCKTIME_THRESHOLD;
  98      psbtin4.height_locktime = 100;
  99      BOOST_CHECK(psbt.AddInput(psbtin4));
 100      BOOST_CHECK_EQUAL(psbt.inputs.size(), 3);
 101  
 102      // Input with only a time timelock is allowed
 103      rng.fillrand(MakeWritableByteSpan(txid));
 104      PSBTInput psbtin5(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
 105      psbtin5.time_locktime = LOCKTIME_THRESHOLD + 1;
 106      BOOST_CHECK(psbt.AddInput(psbtin5));
 107      BOOST_CHECK_EQUAL(psbt.inputs.size(), 4);
 108  
 109      // Input with only a height timelock is not allowed because of previous
 110      rng.fillrand(MakeWritableByteSpan(txid));
 111      PSBTInput psbtin6(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
 112      psbtin6.height_locktime = 100;
 113      BOOST_CHECK(!psbt.AddInput(psbtin6));
 114      BOOST_CHECK_EQUAL(psbt.inputs.size(), 4);
 115  
 116      // Adding an input that already has a signature is allowed
 117      rng.fillrand(MakeWritableByteSpan(txid));
 118      PSBTInput psbtin7(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
 119      psbtin7.final_script_sig << OP_1;
 120      BOOST_CHECK(psbt.AddInput(psbtin7));
 121      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 122  
 123      // Same thing, but with other things that have signatures
 124      psbtin7.final_script_sig.clear();
 125      psbtin7.final_script_witness.stack.emplace_back();
 126      BOOST_CHECK(!psbt.AddInput(psbtin7));
 127      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 128      psbtin7.final_script_witness.SetNull();
 129      psbtin7.partial_sigs.emplace();
 130      BOOST_CHECK(!psbt.AddInput(psbtin7));
 131      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 132      psbtin7.partial_sigs.clear();
 133      psbtin7.m_tap_key_sig.push_back(0);
 134      BOOST_CHECK(!psbt.AddInput(psbtin7));
 135      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 136      psbtin7.m_tap_key_sig.clear();
 137      psbtin7.m_tap_script_sigs.emplace();
 138      BOOST_CHECK(!psbt.AddInput(psbtin7));
 139      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 140      psbtin7.m_tap_script_sigs.clear();
 141      psbtin7.m_musig2_partial_sigs.emplace();
 142      BOOST_CHECK(!psbt.AddInput(psbtin7));
 143      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 144  
 145      // Adding an input that changes the timelock is no longer allowed
 146      rng.fillrand(MakeWritableByteSpan(txid));
 147      PSBTInput psbtin8(/*psbt_version=*/2, Txid::FromUint256(txid), /*prev_out=*/0);
 148      psbtin8.time_locktime = LOCKTIME_THRESHOLD + 2;
 149      BOOST_CHECK(!psbt.AddInput(psbtin8));
 150      BOOST_CHECK_EQUAL(psbt.inputs.size(), 5);
 151  }
 152  
 153  BOOST_AUTO_TEST_CASE(psbt2_addoutput)
 154  {
 155      CMutableTransaction mtx;
 156      PartiallySignedTransaction psbt(mtx, /*version=*/2);
 157      psbt.m_tx_modifiable.emplace();
 158      psbt.m_tx_modifiable->set(1, true);
 159      BOOST_CHECK_EQUAL(psbt.outputs.size(), 0);
 160  
 161      // Same PSBT version is required
 162      PSBTOutput psbtout_v0(/*psbt_version=*/0, /*amount=*/1, CScript());
 163      BOOST_CHECK(!psbt.AddOutput(psbtout_v0));
 164      BOOST_CHECK_EQUAL(psbt.outputs.size(), 0);
 165      PSBTOutput psbtout(/*psbt_version=*/2, /*amount=*/1, CScript());
 166      BOOST_CHECK(psbt.AddOutput(psbtout));
 167      BOOST_CHECK_EQUAL(psbt.outputs.size(), 1);
 168  
 169      // Disabling outputs modifiable flag prevents adding new outputs
 170      psbt.m_tx_modifiable->set(1, false);
 171      PSBTOutput psbtout2(/*psbt_version=*/2, /*amount=*/1, CScript());
 172      BOOST_CHECK(!psbt.AddOutput(psbtout2));
 173      BOOST_CHECK_EQUAL(psbt.outputs.size(), 1);
 174      psbt.m_tx_modifiable->set(1, true);
 175      PSBTOutput psbtout3(/*psbt_version=*/2, /*amount=*/1, CScript());
 176      BOOST_CHECK(psbt.AddOutput(psbtout3));
 177      BOOST_CHECK_EQUAL(psbt.outputs.size(), 2);
 178  }
 179  
 180  BOOST_AUTO_TEST_CASE(merge_proprietary_fields)
 181  {
 182      CMutableTransaction tx;
 183      tx.vin.emplace_back(COutPoint{});
 184      tx.vout.emplace_back(0, CScript{});
 185  
 186      PartiallySignedTransaction left(tx);
 187      PartiallySignedTransaction right(tx);
 188  
 189      const auto left_prop = MakeProprietary(/*subtype=*/1, /*key_data=*/0x01, /*value=*/0xaa);
 190      const auto right_prop = MakeProprietary(/*subtype=*/2, /*key_data=*/0x02, /*value=*/0xbb);
 191  
 192      left.m_proprietary.insert(left_prop);
 193      left.inputs[0].m_proprietary.insert(left_prop);
 194      left.outputs[0].m_proprietary.insert(left_prop);
 195  
 196      right.m_proprietary.insert(right_prop);
 197      right.inputs[0].m_proprietary.insert(right_prop);
 198      right.outputs[0].m_proprietary.insert(right_prop);
 199  
 200      BOOST_REQUIRE(left.Merge(right));
 201  
 202      BOOST_REQUIRE_EQUAL(left.m_proprietary.size(), 2U);
 203      BOOST_REQUIRE_EQUAL(left.inputs[0].m_proprietary.size(), 2U);
 204      BOOST_REQUIRE_EQUAL(left.outputs[0].m_proprietary.size(), 2U);
 205  
 206      const auto global_it = left.m_proprietary.find(right_prop);
 207      BOOST_REQUIRE(global_it != left.m_proprietary.end());
 208      BOOST_CHECK(global_it->value == right_prop.value);
 209  
 210      const auto input_it = left.inputs[0].m_proprietary.find(right_prop);
 211      BOOST_REQUIRE(input_it != left.inputs[0].m_proprietary.end());
 212      BOOST_CHECK(input_it->value == right_prop.value);
 213  
 214      const auto output_it = left.outputs[0].m_proprietary.find(right_prop);
 215      BOOST_REQUIRE(output_it != left.outputs[0].m_proprietary.end());
 216      BOOST_CHECK(output_it->value == right_prop.value);
 217  }
 218  
 219  BOOST_AUTO_TEST_SUITE_END()
 220