transaction_utils.cpp raw

   1  // Copyright (c) 2019-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <coins.h>
   6  #include <consensus/validation.h>
   7  #include <script/signingprovider.h>
   8  #include <test/util/transaction_utils.h>
   9  
  10  CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, CAmount nValue)
  11  {
  12      CMutableTransaction txCredit;
  13      txCredit.version = 1;
  14      txCredit.nLockTime = 0;
  15      txCredit.vin.resize(1);
  16      txCredit.vout.resize(1);
  17      txCredit.vin[0].prevout.SetNull();
  18      txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
  19      txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
  20      txCredit.vout[0].scriptPubKey = scriptPubKey;
  21      txCredit.vout[0].nValue = nValue;
  22  
  23      return txCredit;
  24  }
  25  
  26  CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit)
  27  {
  28      CMutableTransaction txSpend;
  29      txSpend.version = 1;
  30      txSpend.nLockTime = 0;
  31      txSpend.vin.resize(1);
  32      txSpend.vout.resize(1);
  33      txSpend.vin[0].scriptWitness = scriptWitness;
  34      txSpend.vin[0].prevout.hash = txCredit.GetHash();
  35      txSpend.vin[0].prevout.n = 0;
  36      txSpend.vin[0].scriptSig = scriptSig;
  37      txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
  38      txSpend.vout[0].scriptPubKey = CScript();
  39      txSpend.vout[0].nValue = txCredit.vout[0].nValue;
  40  
  41      return txSpend;
  42  }
  43  
  44  std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues)
  45  {
  46      std::vector<CMutableTransaction> dummyTransactions;
  47      dummyTransactions.resize(2);
  48  
  49      // Add some keys to the keystore:
  50      CKey key[4];
  51      for (int i = 0; i < 4; i++) {
  52          key[i].MakeNewKey(i % 2);
  53          keystoreRet.AddKey(key[i]);
  54      }
  55  
  56      // Create some dummy input transactions
  57      dummyTransactions[0].vout.resize(2);
  58      dummyTransactions[0].vout[0].nValue = nValues[0];
  59      dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
  60      dummyTransactions[0].vout[1].nValue = nValues[1];
  61      dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
  62      AddCoins(coinsRet, CTransaction(dummyTransactions[0]), 0);
  63  
  64      dummyTransactions[1].vout.resize(2);
  65      dummyTransactions[1].vout[0].nValue = nValues[2];
  66      dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(PKHash(key[2].GetPubKey()));
  67      dummyTransactions[1].vout[1].nValue = nValues[3];
  68      dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(PKHash(key[3].GetPubKey()));
  69      AddCoins(coinsRet, CTransaction(dummyTransactions[1]), 0);
  70  
  71      return dummyTransactions;
  72  }
  73  
  74  void BulkTransaction(CMutableTransaction& tx, int32_t target_weight)
  75  {
  76      tx.vout.emplace_back(0, CScript() << OP_RETURN);
  77      auto unpadded_weight{GetTransactionWeight(CTransaction(tx))};
  78      assert(target_weight >= unpadded_weight);
  79  
  80      // determine number of needed padding bytes by converting weight difference to vbytes
  81      auto dummy_vbytes = (target_weight - unpadded_weight + (WITNESS_SCALE_FACTOR - 1)) / WITNESS_SCALE_FACTOR;
  82      // compensate for the increase of the compact-size encoded script length
  83      // (note that the length encoding of the unpadded output script needs one byte)
  84      dummy_vbytes -= GetSizeOfCompactSize(dummy_vbytes) - 1;
  85  
  86      // pad transaction by repeatedly appending a dummy opcode to the output script
  87      tx.vout[0].scriptPubKey.insert(tx.vout[0].scriptPubKey.end(), dummy_vbytes, OP_1);
  88  
  89      // actual weight should be at most 3 higher than target weight
  90      assert(GetTransactionWeight(CTransaction(tx)) >= target_weight);
  91      assert(GetTransactionWeight(CTransaction(tx)) <= target_weight + 3);
  92  }
  93  
  94  bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, const CAmount& amount, int nHashType, SignatureData& sig_data)
  95  {
  96      assert(nIn < txTo.vin.size());
  97  
  98      MutableTransactionSignatureCreator creator(txTo, nIn, amount, {.sighash_type = nHashType});
  99  
 100      bool ret = ProduceSignature(provider, creator, fromPubKey, sig_data);
 101      UpdateInput(txTo.vin.at(nIn), sig_data);
 102      return ret;
 103  }
 104  
 105  bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType, SignatureData& sig_data)
 106  {
 107      assert(nIn < txTo.vin.size());
 108      const CTxIn& txin = txTo.vin[nIn];
 109      assert(txin.prevout.n < txFrom.vout.size());
 110      const CTxOut& txout = txFrom.vout[txin.prevout.n];
 111  
 112      return SignSignature(provider, txout.scriptPubKey, txTo, nIn, txout.nValue, nHashType, sig_data);
 113  }
 114