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/system.h> 12 #include <compat/compat.h> 13 #include <consensus/amount.h> 14 #include <consensus/consensus.h> 15 #include <core_io.h> 16 #include <key_io.h> 17 #include <policy/policy.h> 18 #include <primitives/transaction.h> 19 #include <script/script.h> 20 #include <script/sign.h> 21 #include <script/signingprovider.h> 22 #include <univalue.h> 23 #include <util/exception.h> 24 #include <util/fs.h> 25 #include <util/moneystr.h> 26 #include <util/rbf.h> 27 #include <util/strencodings.h> 28 #include <util/string.h> 29 #include <util/translation.h> 30 31 #include <cstdio> 32 #include <functional> 33 #include <memory> 34 35 using util::SplitString; 36 using util::ToString; 37 using util::TrimString; 38 using util::TrimStringView; 39 40 static bool fCreateBlank; 41 static std::map<std::string,UniValue> registers; 42 static const int CONTINUE_EXECUTION=-1; 43 44 const TranslateFn G_TRANSLATION_FUN{nullptr}; 45 46 static void SetupBitcoinTxArgs(ArgsManager &argsman) 47 { 48 SetupHelpOptions(argsman); 49 50 argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 51 argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 52 argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 53 argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 54 SetupChainParamsBaseOptions(argsman); 55 56 argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 57 argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 58 argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 59 argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 60 argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 61 argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 62 argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 63 argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. " 64 "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " 65 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 66 argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. " 67 "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. " 68 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 69 argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. " 70 "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " 71 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 72 argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. " 73 "If N is not provided, the command attempts to opt-in all available inputs for RBF. " 74 "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 75 argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. " 76 "This command requires JSON registers:" 77 "prevtxs=JSON object, " 78 "privatekeys=JSON object. " 79 "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 80 81 argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); 82 argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); 83 } 84 85 // 86 // This function returns either one of EXIT_ codes when it's expected to stop the process or 87 // CONTINUE_EXECUTION when it's expected to continue further. 88 // 89 static int AppInitRawTx(int argc, char* argv[]) 90 { 91 SetupBitcoinTxArgs(gArgs); 92 std::string error; 93 if (!gArgs.ParseParameters(argc, argv, error)) { 94 tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); 95 return EXIT_FAILURE; 96 } 97 98 // Check for chain settings (Params() calls are only valid after this clause) 99 try { 100 SelectParams(gArgs.GetChainType()); 101 } catch (const std::exception& e) { 102 tfm::format(std::cerr, "Error: %s\n", e.what()); 103 return EXIT_FAILURE; 104 } 105 106 fCreateBlank = gArgs.GetBoolArg("-create", false); 107 108 if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) { 109 // First part of help message is specific to this utility 110 std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n"; 111 112 if (gArgs.GetBoolArg("-version", false)) { 113 strUsage += FormatParagraph(LicenseInfo()); 114 } else { 115 strUsage += "\n" 116 "The bitcoin-tx tool is used for creating and modifying bitcoin transactions.\n\n" 117 "bitcoin-tx can be used with \"<hex-tx> [commands]\" to update a hex-encoded bitcoin transaction, or with \"-create [commands]\" to create a hex-encoded bitcoin transaction.\n" 118 "\n" 119 "Usage: bitcoin-tx [options] <hex-tx> [commands]\n" 120 "or: bitcoin-tx [options] -create [commands]\n" 121 "\n"; 122 strUsage += gArgs.GetHelpMessage(); 123 } 124 125 tfm::format(std::cout, "%s", strUsage); 126 127 if (argc < 2) { 128 tfm::format(std::cerr, "Error: too few parameters\n"); 129 return EXIT_FAILURE; 130 } 131 return EXIT_SUCCESS; 132 } 133 return CONTINUE_EXECUTION; 134 } 135 136 static void RegisterSetJson(const std::string& key, const std::string& rawJson) 137 { 138 UniValue val; 139 if (!val.read(rawJson)) { 140 std::string strErr = "Cannot parse JSON for key " + key; 141 throw std::runtime_error(strErr); 142 } 143 144 registers[key] = val; 145 } 146 147 static void RegisterSet(const std::string& strInput) 148 { 149 // separate NAME:VALUE in string 150 size_t pos = strInput.find(':'); 151 if ((pos == std::string::npos) || 152 (pos == 0) || 153 (pos == (strInput.size() - 1))) 154 throw std::runtime_error("Register input requires NAME:VALUE"); 155 156 std::string key = strInput.substr(0, pos); 157 std::string valStr = strInput.substr(pos + 1, std::string::npos); 158 159 RegisterSetJson(key, valStr); 160 } 161 162 static void RegisterLoad(const std::string& strInput) 163 { 164 // separate NAME:FILENAME in string 165 size_t pos = strInput.find(':'); 166 if ((pos == std::string::npos) || 167 (pos == 0) || 168 (pos == (strInput.size() - 1))) 169 throw std::runtime_error("Register load requires NAME:FILENAME"); 170 171 std::string key = strInput.substr(0, pos); 172 std::string filename = strInput.substr(pos + 1, std::string::npos); 173 174 FILE *f = fsbridge::fopen(filename.c_str(), "r"); 175 if (!f) { 176 std::string strErr = "Cannot open file " + filename; 177 throw std::runtime_error(strErr); 178 } 179 180 // load file chunks into one big buffer 181 std::string valStr; 182 while ((!feof(f)) && (!ferror(f))) { 183 char buf[4096]; 184 int bread = fread(buf, 1, sizeof(buf), f); 185 if (bread <= 0) 186 break; 187 188 valStr.insert(valStr.size(), buf, bread); 189 } 190 191 int error = ferror(f); 192 fclose(f); 193 194 if (error) { 195 std::string strErr = "Error reading file " + filename; 196 throw std::runtime_error(strErr); 197 } 198 199 // evaluate as JSON buffer register 200 RegisterSetJson(key, valStr); 201 } 202 203 static CAmount ExtractAndValidateValue(const std::string& strValue) 204 { 205 if (std::optional<CAmount> parsed = ParseMoney(strValue)) { 206 return parsed.value(); 207 } else { 208 throw std::runtime_error("invalid TX output value"); 209 } 210 } 211 212 static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) 213 { 214 const auto ver{ToIntegral<uint32_t>(cmdVal)}; 215 if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) { 216 throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'"); 217 } 218 tx.version = *ver; 219 } 220 221 static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal) 222 { 223 const auto locktime{ToIntegral<uint32_t>(cmdVal)}; 224 if (!locktime) { 225 throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'"); 226 } 227 tx.nLockTime = *locktime; 228 } 229 230 static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx) 231 { 232 const auto idx{ToIntegral<uint32_t>(strInIdx)}; 233 if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) { 234 throw std::runtime_error("Invalid TX input index '" + strInIdx + "'"); 235 } 236 237 // set the nSequence to MAX_INT - 2 (= RBF opt in flag) 238 uint32_t cnt{0}; 239 for (CTxIn& txin : tx.vin) { 240 if (strInIdx == "" || cnt == *idx) { 241 if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) { 242 txin.nSequence = MAX_BIP125_RBF_SEQUENCE; 243 } 244 } 245 ++cnt; 246 } 247 } 248 249 template <typename T> 250 static T TrimAndParse(const std::string& int_str, const std::string& err) 251 { 252 const auto parsed{ToIntegral<T>(TrimStringView(int_str))}; 253 if (!parsed.has_value()) { 254 throw std::runtime_error(err + " '" + int_str + "'"); 255 } 256 return parsed.value(); 257 } 258 259 static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput) 260 { 261 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 262 263 // separate TXID:VOUT in string 264 if (vStrInputParts.size()<2) 265 throw std::runtime_error("TX input missing separator"); 266 267 // extract and validate TXID 268 auto txid{Txid::FromHex(vStrInputParts[0])}; 269 if (!txid) { 270 throw std::runtime_error("invalid TX input txid"); 271 } 272 273 static const unsigned int minTxOutSz = 9; 274 static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz); 275 276 // extract and validate vout 277 const std::string& strVout = vStrInputParts[1]; 278 const auto vout{ToIntegral<uint32_t>(strVout)}; 279 if (!vout || *vout > maxVout) { 280 throw std::runtime_error("invalid TX input vout '" + strVout + "'"); 281 } 282 283 // extract the optional sequence number 284 uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL; 285 if (vStrInputParts.size() > 2) { 286 nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id"); 287 } 288 289 // append to transaction input list 290 CTxIn txin{*txid, *vout, CScript{}, nSequenceIn}; 291 tx.vin.push_back(txin); 292 } 293 294 static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) 295 { 296 // Separate into VALUE:ADDRESS 297 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 298 299 if (vStrInputParts.size() != 2) 300 throw std::runtime_error("TX output missing or too many separators"); 301 302 // Extract and validate VALUE 303 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 304 305 // extract and validate ADDRESS 306 const std::string& strAddr = vStrInputParts[1]; 307 CTxDestination destination = DecodeDestination(strAddr); 308 if (!IsValidDestination(destination)) { 309 throw std::runtime_error("invalid TX output address"); 310 } 311 CScript scriptPubKey = GetScriptForDestination(destination); 312 313 // construct TxOut, append to transaction output list 314 CTxOut txout(value, scriptPubKey); 315 tx.vout.push_back(txout); 316 } 317 318 static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput) 319 { 320 // Separate into VALUE:PUBKEY[:FLAGS] 321 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 322 323 if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3) 324 throw std::runtime_error("TX output missing or too many separators"); 325 326 // Extract and validate VALUE 327 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 328 329 // Extract and validate PUBKEY 330 CPubKey pubkey(ParseHex(vStrInputParts[1])); 331 if (!pubkey.IsFullyValid()) 332 throw std::runtime_error("invalid TX output pubkey"); 333 CScript scriptPubKey = GetScriptForRawPubKey(pubkey); 334 335 // Extract and validate FLAGS 336 bool bSegWit = false; 337 bool bScriptHash = false; 338 if (vStrInputParts.size() == 3) { 339 const std::string& flags = vStrInputParts[2]; 340 bSegWit = (flags.find('W') != std::string::npos); 341 bScriptHash = (flags.find('S') != std::string::npos); 342 } 343 344 if (bSegWit) { 345 if (!pubkey.IsCompressed()) { 346 throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); 347 } 348 // Build a P2WPKH script 349 scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey)); 350 } 351 if (bScriptHash) { 352 // Get the ID for the script, and then construct a P2SH destination for it. 353 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 354 } 355 356 // construct TxOut, append to transaction output list 357 CTxOut txout(value, scriptPubKey); 358 tx.vout.push_back(txout); 359 } 360 361 static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput) 362 { 363 // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] 364 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 365 366 // Check that there are enough parameters 367 if (vStrInputParts.size()<3) 368 throw std::runtime_error("Not enough multisig parameters"); 369 370 // Extract and validate VALUE 371 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 372 373 // Extract REQUIRED 374 const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")}; 375 376 // Extract NUMKEYS 377 const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")}; 378 379 // Validate there are the correct number of pubkeys 380 if (vStrInputParts.size() < numkeys + 3) 381 throw std::runtime_error("incorrect number of multisig pubkeys"); 382 383 if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required) 384 throw std::runtime_error("multisig parameter mismatch. Required " \ 385 + ToString(required) + " of " + ToString(numkeys) + "signatures."); 386 387 // extract and validate PUBKEYs 388 std::vector<CPubKey> pubkeys; 389 for(int pos = 1; pos <= int(numkeys); pos++) { 390 CPubKey pubkey(ParseHex(vStrInputParts[pos + 2])); 391 if (!pubkey.IsFullyValid()) 392 throw std::runtime_error("invalid TX output pubkey"); 393 pubkeys.push_back(pubkey); 394 } 395 396 // Extract FLAGS 397 bool bSegWit = false; 398 bool bScriptHash = false; 399 if (vStrInputParts.size() == numkeys + 4) { 400 const std::string& flags = vStrInputParts.back(); 401 bSegWit = (flags.find('W') != std::string::npos); 402 bScriptHash = (flags.find('S') != std::string::npos); 403 } 404 else if (vStrInputParts.size() > numkeys + 4) { 405 // Validate that there were no more parameters passed 406 throw std::runtime_error("Too many parameters"); 407 } 408 409 CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); 410 411 if (bSegWit) { 412 for (const CPubKey& pubkey : pubkeys) { 413 if (!pubkey.IsCompressed()) { 414 throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); 415 } 416 } 417 // Build a P2WSH with the multisig script 418 scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey)); 419 } 420 if (bScriptHash) { 421 if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { 422 throw std::runtime_error(strprintf( 423 "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); 424 } 425 // Get the ID for the script, and then construct a P2SH destination for it. 426 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 427 } 428 429 // construct TxOut, append to transaction output list 430 CTxOut txout(value, scriptPubKey); 431 tx.vout.push_back(txout); 432 } 433 434 static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput) 435 { 436 CAmount value = 0; 437 438 // separate [VALUE:]DATA in string 439 size_t pos = strInput.find(':'); 440 441 if (pos==0) 442 throw std::runtime_error("TX output value not specified"); 443 444 if (pos == std::string::npos) { 445 pos = 0; 446 } else { 447 // Extract and validate VALUE 448 value = ExtractAndValidateValue(strInput.substr(0, pos)); 449 ++pos; 450 } 451 452 // extract and validate DATA 453 const std::string strData{strInput.substr(pos, std::string::npos)}; 454 455 if (!IsHex(strData)) 456 throw std::runtime_error("invalid TX output data"); 457 458 std::vector<unsigned char> data = ParseHex(strData); 459 460 CTxOut txout(value, CScript() << OP_RETURN << data); 461 tx.vout.push_back(txout); 462 } 463 464 static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) 465 { 466 // separate VALUE:SCRIPT[:FLAGS] 467 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 468 if (vStrInputParts.size() < 2) 469 throw std::runtime_error("TX output missing separator"); 470 471 // Extract and validate VALUE 472 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 473 474 // extract and validate script 475 const std::string& strScript = vStrInputParts[1]; 476 CScript scriptPubKey = ParseScript(strScript); 477 478 // Extract FLAGS 479 bool bSegWit = false; 480 bool bScriptHash = false; 481 if (vStrInputParts.size() == 3) { 482 const std::string& flags = vStrInputParts.back(); 483 bSegWit = (flags.find('W') != std::string::npos); 484 bScriptHash = (flags.find('S') != std::string::npos); 485 } 486 487 if (scriptPubKey.size() > MAX_SCRIPT_SIZE) { 488 throw std::runtime_error(strprintf( 489 "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE)); 490 } 491 492 if (bSegWit) { 493 scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey)); 494 } 495 if (bScriptHash) { 496 if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { 497 throw std::runtime_error(strprintf( 498 "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); 499 } 500 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 501 } 502 503 // construct TxOut, append to transaction output list 504 CTxOut txout(value, scriptPubKey); 505 tx.vout.push_back(txout); 506 } 507 508 static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx) 509 { 510 const auto idx{ToIntegral<uint32_t>(strInIdx)}; 511 if (!idx || idx >= tx.vin.size()) { 512 throw std::runtime_error("Invalid TX input index '" + strInIdx + "'"); 513 } 514 tx.vin.erase(tx.vin.begin() + *idx); 515 } 516 517 static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx) 518 { 519 const auto idx{ToIntegral<uint32_t>(strOutIdx)}; 520 if (!idx || idx >= tx.vout.size()) { 521 throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'"); 522 } 523 tx.vout.erase(tx.vout.begin() + *idx); 524 } 525 526 static const unsigned int N_SIGHASH_OPTS = 7; 527 static const struct { 528 const char *flagStr; 529 int flags; 530 } sighashOptions[N_SIGHASH_OPTS] = { 531 {"DEFAULT", SIGHASH_DEFAULT}, 532 {"ALL", SIGHASH_ALL}, 533 {"NONE", SIGHASH_NONE}, 534 {"SINGLE", SIGHASH_SINGLE}, 535 {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY}, 536 {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY}, 537 {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY}, 538 }; 539 540 static bool findSighashFlags(int& flags, const std::string& flagStr) 541 { 542 flags = 0; 543 544 for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) { 545 if (flagStr == sighashOptions[i].flagStr) { 546 flags = sighashOptions[i].flags; 547 return true; 548 } 549 } 550 551 return false; 552 } 553 554 static CAmount AmountFromValue(const UniValue& value) 555 { 556 if (!value.isNum() && !value.isStr()) 557 throw std::runtime_error("Amount is not a number or string"); 558 CAmount amount; 559 if (!ParseFixedPoint(value.getValStr(), 8, &amount)) 560 throw std::runtime_error("Invalid amount"); 561 if (!MoneyRange(amount)) 562 throw std::runtime_error("Amount out of range"); 563 return amount; 564 } 565 566 static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName) 567 { 568 std::string strHex; 569 if (v.isStr()) 570 strHex = v.getValStr(); 571 if (!IsHex(strHex)) 572 throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); 573 return ParseHex(strHex); 574 } 575 576 static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) 577 { 578 int nHashType = SIGHASH_ALL; 579 580 if (flagStr.size() > 0) 581 if (!findSighashFlags(nHashType, flagStr)) 582 throw std::runtime_error("unknown sighash flag/sign option"); 583 584 // mergedTx will end up with all the signatures; it 585 // starts as a clone of the raw tx: 586 CMutableTransaction mergedTx{tx}; 587 const CMutableTransaction txv{tx}; 588 CCoinsView viewDummy; 589 CCoinsViewCache view(&viewDummy); 590 591 if (!registers.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, 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 }