/ src / bitcoin-tx.cpp
bitcoin-tx.cpp
  1  // Copyright (c) 2009-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 <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/license_info.h>
 12  #include <common/system.h>
 13  #include <compat/compat.h>
 14  #include <consensus/amount.h>
 15  #include <consensus/consensus.h>
 16  #include <core_io.h>
 17  #include <key_io.h>
 18  #include <policy/policy.h>
 19  #include <primitives/transaction.h>
 20  #include <script/script.h>
 21  #include <script/sign.h>
 22  #include <script/signingprovider.h>
 23  #include <univalue.h>
 24  #include <util/exception.h>
 25  #include <util/fs.h>
 26  #include <util/moneystr.h>
 27  #include <util/rbf.h>
 28  #include <util/strencodings.h>
 29  #include <util/string.h>
 30  #include <util/translation.h>
 31  
 32  #include <cstdio>
 33  #include <functional>
 34  #include <memory>
 35  
 36  using util::SplitString;
 37  using util::ToString;
 38  using util::TrimString;
 39  using util::TrimStringView;
 40  
 41  static bool fCreateBlank;
 42  static std::map<std::string,UniValue> registers;
 43  static const int CONTINUE_EXECUTION=-1;
 44  
 45  const TranslateFn G_TRANSLATION_FUN{nullptr};
 46  
 47  static void SetupBitcoinTxArgs(ArgsManager &argsman)
 48  {
 49      SetupHelpOptions(argsman);
 50  
 51      argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 52      argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 53      argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 54      argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
 55      SetupChainParamsBaseOptions(argsman);
 56  
 57      argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 58      argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 59      argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 60      argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 61      argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 62      argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 63      argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 64      argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "
 65          "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
 66          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 67      argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. "
 68          "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. "
 69          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 70      argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
 71          "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
 72          "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 73      argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. "
 74          "If N is not provided, the command attempts to opt-in all available inputs for RBF. "
 75          "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 76      argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
 77          "This command requires JSON registers:"
 78          "prevtxs=JSON object, "
 79          "privatekeys=JSON object. "
 80          "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
 81  
 82      argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
 83      argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
 84  }
 85  
 86  //
 87  // This function returns either one of EXIT_ codes when it's expected to stop the process or
 88  // CONTINUE_EXECUTION when it's expected to continue further.
 89  //
 90  static int AppInitRawTx(int argc, char* argv[])
 91  {
 92      SetupBitcoinTxArgs(gArgs);
 93      std::string error;
 94      if (!gArgs.ParseParameters(argc, argv, error)) {
 95          tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
 96          return EXIT_FAILURE;
 97      }
 98  
 99      // Check for chain settings (Params() calls are only valid after this clause)
100      try {
101          SelectParams(gArgs.GetChainType());
102      } catch (const std::exception& e) {
103          tfm::format(std::cerr, "Error: %s\n", e.what());
104          return EXIT_FAILURE;
105      }
106  
107      fCreateBlank = gArgs.GetBoolArg("-create", false);
108  
109      if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {
110          // First part of help message is specific to this utility
111          std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";
112  
113          if (gArgs.GetBoolArg("-version", false)) {
114              strUsage += FormatParagraph(LicenseInfo());
115          } else {
116              strUsage += "\n"
117                  "The bitcoin-tx tool is used for creating and modifying bitcoin transactions.\n\n"
118                  "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"
119                  "\n"
120                  "Usage: bitcoin-tx [options] <hex-tx> [commands]\n"
121                  "or:    bitcoin-tx [options] -create [commands]\n"
122                  "\n";
123              strUsage += gArgs.GetHelpMessage();
124          }
125  
126          tfm::format(std::cout, "%s", strUsage);
127  
128          if (argc < 2) {
129              tfm::format(std::cerr, "Error: too few parameters\n");
130              return EXIT_FAILURE;
131          }
132          return EXIT_SUCCESS;
133      }
134      return CONTINUE_EXECUTION;
135  }
136  
137  static void RegisterSetJson(const std::string& key, const std::string& rawJson)
138  {
139      UniValue val;
140      if (!val.read(rawJson)) {
141          std::string strErr = "Cannot parse JSON for key " + key;
142          throw std::runtime_error(strErr);
143      }
144  
145      registers[key] = val;
146  }
147  
148  static void RegisterSet(const std::string& strInput)
149  {
150      // separate NAME:VALUE in string
151      size_t pos = strInput.find(':');
152      if ((pos == std::string::npos) ||
153          (pos == 0) ||
154          (pos == (strInput.size() - 1)))
155          throw std::runtime_error("Register input requires NAME:VALUE");
156  
157      std::string key = strInput.substr(0, pos);
158      std::string valStr = strInput.substr(pos + 1, std::string::npos);
159  
160      RegisterSetJson(key, valStr);
161  }
162  
163  static void RegisterLoad(const std::string& strInput)
164  {
165      // separate NAME:FILENAME in string
166      size_t pos = strInput.find(':');
167      if ((pos == std::string::npos) ||
168          (pos == 0) ||
169          (pos == (strInput.size() - 1)))
170          throw std::runtime_error("Register load requires NAME:FILENAME");
171  
172      std::string key = strInput.substr(0, pos);
173      std::string filename = strInput.substr(pos + 1, std::string::npos);
174  
175      FILE *f = fsbridge::fopen(filename.c_str(), "r");
176      if (!f) {
177          std::string strErr = "Cannot open file " + filename;
178          throw std::runtime_error(strErr);
179      }
180  
181      // load file chunks into one big buffer
182      std::string valStr;
183      while ((!feof(f)) && (!ferror(f))) {
184          char buf[4096];
185          int bread = fread(buf, 1, sizeof(buf), f);
186          if (bread <= 0)
187              break;
188  
189          valStr.insert(valStr.size(), buf, bread);
190      }
191  
192      int error = ferror(f);
193      fclose(f);
194  
195      if (error) {
196          std::string strErr = "Error reading file " + filename;
197          throw std::runtime_error(strErr);
198      }
199  
200      // evaluate as JSON buffer register
201      RegisterSetJson(key, valStr);
202  }
203  
204  static CAmount ExtractAndValidateValue(const std::string& strValue)
205  {
206      if (std::optional<CAmount> parsed = ParseMoney(strValue)) {
207          return parsed.value();
208      } else {
209          throw std::runtime_error("invalid TX output value");
210      }
211  }
212  
213  static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
214  {
215      const auto ver{ToIntegral<uint32_t>(cmdVal)};
216      if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) {
217          throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
218      }
219      tx.version = *ver;
220  }
221  
222  static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
223  {
224      const auto locktime{ToIntegral<uint32_t>(cmdVal)};
225      if (!locktime) {
226          throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
227      }
228      tx.nLockTime = *locktime;
229  }
230  
231  static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
232  {
233      const auto idx{ToIntegral<uint32_t>(strInIdx)};
234      if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) {
235          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
236      }
237  
238      // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
239      uint32_t cnt{0};
240      for (CTxIn& txin : tx.vin) {
241          if (strInIdx == "" || cnt == *idx) {
242              if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
243                  txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
244              }
245          }
246          ++cnt;
247      }
248  }
249  
250  template <typename T>
251  static T TrimAndParse(const std::string& int_str, const std::string& err)
252  {
253      const auto parsed{ToIntegral<T>(TrimStringView(int_str))};
254      if (!parsed.has_value()) {
255          throw std::runtime_error(err + " '" + int_str + "'");
256      }
257      return parsed.value();
258  }
259  
260  static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
261  {
262      std::vector<std::string> vStrInputParts = SplitString(strInput, ':');
263  
264      // separate TXID:VOUT in string
265      if (vStrInputParts.size()<2)
266          throw std::runtime_error("TX input missing separator");
267  
268      // extract and validate TXID
269      auto txid{Txid::FromHex(vStrInputParts[0])};
270      if (!txid) {
271          throw std::runtime_error("invalid TX input txid");
272      }
273  
274      static const unsigned int minTxOutSz = 9;
275      static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
276  
277      // extract and validate vout
278      const std::string& strVout = vStrInputParts[1];
279      const auto vout{ToIntegral<uint32_t>(strVout)};
280      if (!vout || *vout > maxVout) {
281          throw std::runtime_error("invalid TX input vout '" + strVout + "'");
282      }
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      const auto idx{ToIntegral<uint32_t>(strInIdx)};
512      if (!idx || idx >= tx.vin.size()) {
513          throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
514      }
515      tx.vin.erase(tx.vin.begin() + *idx);
516  }
517  
518  static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
519  {
520      const auto idx{ToIntegral<uint32_t>(strOutIdx)};
521      if (!idx || idx >= tx.vout.size()) {
522          throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
523      }
524      tx.vout.erase(tx.vout.begin() + *idx);
525  }
526  
527  static const unsigned int N_SIGHASH_OPTS = 7;
528  static const struct {
529      const char *flagStr;
530      int flags;
531  } sighashOptions[N_SIGHASH_OPTS] = {
532      {"DEFAULT", SIGHASH_DEFAULT},
533      {"ALL", SIGHASH_ALL},
534      {"NONE", SIGHASH_NONE},
535      {"SINGLE", SIGHASH_SINGLE},
536      {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
537      {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
538      {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
539  };
540  
541  static bool findSighashFlags(int& flags, const std::string& flagStr)
542  {
543      flags = 0;
544  
545      for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
546          if (flagStr == sighashOptions[i].flagStr) {
547              flags = sighashOptions[i].flags;
548              return true;
549          }
550      }
551  
552      return false;
553  }
554  
555  static CAmount AmountFromValue(const UniValue& value)
556  {
557      if (!value.isNum() && !value.isStr())
558          throw std::runtime_error("Amount is not a number or string");
559      CAmount amount;
560      if (!ParseFixedPoint(value.getValStr(), 8, &amount))
561          throw std::runtime_error("Invalid amount");
562      if (!MoneyRange(amount))
563          throw std::runtime_error("Amount out of range");
564      return amount;
565  }
566  
567  static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
568  {
569      std::string strHex;
570      if (v.isStr())
571          strHex = v.getValStr();
572      if (!IsHex(strHex))
573          throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
574      return ParseHex(strHex);
575  }
576  
577  static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
578  {
579      int nHashType = SIGHASH_ALL;
580  
581      if (flagStr.size() > 0)
582          if (!findSighashFlags(nHashType, flagStr))
583              throw std::runtime_error("unknown sighash flag/sign option");
584  
585      // mergedTx will end up with all the signatures; it
586      // starts as a clone of the raw tx:
587      CMutableTransaction mergedTx{tx};
588      const CMutableTransaction txv{tx};
589      CCoinsViewCache view{&CoinsViewEmpty::Get()};
590  
591      if (!registers.contains("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.contains("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, {.sighash_type = 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  }