/ src / bitcoin-tx.cpp
bitcoin-tx.cpp
  1  // Copyright (c) 2009-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep
  6  
  7  #include <chainparamsbase.h>
  8  #include <clientversion.h>
  9  #include <coins.h>
 10  #include <common/args.h>
 11  #include <common/system.h>
 12  #include <compat/compat.h>
 13  #include <consensus/amount.h>
 14  #include <consensus/consensus.h>
 15  #include <core_io.h>
 16  #include <key_io.h>
 17  #include <policy/policy.h>
 18  #include <primitives/transaction.h>
 19  #include <script/script.h>
 20  #include <script/sign.h>
 21  #include <script/signingprovider.h>
 22  #include <univalue.h>
 23  #include <util/exception.h>
 24  #include <util/fs.h>
 25  #include <util/moneystr.h>
 26  #include <util/rbf.h>
 27  #include <util/strencodings.h>
 28  #include <util/string.h>
 29  #include <util/translation.h>
 30  
 31  #include <cstdio>
 32  #include <functional>
 33  #include <memory>
 34  
 35  using util::SplitString;
 36  using util::ToString;
 37  using util::TrimString;
 38  using util::TrimStringView;
 39  
 40  static bool fCreateBlank;
 41  static std::map<std::string,UniValue> registers;
 42  static const int CONTINUE_EXECUTION=-1;
 43  
 44  const TranslateFn G_TRANSLATION_FUN{nullptr};
 45  
 46  static void SetupBitcoinTxArgs(ArgsManager &argsman)
 47  {
 48      SetupHelpOptions(argsman);
 49  
 50      argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 51      argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 52      argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 53      argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 54      SetupChainParamsBaseOptions(argsman);
 55  
 56      argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 57      argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 58      argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 59      argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 60      argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 61      argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 62      argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 63      argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "
 64          "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
 65          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 66      argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. "
 67          "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. "
 68          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 69      argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
 70          "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
 71          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 72      argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. "
 73          "If N is not provided, the command attempts to opt-in all available inputs for RBF. "
 74          "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 75      argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
 76          "This command requires JSON registers:"
 77          "prevtxs=JSON object, "
 78          "privatekeys=JSON object. "
 79          "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 80  
 81      argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
 82      argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
 83  }
 84  
 85  //
 86  // This function returns either one of EXIT_ codes when it's expected to stop the process or
 87  // CONTINUE_EXECUTION when it's expected to continue further.
 88  //
 89  static int AppInitRawTx(int argc, char* argv[])
 90  {
 91      SetupBitcoinTxArgs(gArgs);
 92      std::string error;
 93      if (!gArgs.ParseParameters(argc, argv, error)) {
 94          tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
 95          return EXIT_FAILURE;
 96      }
 97  
 98      // Check for chain settings (Params() calls are only valid after this clause)
 99      try {
100          SelectParams(gArgs.GetChainType());
101      } catch (const std::exception& e) {
102          tfm::format(std::cerr, "Error: %s\n", e.what());
103          return EXIT_FAILURE;
104      }
105  
106      fCreateBlank = gArgs.GetBoolArg("-create", false);
107  
108      if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
109          // First part of help message is specific to this utility
110          std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";
111  
112          if (gArgs.GetBoolArg("-version", false)) {
113              strUsage += FormatParagraph(LicenseInfo());
114          } else {
115              strUsage += "\n"
116                  "The bitcoin-tx tool is used for creating and modifying bitcoin transactions.\n\n"
117                  "bitcoin-tx can be used with \"<hex-tx> [commands]\" to update a hex-encoded bitcoin transaction, or with \"-create [commands]\" to create a hex-encoded bitcoin transaction.\n"
118                  "\n"
119                  "Usage: bitcoin-tx [options] <hex-tx> [commands]\n"
120                  "or:    bitcoin-tx [options] -create [commands]\n"
121                  "\n";
122              strUsage += gArgs.GetHelpMessage();
123          }
124  
125          tfm::format(std::cout, "%s", strUsage);
126  
127          if (argc < 2) {
128              tfm::format(std::cerr, "Error: too few parameters\n");
129              return EXIT_FAILURE;
130          }
131          return EXIT_SUCCESS;
132      }
133      return CONTINUE_EXECUTION;
134  }
135  
136  static void RegisterSetJson(const std::string& key, const std::string& rawJson)
137  {
138      UniValue val;
139      if (!val.read(rawJson)) {
140          std::string strErr = "Cannot parse JSON for key " + key;
141          throw std::runtime_error(strErr);
142      }
143  
144      registers[key] = val;
145  }
146  
147  static void RegisterSet(const std::string& strInput)
148  {
149      // separate NAME:VALUE in string
150      size_t pos = strInput.find(':');
151      if ((pos == std::string::npos) ||
152          (pos == 0) ||
153          (pos == (strInput.size() - 1)))
154          throw std::runtime_error("Register input requires NAME:VALUE");
155  
156      std::string key = strInput.substr(0, pos);
157      std::string valStr = strInput.substr(pos + 1, std::string::npos);
158  
159      RegisterSetJson(key, valStr);
160  }
161  
162  static void RegisterLoad(const std::string& strInput)
163  {
164      // separate NAME:FILENAME in string
165      size_t pos = strInput.find(':');
166      if ((pos == std::string::npos) ||
167          (pos == 0) ||
168          (pos == (strInput.size() - 1)))
169          throw std::runtime_error("Register load requires NAME:FILENAME");
170  
171      std::string key = strInput.substr(0, pos);
172      std::string filename = strInput.substr(pos + 1, std::string::npos);
173  
174      FILE *f = fsbridge::fopen(filename.c_str(), "r");
175      if (!f) {
176          std::string strErr = "Cannot open file " + filename;
177          throw std::runtime_error(strErr);
178      }
179  
180      // load file chunks into one big buffer
181      std::string valStr;
182      while ((!feof(f)) && (!ferror(f))) {
183          char buf[4096];
184          int bread = fread(buf, 1, sizeof(buf), f);
185          if (bread <= 0)
186              break;
187  
188          valStr.insert(valStr.size(), buf, bread);
189      }
190  
191      int error = ferror(f);
192      fclose(f);
193  
194      if (error) {
195          std::string strErr = "Error reading file " + filename;
196          throw std::runtime_error(strErr);
197      }
198  
199      // evaluate as JSON buffer register
200      RegisterSetJson(key, valStr);
201  }
202  
203  static CAmount ExtractAndValidateValue(const std::string& strValue)
204  {
205      if (std::optional<CAmount> parsed = ParseMoney(strValue)) {
206          return parsed.value();
207      } else {
208          throw std::runtime_error("invalid TX output value");
209      }
210  }
211  
212  static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
213  {
214      const auto ver{ToIntegral<uint32_t>(cmdVal)};
215      if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) {
216          throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
217      }
218      tx.version = *ver;
219  }
220  
221  static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
222  {
223      const auto locktime{ToIntegral<uint32_t>(cmdVal)};
224      if (!locktime) {
225          throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
226      }
227      tx.nLockTime = *locktime;
228  }
229  
230  static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
231  {
232      const auto idx{ToIntegral<uint32_t>(strInIdx)};
233      if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) {
234          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
235      }
236  
237      // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
238      uint32_t cnt{0};
239      for (CTxIn& txin : tx.vin) {
240          if (strInIdx == "" || cnt == *idx) {
241              if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
242                  txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
243              }
244          }
245          ++cnt;
246      }
247  }
248  
249  template <typename T>
250  static T TrimAndParse(const std::string& int_str, const std::string& err)
251  {
252      const auto parsed{ToIntegral<T>(TrimStringView(int_str))};
253      if (!parsed.has_value()) {
254          throw std::runtime_error(err + " '" + int_str + "'");
255      }
256      return parsed.value();
257  }
258  
259  static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
260  {
261      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
262  
263      // separate TXID:VOUT in string
264      if (vStrInputParts.size()<2)
265          throw std::runtime_error("TX input missing separator");
266  
267      // extract and validate TXID
268      auto txid{Txid::FromHex(vStrInputParts[0])};
269      if (!txid) {
270          throw std::runtime_error("invalid TX input txid");
271      }
272  
273      static const unsigned int minTxOutSz = 9;
274      static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
275  
276      // extract and validate vout
277      const std::string& strVout = vStrInputParts[1];
278      const auto vout{ToIntegral<uint32_t>(strVout)};
279      if (!vout || *vout > maxVout) {
280          throw std::runtime_error("invalid TX input vout '" + strVout + "'");
281      }
282  
283      // extract the optional sequence number
284      uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
285      if (vStrInputParts.size() > 2) {
286          nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id");
287      }
288  
289      // append to transaction input list
290      CTxIn txin{*txid, *vout, CScript{}, nSequenceIn};
291      tx.vin.push_back(txin);
292  }
293  
294  static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
295  {
296      // Separate into VALUE:ADDRESS
297      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
298  
299      if (vStrInputParts.size() != 2)
300          throw std::runtime_error("TX output missing or too many separators");
301  
302      // Extract and validate VALUE
303      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
304  
305      // extract and validate ADDRESS
306      const std::string& strAddr = vStrInputParts[1];
307      CTxDestination destination = DecodeDestination(strAddr);
308      if (!IsValidDestination(destination)) {
309          throw std::runtime_error("invalid TX output address");
310      }
311      CScript scriptPubKey = GetScriptForDestination(destination);
312  
313      // construct TxOut, append to transaction output list
314      CTxOut txout(value, scriptPubKey);
315      tx.vout.push_back(txout);
316  }
317  
318  static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
319  {
320      // Separate into VALUE:PUBKEY[:FLAGS]
321      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
322  
323      if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
324          throw std::runtime_error("TX output missing or too many separators");
325  
326      // Extract and validate VALUE
327      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
328  
329      // Extract and validate PUBKEY
330      CPubKey pubkey(ParseHex(vStrInputParts[1]));
331      if (!pubkey.IsFullyValid())
332          throw std::runtime_error("invalid TX output pubkey");
333      CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
334  
335      // Extract and validate FLAGS
336      bool bSegWit = false;
337      bool bScriptHash = false;
338      if (vStrInputParts.size() == 3) {
339          const std::string& flags = vStrInputParts[2];
340          bSegWit = (flags.find('W') != std::string::npos);
341          bScriptHash = (flags.find('S') != std::string::npos);
342      }
343  
344      if (bSegWit) {
345          if (!pubkey.IsCompressed()) {
346              throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
347          }
348          // Build a P2WPKH script
349          scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey));
350      }
351      if (bScriptHash) {
352          // Get the ID for the script, and then construct a P2SH destination for it.
353          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
354      }
355  
356      // construct TxOut, append to transaction output list
357      CTxOut txout(value, scriptPubKey);
358      tx.vout.push_back(txout);
359  }
360  
361  static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
362  {
363      // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
364      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
365  
366      // Check that there are enough parameters
367      if (vStrInputParts.size()<3)
368          throw std::runtime_error("Not enough multisig parameters");
369  
370      // Extract and validate VALUE
371      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
372  
373      // Extract REQUIRED
374      const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")};
375  
376      // Extract NUMKEYS
377      const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")};
378  
379      // Validate there are the correct number of pubkeys
380      if (vStrInputParts.size() < numkeys + 3)
381          throw std::runtime_error("incorrect number of multisig pubkeys");
382  
383      if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required)
384          throw std::runtime_error("multisig parameter mismatch. Required " \
385                              + ToString(required) + " of " + ToString(numkeys) + "signatures.");
386  
387      // extract and validate PUBKEYs
388      std::vector<CPubKey> pubkeys;
389      for(int pos = 1; pos <= int(numkeys); pos++) {
390          CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
391          if (!pubkey.IsFullyValid())
392              throw std::runtime_error("invalid TX output pubkey");
393          pubkeys.push_back(pubkey);
394      }
395  
396      // Extract FLAGS
397      bool bSegWit = false;
398      bool bScriptHash = false;
399      if (vStrInputParts.size() == numkeys + 4) {
400          const std::string& flags = vStrInputParts.back();
401          bSegWit = (flags.find('W') != std::string::npos);
402          bScriptHash = (flags.find('S') != std::string::npos);
403      }
404      else if (vStrInputParts.size() > numkeys + 4) {
405          // Validate that there were no more parameters passed
406          throw std::runtime_error("Too many parameters");
407      }
408  
409      CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
410  
411      if (bSegWit) {
412          for (const CPubKey& pubkey : pubkeys) {
413              if (!pubkey.IsCompressed()) {
414                  throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
415              }
416          }
417          // Build a P2WSH with the multisig script
418          scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
419      }
420      if (bScriptHash) {
421          if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
422              throw std::runtime_error(strprintf(
423                          "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
424          }
425          // Get the ID for the script, and then construct a P2SH destination for it.
426          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
427      }
428  
429      // construct TxOut, append to transaction output list
430      CTxOut txout(value, scriptPubKey);
431      tx.vout.push_back(txout);
432  }
433  
434  static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
435  {
436      CAmount value = 0;
437  
438      // separate [VALUE:]DATA in string
439      size_t pos = strInput.find(':');
440  
441      if (pos==0)
442          throw std::runtime_error("TX output value not specified");
443  
444      if (pos == std::string::npos) {
445          pos = 0;
446      } else {
447          // Extract and validate VALUE
448          value = ExtractAndValidateValue(strInput.substr(0, pos));
449          ++pos;
450      }
451  
452      // extract and validate DATA
453      const std::string strData{strInput.substr(pos, std::string::npos)};
454  
455      if (!IsHex(strData))
456          throw std::runtime_error("invalid TX output data");
457  
458      std::vector<unsigned char> data = ParseHex(strData);
459  
460      CTxOut txout(value, CScript() << OP_RETURN << data);
461      tx.vout.push_back(txout);
462  }
463  
464  static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
465  {
466      // separate VALUE:SCRIPT[:FLAGS]
467      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
468      if (vStrInputParts.size() < 2)
469          throw std::runtime_error("TX output missing separator");
470  
471      // Extract and validate VALUE
472      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
473  
474      // extract and validate script
475      const std::string& strScript = vStrInputParts[1];
476      CScript scriptPubKey = ParseScript(strScript);
477  
478      // Extract FLAGS
479      bool bSegWit = false;
480      bool bScriptHash = false;
481      if (vStrInputParts.size() == 3) {
482          const std::string& flags = vStrInputParts.back();
483          bSegWit = (flags.find('W') != std::string::npos);
484          bScriptHash = (flags.find('S') != std::string::npos);
485      }
486  
487      if (scriptPubKey.size() > MAX_SCRIPT_SIZE) {
488          throw std::runtime_error(strprintf(
489                      "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE));
490      }
491  
492      if (bSegWit) {
493          scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
494      }
495      if (bScriptHash) {
496          if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
497              throw std::runtime_error(strprintf(
498                          "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
499          }
500          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
501      }
502  
503      // construct TxOut, append to transaction output list
504      CTxOut txout(value, scriptPubKey);
505      tx.vout.push_back(txout);
506  }
507  
508  static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
509  {
510      const auto idx{ToIntegral<uint32_t>(strInIdx)};
511      if (!idx || idx >= tx.vin.size()) {
512          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
513      }
514      tx.vin.erase(tx.vin.begin() + *idx);
515  }
516  
517  static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
518  {
519      const auto idx{ToIntegral<uint32_t>(strOutIdx)};
520      if (!idx || idx >= tx.vout.size()) {
521          throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
522      }
523      tx.vout.erase(tx.vout.begin() + *idx);
524  }
525  
526  static const unsigned int N_SIGHASH_OPTS = 7;
527  static const struct {
528      const char *flagStr;
529      int flags;
530  } sighashOptions[N_SIGHASH_OPTS] = {
531      {"DEFAULT", SIGHASH_DEFAULT},
532      {"ALL", SIGHASH_ALL},
533      {"NONE", SIGHASH_NONE},
534      {"SINGLE", SIGHASH_SINGLE},
535      {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
536      {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
537      {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
538  };
539  
540  static bool findSighashFlags(int& flags, const std::string& flagStr)
541  {
542      flags = 0;
543  
544      for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
545          if (flagStr == sighashOptions[i].flagStr) {
546              flags = sighashOptions[i].flags;
547              return true;
548          }
549      }
550  
551      return false;
552  }
553  
554  static CAmount AmountFromValue(const UniValue& value)
555  {
556      if (!value.isNum() && !value.isStr())
557          throw std::runtime_error("Amount is not a number or string");
558      CAmount amount;
559      if (!ParseFixedPoint(value.getValStr(), 8, &amount))
560          throw std::runtime_error("Invalid amount");
561      if (!MoneyRange(amount))
562          throw std::runtime_error("Amount out of range");
563      return amount;
564  }
565  
566  static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
567  {
568      std::string strHex;
569      if (v.isStr())
570          strHex = v.getValStr();
571      if (!IsHex(strHex))
572          throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
573      return ParseHex(strHex);
574  }
575  
576  static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
577  {
578      int nHashType = SIGHASH_ALL;
579  
580      if (flagStr.size() > 0)
581          if (!findSighashFlags(nHashType, flagStr))
582              throw std::runtime_error("unknown sighash flag/sign option");
583  
584      // mergedTx will end up with all the signatures; it
585      // starts as a clone of the raw tx:
586      CMutableTransaction mergedTx{tx};
587      const CMutableTransaction txv{tx};
588      CCoinsView viewDummy;
589      CCoinsViewCache view(&viewDummy);
590  
591      if (!registers.count("privatekeys"))
592          throw std::runtime_error("privatekeys register variable must be set.");
593      FillableSigningProvider tempKeystore;
594      UniValue keysObj = registers["privatekeys"];
595  
596      for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
597          if (!keysObj[kidx].isStr())
598              throw std::runtime_error("privatekey not a std::string");
599          CKey key = DecodeSecret(keysObj[kidx].getValStr());
600          if (!key.IsValid()) {
601              throw std::runtime_error("privatekey not valid");
602          }
603          tempKeystore.AddKey(key);
604      }
605  
606      // Add previous txouts given in the RPC call:
607      if (!registers.count("prevtxs"))
608          throw std::runtime_error("prevtxs register variable must be set.");
609      UniValue prevtxsObj = registers["prevtxs"];
610      {
611          for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
612              const UniValue& prevOut = prevtxsObj[previdx];
613              if (!prevOut.isObject())
614                  throw std::runtime_error("expected prevtxs internal object");
615  
616              std::map<std::string, UniValue::VType> types = {
617                  {"txid", UniValue::VSTR},
618                  {"vout", UniValue::VNUM},
619                  {"scriptPubKey", UniValue::VSTR},
620              };
621              if (!prevOut.checkObject(types))
622                  throw std::runtime_error("prevtxs internal object typecheck fail");
623  
624              auto txid{Txid::FromHex(prevOut["txid"].get_str())};
625              if (!txid) {
626                  throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')");
627              }
628  
629              const int nOut = prevOut["vout"].getInt<int>();
630              if (nOut < 0)
631                  throw std::runtime_error("vout cannot be negative");
632  
633              COutPoint out(*txid, nOut);
634              std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
635              CScript scriptPubKey(pkData.begin(), pkData.end());
636  
637              {
638                  const Coin& coin = view.AccessCoin(out);
639                  if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
640                      std::string err("Previous output scriptPubKey mismatch:\n");
641                      err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
642                          ScriptToAsmStr(scriptPubKey);
643                      throw std::runtime_error(err);
644                  }
645                  Coin newcoin;
646                  newcoin.out.scriptPubKey = scriptPubKey;
647                  newcoin.out.nValue = MAX_MONEY;
648                  if (prevOut.exists("amount")) {
649                      newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
650                  }
651                  newcoin.nHeight = 1;
652                  view.AddCoin(out, std::move(newcoin), true);
653              }
654  
655              // if redeemScript given and private keys given,
656              // add redeemScript to the tempKeystore so it can be signed:
657              if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
658                  prevOut.exists("redeemScript")) {
659                  UniValue v = prevOut["redeemScript"];
660                  std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
661                  CScript redeemScript(rsData.begin(), rsData.end());
662                  tempKeystore.AddCScript(redeemScript);
663              }
664          }
665      }
666  
667      const FillableSigningProvider& keystore = tempKeystore;
668  
669      bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
670  
671      // Sign what we can:
672      for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
673          CTxIn& txin = mergedTx.vin[i];
674          const Coin& coin = view.AccessCoin(txin.prevout);
675          if (coin.IsSpent()) {
676              continue;
677          }
678          const CScript& prevPubKey = coin.out.scriptPubKey;
679          const CAmount& amount = coin.out.nValue;
680  
681          SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
682          // Only sign SIGHASH_SINGLE if there's a corresponding output:
683          if (!fHashSingle || (i < mergedTx.vout.size()))
684              ProduceSignature(keystore, MutableTransactionSignatureCreator(mergedTx, i, amount, nHashType), prevPubKey, sigdata);
685  
686          if (amount == MAX_MONEY && !sigdata.scriptWitness.IsNull()) {
687              throw std::runtime_error(strprintf("Missing amount for CTxOut with scriptPubKey=%s", HexStr(prevPubKey)));
688          }
689  
690          UpdateInput(txin, sigdata);
691      }
692  
693      tx = mergedTx;
694  }
695  
696  static void MutateTx(CMutableTransaction& tx, const std::string& command,
697                       const std::string& commandVal)
698  {
699      std::unique_ptr<ECC_Context> ecc;
700  
701      if (command == "nversion")
702          MutateTxVersion(tx, commandVal);
703      else if (command == "locktime")
704          MutateTxLocktime(tx, commandVal);
705      else if (command == "replaceable") {
706          MutateTxRBFOptIn(tx, commandVal);
707      }
708  
709      else if (command == "delin")
710          MutateTxDelInput(tx, commandVal);
711      else if (command == "in")
712          MutateTxAddInput(tx, commandVal);
713  
714      else if (command == "delout")
715          MutateTxDelOutput(tx, commandVal);
716      else if (command == "outaddr")
717          MutateTxAddOutAddr(tx, commandVal);
718      else if (command == "outpubkey") {
719          ecc.reset(new ECC_Context());
720          MutateTxAddOutPubKey(tx, commandVal);
721      } else if (command == "outmultisig") {
722          ecc.reset(new ECC_Context());
723          MutateTxAddOutMultiSig(tx, commandVal);
724      } else if (command == "outscript")
725          MutateTxAddOutScript(tx, commandVal);
726      else if (command == "outdata")
727          MutateTxAddOutData(tx, commandVal);
728  
729      else if (command == "sign") {
730          ecc.reset(new ECC_Context());
731          MutateTxSign(tx, commandVal);
732      }
733  
734      else if (command == "load")
735          RegisterLoad(commandVal);
736  
737      else if (command == "set")
738          RegisterSet(commandVal);
739  
740      else
741          throw std::runtime_error("unknown command");
742  }
743  
744  static void OutputTxJSON(const CTransaction& tx)
745  {
746      UniValue entry(UniValue::VOBJ);
747      TxToUniv(tx, /*block_hash=*/uint256(), entry);
748  
749      std::string jsonOutput = entry.write(4);
750      tfm::format(std::cout, "%s\n", jsonOutput);
751  }
752  
753  static void OutputTxHash(const CTransaction& tx)
754  {
755      std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
756  
757      tfm::format(std::cout, "%s\n", strHexHash);
758  }
759  
760  static void OutputTxHex(const CTransaction& tx)
761  {
762      std::string strHex = EncodeHexTx(tx);
763  
764      tfm::format(std::cout, "%s\n", strHex);
765  }
766  
767  static void OutputTx(const CTransaction& tx)
768  {
769      if (gArgs.GetBoolArg("-json", false))
770          OutputTxJSON(tx);
771      else if (gArgs.GetBoolArg("-txid", false))
772          OutputTxHash(tx);
773      else
774          OutputTxHex(tx);
775  }
776  
777  static std::string readStdin()
778  {
779      char buf[4096];
780      std::string ret;
781  
782      while (!feof(stdin)) {
783          size_t bread = fread(buf, 1, sizeof(buf), stdin);
784          ret.append(buf, bread);
785          if (bread < sizeof(buf))
786              break;
787      }
788  
789      if (ferror(stdin))
790          throw std::runtime_error("error reading stdin");
791  
792      return TrimString(ret);
793  }
794  
795  static int CommandLineRawTx(int argc, char* argv[])
796  {
797      std::string strPrint;
798      int nRet = 0;
799      try {
800          // Skip switches; Permit common stdin convention "-"
801          while (argc > 1 && IsSwitchChar(argv[1][0]) &&
802                 (argv[1][1] != 0)) {
803              argc--;
804              argv++;
805          }
806  
807          CMutableTransaction tx;
808          int startArg;
809  
810          if (!fCreateBlank) {
811              // require at least one param
812              if (argc < 2)
813                  throw std::runtime_error("too few parameters");
814  
815              // param: hex-encoded bitcoin transaction
816              std::string strHexTx(argv[1]);
817              if (strHexTx == "-")                 // "-" implies standard input
818                  strHexTx = readStdin();
819  
820              if (!DecodeHexTx(tx, strHexTx, true))
821                  throw std::runtime_error("invalid transaction encoding");
822  
823              startArg = 2;
824          } else
825              startArg = 1;
826  
827          for (int i = startArg; i < argc; i++) {
828              std::string arg = argv[i];
829              std::string key, value;
830              size_t eqpos = arg.find('=');
831              if (eqpos == std::string::npos)
832                  key = arg;
833              else {
834                  key = arg.substr(0, eqpos);
835                  value = arg.substr(eqpos + 1);
836              }
837  
838              MutateTx(tx, key, value);
839          }
840  
841          OutputTx(CTransaction(tx));
842      }
843      catch (const std::exception& e) {
844          strPrint = std::string("error: ") + e.what();
845          nRet = EXIT_FAILURE;
846      }
847      catch (...) {
848          PrintExceptionContinue(nullptr, "CommandLineRawTx()");
849          throw;
850      }
851  
852      if (strPrint != "") {
853          tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
854      }
855      return nRet;
856  }
857  
858  MAIN_FUNCTION
859  {
860      SetupEnvironment();
861  
862      try {
863          int ret = AppInitRawTx(argc, argv);
864          if (ret != CONTINUE_EXECUTION)
865              return ret;
866      }
867      catch (const std::exception& e) {
868          PrintExceptionContinue(&e, "AppInitRawTx()");
869          return EXIT_FAILURE;
870      } catch (...) {
871          PrintExceptionContinue(nullptr, "AppInitRawTx()");
872          return EXIT_FAILURE;
873      }
874  
875      int ret = EXIT_FAILURE;
876      try {
877          ret = CommandLineRawTx(argc, argv);
878      }
879      catch (const std::exception& e) {
880          PrintExceptionContinue(&e, "CommandLineRawTx()");
881      } catch (...) {
882          PrintExceptionContinue(nullptr, "CommandLineRawTx()");
883      }
884      return ret;
885  }