bitcoin-tx.cpp raw

   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      int64_t 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  }
 886