/ 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      uint32_t newVersion;
215      if (!ParseUInt32(cmdVal, &newVersion) || newVersion < 1 || newVersion > TX_MAX_STANDARD_VERSION) {
216          throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
217      }
218  
219      tx.version = newVersion;
220  }
221  
222  static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
223  {
224      int64_t newLocktime;
225      if (!ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
226          throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
227  
228      tx.nLockTime = (unsigned int) newLocktime;
229  }
230  
231  static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
232  {
233      // parse requested index
234      int64_t inIdx = -1;
235      if (strInIdx != "" && (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size()))) {
236          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
237      }
238  
239      // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
240      int cnt = 0;
241      for (CTxIn& txin : tx.vin) {
242          if (strInIdx == "" || cnt == inIdx) {
243              if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
244                  txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
245              }
246          }
247          ++cnt;
248      }
249  }
250  
251  template <typename T>
252  static T TrimAndParse(const std::string& int_str, const std::string& err)
253  {
254      const auto parsed{ToIntegral<T>(TrimStringView(int_str))};
255      if (!parsed.has_value()) {
256          throw std::runtime_error(err + " '" + int_str + "'");
257      }
258      return parsed.value();
259  }
260  
261  static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
262  {
263      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
264  
265      // separate TXID:VOUT in string
266      if (vStrInputParts.size()<2)
267          throw std::runtime_error("TX input missing separator");
268  
269      // extract and validate TXID
270      auto txid{Txid::FromHex(vStrInputParts[0])};
271      if (!txid) {
272          throw std::runtime_error("invalid TX input txid");
273      }
274  
275      static const unsigned int minTxOutSz = 9;
276      static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
277  
278      // extract and validate vout
279      const std::string& strVout = vStrInputParts[1];
280      int64_t vout;
281      if (!ParseInt64(strVout, &vout) || vout < 0 || vout > static_cast<int64_t>(maxVout))
282          throw std::runtime_error("invalid TX input vout '" + strVout + "'");
283  
284      // extract the optional sequence number
285      uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
286      if (vStrInputParts.size() > 2) {
287          nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id");
288      }
289  
290      // append to transaction input list
291      CTxIn txin(*txid, vout, CScript(), nSequenceIn);
292      tx.vin.push_back(txin);
293  }
294  
295  static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
296  {
297      // Separate into VALUE:ADDRESS
298      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
299  
300      if (vStrInputParts.size() != 2)
301          throw std::runtime_error("TX output missing or too many separators");
302  
303      // Extract and validate VALUE
304      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
305  
306      // extract and validate ADDRESS
307      const std::string& strAddr = vStrInputParts[1];
308      CTxDestination destination = DecodeDestination(strAddr);
309      if (!IsValidDestination(destination)) {
310          throw std::runtime_error("invalid TX output address");
311      }
312      CScript scriptPubKey = GetScriptForDestination(destination);
313  
314      // construct TxOut, append to transaction output list
315      CTxOut txout(value, scriptPubKey);
316      tx.vout.push_back(txout);
317  }
318  
319  static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
320  {
321      // Separate into VALUE:PUBKEY[:FLAGS]
322      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
323  
324      if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
325          throw std::runtime_error("TX output missing or too many separators");
326  
327      // Extract and validate VALUE
328      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
329  
330      // Extract and validate PUBKEY
331      CPubKey pubkey(ParseHex(vStrInputParts[1]));
332      if (!pubkey.IsFullyValid())
333          throw std::runtime_error("invalid TX output pubkey");
334      CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
335  
336      // Extract and validate FLAGS
337      bool bSegWit = false;
338      bool bScriptHash = false;
339      if (vStrInputParts.size() == 3) {
340          const std::string& flags = vStrInputParts[2];
341          bSegWit = (flags.find('W') != std::string::npos);
342          bScriptHash = (flags.find('S') != std::string::npos);
343      }
344  
345      if (bSegWit) {
346          if (!pubkey.IsCompressed()) {
347              throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
348          }
349          // Build a P2WPKH script
350          scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey));
351      }
352      if (bScriptHash) {
353          // Get the ID for the script, and then construct a P2SH destination for it.
354          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
355      }
356  
357      // construct TxOut, append to transaction output list
358      CTxOut txout(value, scriptPubKey);
359      tx.vout.push_back(txout);
360  }
361  
362  static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
363  {
364      // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
365      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
366  
367      // Check that there are enough parameters
368      if (vStrInputParts.size()<3)
369          throw std::runtime_error("Not enough multisig parameters");
370  
371      // Extract and validate VALUE
372      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
373  
374      // Extract REQUIRED
375      const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")};
376  
377      // Extract NUMKEYS
378      const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")};
379  
380      // Validate there are the correct number of pubkeys
381      if (vStrInputParts.size() < numkeys + 3)
382          throw std::runtime_error("incorrect number of multisig pubkeys");
383  
384      if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required)
385          throw std::runtime_error("multisig parameter mismatch. Required " \
386                              + ToString(required) + " of " + ToString(numkeys) + "signatures.");
387  
388      // extract and validate PUBKEYs
389      std::vector<CPubKey> pubkeys;
390      for(int pos = 1; pos <= int(numkeys); pos++) {
391          CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
392          if (!pubkey.IsFullyValid())
393              throw std::runtime_error("invalid TX output pubkey");
394          pubkeys.push_back(pubkey);
395      }
396  
397      // Extract FLAGS
398      bool bSegWit = false;
399      bool bScriptHash = false;
400      if (vStrInputParts.size() == numkeys + 4) {
401          const std::string& flags = vStrInputParts.back();
402          bSegWit = (flags.find('W') != std::string::npos);
403          bScriptHash = (flags.find('S') != std::string::npos);
404      }
405      else if (vStrInputParts.size() > numkeys + 4) {
406          // Validate that there were no more parameters passed
407          throw std::runtime_error("Too many parameters");
408      }
409  
410      CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
411  
412      if (bSegWit) {
413          for (const CPubKey& pubkey : pubkeys) {
414              if (!pubkey.IsCompressed()) {
415                  throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
416              }
417          }
418          // Build a P2WSH with the multisig script
419          scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
420      }
421      if (bScriptHash) {
422          if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
423              throw std::runtime_error(strprintf(
424                          "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
425          }
426          // Get the ID for the script, and then construct a P2SH destination for it.
427          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
428      }
429  
430      // construct TxOut, append to transaction output list
431      CTxOut txout(value, scriptPubKey);
432      tx.vout.push_back(txout);
433  }
434  
435  static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
436  {
437      CAmount value = 0;
438  
439      // separate [VALUE:]DATA in string
440      size_t pos = strInput.find(':');
441  
442      if (pos==0)
443          throw std::runtime_error("TX output value not specified");
444  
445      if (pos == std::string::npos) {
446          pos = 0;
447      } else {
448          // Extract and validate VALUE
449          value = ExtractAndValidateValue(strInput.substr(0, pos));
450          ++pos;
451      }
452  
453      // extract and validate DATA
454      const std::string strData{strInput.substr(pos, std::string::npos)};
455  
456      if (!IsHex(strData))
457          throw std::runtime_error("invalid TX output data");
458  
459      std::vector<unsigned char> data = ParseHex(strData);
460  
461      CTxOut txout(value, CScript() << OP_RETURN << data);
462      tx.vout.push_back(txout);
463  }
464  
465  static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
466  {
467      // separate VALUE:SCRIPT[:FLAGS]
468      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
469      if (vStrInputParts.size() < 2)
470          throw std::runtime_error("TX output missing separator");
471  
472      // Extract and validate VALUE
473      CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
474  
475      // extract and validate script
476      const std::string& strScript = vStrInputParts[1];
477      CScript scriptPubKey = ParseScript(strScript);
478  
479      // Extract FLAGS
480      bool bSegWit = false;
481      bool bScriptHash = false;
482      if (vStrInputParts.size() == 3) {
483          const std::string& flags = vStrInputParts.back();
484          bSegWit = (flags.find('W') != std::string::npos);
485          bScriptHash = (flags.find('S') != std::string::npos);
486      }
487  
488      if (scriptPubKey.size() > MAX_SCRIPT_SIZE) {
489          throw std::runtime_error(strprintf(
490                      "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE));
491      }
492  
493      if (bSegWit) {
494          scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
495      }
496      if (bScriptHash) {
497          if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
498              throw std::runtime_error(strprintf(
499                          "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
500          }
501          scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
502      }
503  
504      // construct TxOut, append to transaction output list
505      CTxOut txout(value, scriptPubKey);
506      tx.vout.push_back(txout);
507  }
508  
509  static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
510  {
511      // parse requested deletion index
512      int64_t inIdx;
513      if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
514          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
515      }
516  
517      // delete input from transaction
518      tx.vin.erase(tx.vin.begin() + inIdx);
519  }
520  
521  static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
522  {
523      // parse requested deletion index
524      int64_t outIdx;
525      if (!ParseInt64(strOutIdx, &outIdx) || outIdx < 0 || outIdx >= static_cast<int64_t>(tx.vout.size())) {
526          throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
527      }
528  
529      // delete output from transaction
530      tx.vout.erase(tx.vout.begin() + outIdx);
531  }
532  
533  static const unsigned int N_SIGHASH_OPTS = 7;
534  static const struct {
535      const char *flagStr;
536      int flags;
537  } sighashOptions[N_SIGHASH_OPTS] = {
538      {"DEFAULT", SIGHASH_DEFAULT},
539      {"ALL", SIGHASH_ALL},
540      {"NONE", SIGHASH_NONE},
541      {"SINGLE", SIGHASH_SINGLE},
542      {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
543      {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
544      {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
545  };
546  
547  static bool findSighashFlags(int& flags, const std::string& flagStr)
548  {
549      flags = 0;
550  
551      for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
552          if (flagStr == sighashOptions[i].flagStr) {
553              flags = sighashOptions[i].flags;
554              return true;
555          }
556      }
557  
558      return false;
559  }
560  
561  static CAmount AmountFromValue(const UniValue& value)
562  {
563      if (!value.isNum() && !value.isStr())
564          throw std::runtime_error("Amount is not a number or string");
565      CAmount amount;
566      if (!ParseFixedPoint(value.getValStr(), 8, &amount))
567          throw std::runtime_error("Invalid amount");
568      if (!MoneyRange(amount))
569          throw std::runtime_error("Amount out of range");
570      return amount;
571  }
572  
573  static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
574  {
575      std::string strHex;
576      if (v.isStr())
577          strHex = v.getValStr();
578      if (!IsHex(strHex))
579          throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
580      return ParseHex(strHex);
581  }
582  
583  static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
584  {
585      int nHashType = SIGHASH_ALL;
586  
587      if (flagStr.size() > 0)
588          if (!findSighashFlags(nHashType, flagStr))
589              throw std::runtime_error("unknown sighash flag/sign option");
590  
591      // mergedTx will end up with all the signatures; it
592      // starts as a clone of the raw tx:
593      CMutableTransaction mergedTx{tx};
594      const CMutableTransaction txv{tx};
595      CCoinsView viewDummy;
596      CCoinsViewCache view(&viewDummy);
597  
598      if (!registers.count("privatekeys"))
599          throw std::runtime_error("privatekeys register variable must be set.");
600      FillableSigningProvider tempKeystore;
601      UniValue keysObj = registers["privatekeys"];
602  
603      for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
604          if (!keysObj[kidx].isStr())
605              throw std::runtime_error("privatekey not a std::string");
606          CKey key = DecodeSecret(keysObj[kidx].getValStr());
607          if (!key.IsValid()) {
608              throw std::runtime_error("privatekey not valid");
609          }
610          tempKeystore.AddKey(key);
611      }
612  
613      // Add previous txouts given in the RPC call:
614      if (!registers.count("prevtxs"))
615          throw std::runtime_error("prevtxs register variable must be set.");
616      UniValue prevtxsObj = registers["prevtxs"];
617      {
618          for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
619              const UniValue& prevOut = prevtxsObj[previdx];
620              if (!prevOut.isObject())
621                  throw std::runtime_error("expected prevtxs internal object");
622  
623              std::map<std::string, UniValue::VType> types = {
624                  {"txid", UniValue::VSTR},
625                  {"vout", UniValue::VNUM},
626                  {"scriptPubKey", UniValue::VSTR},
627              };
628              if (!prevOut.checkObject(types))
629                  throw std::runtime_error("prevtxs internal object typecheck fail");
630  
631              auto txid{Txid::FromHex(prevOut["txid"].get_str())};
632              if (!txid) {
633                  throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')");
634              }
635  
636              const int nOut = prevOut["vout"].getInt<int>();
637              if (nOut < 0)
638                  throw std::runtime_error("vout cannot be negative");
639  
640              COutPoint out(*txid, nOut);
641              std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
642              CScript scriptPubKey(pkData.begin(), pkData.end());
643  
644              {
645                  const Coin& coin = view.AccessCoin(out);
646                  if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
647                      std::string err("Previous output scriptPubKey mismatch:\n");
648                      err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
649                          ScriptToAsmStr(scriptPubKey);
650                      throw std::runtime_error(err);
651                  }
652                  Coin newcoin;
653                  newcoin.out.scriptPubKey = scriptPubKey;
654                  newcoin.out.nValue = MAX_MONEY;
655                  if (prevOut.exists("amount")) {
656                      newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
657                  }
658                  newcoin.nHeight = 1;
659                  view.AddCoin(out, std::move(newcoin), true);
660              }
661  
662              // if redeemScript given and private keys given,
663              // add redeemScript to the tempKeystore so it can be signed:
664              if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
665                  prevOut.exists("redeemScript")) {
666                  UniValue v = prevOut["redeemScript"];
667                  std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
668                  CScript redeemScript(rsData.begin(), rsData.end());
669                  tempKeystore.AddCScript(redeemScript);
670              }
671          }
672      }
673  
674      const FillableSigningProvider& keystore = tempKeystore;
675  
676      bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
677  
678      // Sign what we can:
679      for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
680          CTxIn& txin = mergedTx.vin[i];
681          const Coin& coin = view.AccessCoin(txin.prevout);
682          if (coin.IsSpent()) {
683              continue;
684          }
685          const CScript& prevPubKey = coin.out.scriptPubKey;
686          const CAmount& amount = coin.out.nValue;
687  
688          SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
689          // Only sign SIGHASH_SINGLE if there's a corresponding output:
690          if (!fHashSingle || (i < mergedTx.vout.size()))
691              ProduceSignature(keystore, MutableTransactionSignatureCreator(mergedTx, i, amount, nHashType), prevPubKey, sigdata);
692  
693          if (amount == MAX_MONEY && !sigdata.scriptWitness.IsNull()) {
694              throw std::runtime_error(strprintf("Missing amount for CTxOut with scriptPubKey=%s", HexStr(prevPubKey)));
695          }
696  
697          UpdateInput(txin, sigdata);
698      }
699  
700      tx = mergedTx;
701  }
702  
703  static void MutateTx(CMutableTransaction& tx, const std::string& command,
704                       const std::string& commandVal)
705  {
706      std::unique_ptr<ECC_Context> ecc;
707  
708      if (command == "nversion")
709          MutateTxVersion(tx, commandVal);
710      else if (command == "locktime")
711          MutateTxLocktime(tx, commandVal);
712      else if (command == "replaceable") {
713          MutateTxRBFOptIn(tx, commandVal);
714      }
715  
716      else if (command == "delin")
717          MutateTxDelInput(tx, commandVal);
718      else if (command == "in")
719          MutateTxAddInput(tx, commandVal);
720  
721      else if (command == "delout")
722          MutateTxDelOutput(tx, commandVal);
723      else if (command == "outaddr")
724          MutateTxAddOutAddr(tx, commandVal);
725      else if (command == "outpubkey") {
726          ecc.reset(new ECC_Context());
727          MutateTxAddOutPubKey(tx, commandVal);
728      } else if (command == "outmultisig") {
729          ecc.reset(new ECC_Context());
730          MutateTxAddOutMultiSig(tx, commandVal);
731      } else if (command == "outscript")
732          MutateTxAddOutScript(tx, commandVal);
733      else if (command == "outdata")
734          MutateTxAddOutData(tx, commandVal);
735  
736      else if (command == "sign") {
737          ecc.reset(new ECC_Context());
738          MutateTxSign(tx, commandVal);
739      }
740  
741      else if (command == "load")
742          RegisterLoad(commandVal);
743  
744      else if (command == "set")
745          RegisterSet(commandVal);
746  
747      else
748          throw std::runtime_error("unknown command");
749  }
750  
751  static void OutputTxJSON(const CTransaction& tx)
752  {
753      UniValue entry(UniValue::VOBJ);
754      TxToUniv(tx, /*block_hash=*/uint256(), entry);
755  
756      std::string jsonOutput = entry.write(4);
757      tfm::format(std::cout, "%s\n", jsonOutput);
758  }
759  
760  static void OutputTxHash(const CTransaction& tx)
761  {
762      std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
763  
764      tfm::format(std::cout, "%s\n", strHexHash);
765  }
766  
767  static void OutputTxHex(const CTransaction& tx)
768  {
769      std::string strHex = EncodeHexTx(tx);
770  
771      tfm::format(std::cout, "%s\n", strHex);
772  }
773  
774  static void OutputTx(const CTransaction& tx)
775  {
776      if (gArgs.GetBoolArg("-json", false))
777          OutputTxJSON(tx);
778      else if (gArgs.GetBoolArg("-txid", false))
779          OutputTxHash(tx);
780      else
781          OutputTxHex(tx);
782  }
783  
784  static std::string readStdin()
785  {
786      char buf[4096];
787      std::string ret;
788  
789      while (!feof(stdin)) {
790          size_t bread = fread(buf, 1, sizeof(buf), stdin);
791          ret.append(buf, bread);
792          if (bread < sizeof(buf))
793              break;
794      }
795  
796      if (ferror(stdin))
797          throw std::runtime_error("error reading stdin");
798  
799      return TrimString(ret);
800  }
801  
802  static int CommandLineRawTx(int argc, char* argv[])
803  {
804      std::string strPrint;
805      int nRet = 0;
806      try {
807          // Skip switches; Permit common stdin convention "-"
808          while (argc > 1 && IsSwitchChar(argv[1][0]) &&
809                 (argv[1][1] != 0)) {
810              argc--;
811              argv++;
812          }
813  
814          CMutableTransaction tx;
815          int startArg;
816  
817          if (!fCreateBlank) {
818              // require at least one param
819              if (argc < 2)
820                  throw std::runtime_error("too few parameters");
821  
822              // param: hex-encoded bitcoin transaction
823              std::string strHexTx(argv[1]);
824              if (strHexTx == "-")                 // "-" implies standard input
825                  strHexTx = readStdin();
826  
827              if (!DecodeHexTx(tx, strHexTx, true))
828                  throw std::runtime_error("invalid transaction encoding");
829  
830              startArg = 2;
831          } else
832              startArg = 1;
833  
834          for (int i = startArg; i < argc; i++) {
835              std::string arg = argv[i];
836              std::string key, value;
837              size_t eqpos = arg.find('=');
838              if (eqpos == std::string::npos)
839                  key = arg;
840              else {
841                  key = arg.substr(0, eqpos);
842                  value = arg.substr(eqpos + 1);
843              }
844  
845              MutateTx(tx, key, value);
846          }
847  
848          OutputTx(CTransaction(tx));
849      }
850      catch (const std::exception& e) {
851          strPrint = std::string("error: ") + e.what();
852          nRet = EXIT_FAILURE;
853      }
854      catch (...) {
855          PrintExceptionContinue(nullptr, "CommandLineRawTx()");
856          throw;
857      }
858  
859      if (strPrint != "") {
860          tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
861      }
862      return nRet;
863  }
864  
865  MAIN_FUNCTION
866  {
867      SetupEnvironment();
868  
869      try {
870          int ret = AppInitRawTx(argc, argv);
871          if (ret != CONTINUE_EXECUTION)
872              return ret;
873      }
874      catch (const std::exception& e) {
875          PrintExceptionContinue(&e, "AppInitRawTx()");
876          return EXIT_FAILURE;
877      } catch (...) {
878          PrintExceptionContinue(nullptr, "AppInitRawTx()");
879          return EXIT_FAILURE;
880      }
881  
882      int ret = EXIT_FAILURE;
883      try {
884          ret = CommandLineRawTx(argc, argv);
885      }
886      catch (const std::exception& e) {
887          PrintExceptionContinue(&e, "CommandLineRawTx()");
888      } catch (...) {
889          PrintExceptionContinue(nullptr, "CommandLineRawTx()");
890      }
891      return ret;
892  }