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 }