bitcoin-tx.cpp
1 // Copyright (c) 2009-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <bitcoin-build-config.h> // IWYU pragma: keep 6 7 #include <chainparamsbase.h> 8 #include <clientversion.h> 9 #include <coins.h> 10 #include <common/args.h> 11 #include <common/license_info.h> 12 #include <common/system.h> 13 #include <compat/compat.h> 14 #include <consensus/amount.h> 15 #include <consensus/consensus.h> 16 #include <core_io.h> 17 #include <key_io.h> 18 #include <policy/policy.h> 19 #include <primitives/transaction.h> 20 #include <script/script.h> 21 #include <script/sign.h> 22 #include <script/signingprovider.h> 23 #include <univalue.h> 24 #include <util/exception.h> 25 #include <util/fs.h> 26 #include <util/moneystr.h> 27 #include <util/rbf.h> 28 #include <util/strencodings.h> 29 #include <util/string.h> 30 #include <util/translation.h> 31 32 #include <cstdio> 33 #include <functional> 34 #include <memory> 35 36 using util::SplitString; 37 using util::ToString; 38 using util::TrimString; 39 using util::TrimStringView; 40 41 static bool fCreateBlank; 42 static std::map<std::string,UniValue> registers; 43 static const int CONTINUE_EXECUTION=-1; 44 45 const TranslateFn G_TRANSLATION_FUN{nullptr}; 46 47 static void SetupBitcoinTxArgs(ArgsManager &argsman) 48 { 49 SetupHelpOptions(argsman); 50 51 argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 52 argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 53 argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 54 argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); 55 SetupChainParamsBaseOptions(argsman); 56 57 argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 58 argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 59 argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 60 argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 61 argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 62 argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 63 argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 64 argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. " 65 "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " 66 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 67 argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. " 68 "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. " 69 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 70 argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. " 71 "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. " 72 "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 73 argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. " 74 "If N is not provided, the command attempts to opt-in all available inputs for RBF. " 75 "If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 76 argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. " 77 "This command requires JSON registers:" 78 "prevtxs=JSON object, " 79 "privatekeys=JSON object. " 80 "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS); 81 82 argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); 83 argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS); 84 } 85 86 // 87 // This function returns either one of EXIT_ codes when it's expected to stop the process or 88 // CONTINUE_EXECUTION when it's expected to continue further. 89 // 90 static int AppInitRawTx(int argc, char* argv[]) 91 { 92 SetupBitcoinTxArgs(gArgs); 93 std::string error; 94 if (!gArgs.ParseParameters(argc, argv, error)) { 95 tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); 96 return EXIT_FAILURE; 97 } 98 99 // Check for chain settings (Params() calls are only valid after this clause) 100 try { 101 SelectParams(gArgs.GetChainType()); 102 } catch (const std::exception& e) { 103 tfm::format(std::cerr, "Error: %s\n", e.what()); 104 return EXIT_FAILURE; 105 } 106 107 fCreateBlank = gArgs.GetBoolArg("-create", false); 108 109 if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) { 110 // First part of help message is specific to this utility 111 std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n"; 112 113 if (gArgs.GetBoolArg("-version", false)) { 114 strUsage += FormatParagraph(LicenseInfo()); 115 } else { 116 strUsage += "\n" 117 "The bitcoin-tx tool is used for creating and modifying bitcoin transactions.\n\n" 118 "bitcoin-tx can be used with \"<hex-tx> [commands]\" to update a hex-encoded bitcoin transaction, or with \"-create [commands]\" to create a hex-encoded bitcoin transaction.\n" 119 "\n" 120 "Usage: bitcoin-tx [options] <hex-tx> [commands]\n" 121 "or: bitcoin-tx [options] -create [commands]\n" 122 "\n"; 123 strUsage += gArgs.GetHelpMessage(); 124 } 125 126 tfm::format(std::cout, "%s", strUsage); 127 128 if (argc < 2) { 129 tfm::format(std::cerr, "Error: too few parameters\n"); 130 return EXIT_FAILURE; 131 } 132 return EXIT_SUCCESS; 133 } 134 return CONTINUE_EXECUTION; 135 } 136 137 static void RegisterSetJson(const std::string& key, const std::string& rawJson) 138 { 139 UniValue val; 140 if (!val.read(rawJson)) { 141 std::string strErr = "Cannot parse JSON for key " + key; 142 throw std::runtime_error(strErr); 143 } 144 145 registers[key] = val; 146 } 147 148 static void RegisterSet(const std::string& strInput) 149 { 150 // separate NAME:VALUE in string 151 size_t pos = strInput.find(':'); 152 if ((pos == std::string::npos) || 153 (pos == 0) || 154 (pos == (strInput.size() - 1))) 155 throw std::runtime_error("Register input requires NAME:VALUE"); 156 157 std::string key = strInput.substr(0, pos); 158 std::string valStr = strInput.substr(pos + 1, std::string::npos); 159 160 RegisterSetJson(key, valStr); 161 } 162 163 static void RegisterLoad(const std::string& strInput) 164 { 165 // separate NAME:FILENAME in string 166 size_t pos = strInput.find(':'); 167 if ((pos == std::string::npos) || 168 (pos == 0) || 169 (pos == (strInput.size() - 1))) 170 throw std::runtime_error("Register load requires NAME:FILENAME"); 171 172 std::string key = strInput.substr(0, pos); 173 std::string filename = strInput.substr(pos + 1, std::string::npos); 174 175 FILE *f = fsbridge::fopen(filename.c_str(), "r"); 176 if (!f) { 177 std::string strErr = "Cannot open file " + filename; 178 throw std::runtime_error(strErr); 179 } 180 181 // load file chunks into one big buffer 182 std::string valStr; 183 while ((!feof(f)) && (!ferror(f))) { 184 char buf[4096]; 185 int bread = fread(buf, 1, sizeof(buf), f); 186 if (bread <= 0) 187 break; 188 189 valStr.insert(valStr.size(), buf, bread); 190 } 191 192 int error = ferror(f); 193 fclose(f); 194 195 if (error) { 196 std::string strErr = "Error reading file " + filename; 197 throw std::runtime_error(strErr); 198 } 199 200 // evaluate as JSON buffer register 201 RegisterSetJson(key, valStr); 202 } 203 204 static CAmount ExtractAndValidateValue(const std::string& strValue) 205 { 206 if (std::optional<CAmount> parsed = ParseMoney(strValue)) { 207 return parsed.value(); 208 } else { 209 throw std::runtime_error("invalid TX output value"); 210 } 211 } 212 213 static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal) 214 { 215 const auto ver{ToIntegral<uint32_t>(cmdVal)}; 216 if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) { 217 throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'"); 218 } 219 tx.version = *ver; 220 } 221 222 static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal) 223 { 224 const auto locktime{ToIntegral<uint32_t>(cmdVal)}; 225 if (!locktime) { 226 throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'"); 227 } 228 tx.nLockTime = *locktime; 229 } 230 231 static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx) 232 { 233 const auto idx{ToIntegral<uint32_t>(strInIdx)}; 234 if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) { 235 throw std::runtime_error("Invalid TX input index '" + strInIdx + "'"); 236 } 237 238 // set the nSequence to MAX_INT - 2 (= RBF opt in flag) 239 uint32_t cnt{0}; 240 for (CTxIn& txin : tx.vin) { 241 if (strInIdx == "" || cnt == *idx) { 242 if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) { 243 txin.nSequence = MAX_BIP125_RBF_SEQUENCE; 244 } 245 } 246 ++cnt; 247 } 248 } 249 250 template <typename T> 251 static T TrimAndParse(const std::string& int_str, const std::string& err) 252 { 253 const auto parsed{ToIntegral<T>(TrimStringView(int_str))}; 254 if (!parsed.has_value()) { 255 throw std::runtime_error(err + " '" + int_str + "'"); 256 } 257 return parsed.value(); 258 } 259 260 static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput) 261 { 262 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 263 264 // separate TXID:VOUT in string 265 if (vStrInputParts.size()<2) 266 throw std::runtime_error("TX input missing separator"); 267 268 // extract and validate TXID 269 auto txid{Txid::FromHex(vStrInputParts[0])}; 270 if (!txid) { 271 throw std::runtime_error("invalid TX input txid"); 272 } 273 274 static const unsigned int minTxOutSz = 9; 275 static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz); 276 277 // extract and validate vout 278 const std::string& strVout = vStrInputParts[1]; 279 const auto vout{ToIntegral<uint32_t>(strVout)}; 280 if (!vout || *vout > maxVout) { 281 throw std::runtime_error("invalid TX input vout '" + strVout + "'"); 282 } 283 284 // extract the optional sequence number 285 uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL; 286 if (vStrInputParts.size() > 2) { 287 nSequenceIn = TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid TX sequence id"); 288 } 289 290 // append to transaction input list 291 CTxIn txin{*txid, *vout, CScript{}, nSequenceIn}; 292 tx.vin.push_back(txin); 293 } 294 295 static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput) 296 { 297 // Separate into VALUE:ADDRESS 298 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 299 300 if (vStrInputParts.size() != 2) 301 throw std::runtime_error("TX output missing or too many separators"); 302 303 // Extract and validate VALUE 304 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 305 306 // extract and validate ADDRESS 307 const std::string& strAddr = vStrInputParts[1]; 308 CTxDestination destination = DecodeDestination(strAddr); 309 if (!IsValidDestination(destination)) { 310 throw std::runtime_error("invalid TX output address"); 311 } 312 CScript scriptPubKey = GetScriptForDestination(destination); 313 314 // construct TxOut, append to transaction output list 315 CTxOut txout(value, scriptPubKey); 316 tx.vout.push_back(txout); 317 } 318 319 static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput) 320 { 321 // Separate into VALUE:PUBKEY[:FLAGS] 322 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 323 324 if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3) 325 throw std::runtime_error("TX output missing or too many separators"); 326 327 // Extract and validate VALUE 328 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 329 330 // Extract and validate PUBKEY 331 CPubKey pubkey(ParseHex(vStrInputParts[1])); 332 if (!pubkey.IsFullyValid()) 333 throw std::runtime_error("invalid TX output pubkey"); 334 CScript scriptPubKey = GetScriptForRawPubKey(pubkey); 335 336 // Extract and validate FLAGS 337 bool bSegWit = false; 338 bool bScriptHash = false; 339 if (vStrInputParts.size() == 3) { 340 const std::string& flags = vStrInputParts[2]; 341 bSegWit = (flags.find('W') != std::string::npos); 342 bScriptHash = (flags.find('S') != std::string::npos); 343 } 344 345 if (bSegWit) { 346 if (!pubkey.IsCompressed()) { 347 throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); 348 } 349 // Build a P2WPKH script 350 scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey)); 351 } 352 if (bScriptHash) { 353 // Get the ID for the script, and then construct a P2SH destination for it. 354 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 355 } 356 357 // construct TxOut, append to transaction output list 358 CTxOut txout(value, scriptPubKey); 359 tx.vout.push_back(txout); 360 } 361 362 static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput) 363 { 364 // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS] 365 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 366 367 // Check that there are enough parameters 368 if (vStrInputParts.size()<3) 369 throw std::runtime_error("Not enough multisig parameters"); 370 371 // Extract and validate VALUE 372 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 373 374 // Extract REQUIRED 375 const uint32_t required{TrimAndParse<uint32_t>(vStrInputParts.at(1), "invalid multisig required number")}; 376 377 // Extract NUMKEYS 378 const uint32_t numkeys{TrimAndParse<uint32_t>(vStrInputParts.at(2), "invalid multisig total number")}; 379 380 // Validate there are the correct number of pubkeys 381 if (vStrInputParts.size() < numkeys + 3) 382 throw std::runtime_error("incorrect number of multisig pubkeys"); 383 384 if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required) 385 throw std::runtime_error("multisig parameter mismatch. Required " \ 386 + ToString(required) + " of " + ToString(numkeys) + "signatures."); 387 388 // extract and validate PUBKEYs 389 std::vector<CPubKey> pubkeys; 390 for(int pos = 1; pos <= int(numkeys); pos++) { 391 CPubKey pubkey(ParseHex(vStrInputParts[pos + 2])); 392 if (!pubkey.IsFullyValid()) 393 throw std::runtime_error("invalid TX output pubkey"); 394 pubkeys.push_back(pubkey); 395 } 396 397 // Extract FLAGS 398 bool bSegWit = false; 399 bool bScriptHash = false; 400 if (vStrInputParts.size() == numkeys + 4) { 401 const std::string& flags = vStrInputParts.back(); 402 bSegWit = (flags.find('W') != std::string::npos); 403 bScriptHash = (flags.find('S') != std::string::npos); 404 } 405 else if (vStrInputParts.size() > numkeys + 4) { 406 // Validate that there were no more parameters passed 407 throw std::runtime_error("Too many parameters"); 408 } 409 410 CScript scriptPubKey = GetScriptForMultisig(required, pubkeys); 411 412 if (bSegWit) { 413 for (const CPubKey& pubkey : pubkeys) { 414 if (!pubkey.IsCompressed()) { 415 throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs"); 416 } 417 } 418 // Build a P2WSH with the multisig script 419 scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey)); 420 } 421 if (bScriptHash) { 422 if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { 423 throw std::runtime_error(strprintf( 424 "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); 425 } 426 // Get the ID for the script, and then construct a P2SH destination for it. 427 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 428 } 429 430 // construct TxOut, append to transaction output list 431 CTxOut txout(value, scriptPubKey); 432 tx.vout.push_back(txout); 433 } 434 435 static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput) 436 { 437 CAmount value = 0; 438 439 // separate [VALUE:]DATA in string 440 size_t pos = strInput.find(':'); 441 442 if (pos==0) 443 throw std::runtime_error("TX output value not specified"); 444 445 if (pos == std::string::npos) { 446 pos = 0; 447 } else { 448 // Extract and validate VALUE 449 value = ExtractAndValidateValue(strInput.substr(0, pos)); 450 ++pos; 451 } 452 453 // extract and validate DATA 454 const std::string strData{strInput.substr(pos, std::string::npos)}; 455 456 if (!IsHex(strData)) 457 throw std::runtime_error("invalid TX output data"); 458 459 std::vector<unsigned char> data = ParseHex(strData); 460 461 CTxOut txout(value, CScript() << OP_RETURN << data); 462 tx.vout.push_back(txout); 463 } 464 465 static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput) 466 { 467 // separate VALUE:SCRIPT[:FLAGS] 468 std::vector<std::string> vStrInputParts = SplitString(strInput, ':'); 469 if (vStrInputParts.size() < 2) 470 throw std::runtime_error("TX output missing separator"); 471 472 // Extract and validate VALUE 473 CAmount value = ExtractAndValidateValue(vStrInputParts[0]); 474 475 // extract and validate script 476 const std::string& strScript = vStrInputParts[1]; 477 CScript scriptPubKey = ParseScript(strScript); 478 479 // Extract FLAGS 480 bool bSegWit = false; 481 bool bScriptHash = false; 482 if (vStrInputParts.size() == 3) { 483 const std::string& flags = vStrInputParts.back(); 484 bSegWit = (flags.find('W') != std::string::npos); 485 bScriptHash = (flags.find('S') != std::string::npos); 486 } 487 488 if (scriptPubKey.size() > MAX_SCRIPT_SIZE) { 489 throw std::runtime_error(strprintf( 490 "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE)); 491 } 492 493 if (bSegWit) { 494 scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey)); 495 } 496 if (bScriptHash) { 497 if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) { 498 throw std::runtime_error(strprintf( 499 "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE)); 500 } 501 scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey)); 502 } 503 504 // construct TxOut, append to transaction output list 505 CTxOut txout(value, scriptPubKey); 506 tx.vout.push_back(txout); 507 } 508 509 static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx) 510 { 511 const auto idx{ToIntegral<uint32_t>(strInIdx)}; 512 if (!idx || idx >= tx.vin.size()) { 513 throw std::runtime_error("Invalid TX input index '" + strInIdx + "'"); 514 } 515 tx.vin.erase(tx.vin.begin() + *idx); 516 } 517 518 static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx) 519 { 520 const auto idx{ToIntegral<uint32_t>(strOutIdx)}; 521 if (!idx || idx >= tx.vout.size()) { 522 throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'"); 523 } 524 tx.vout.erase(tx.vout.begin() + *idx); 525 } 526 527 static const unsigned int N_SIGHASH_OPTS = 7; 528 static const struct { 529 const char *flagStr; 530 int flags; 531 } sighashOptions[N_SIGHASH_OPTS] = { 532 {"DEFAULT", SIGHASH_DEFAULT}, 533 {"ALL", SIGHASH_ALL}, 534 {"NONE", SIGHASH_NONE}, 535 {"SINGLE", SIGHASH_SINGLE}, 536 {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY}, 537 {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY}, 538 {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY}, 539 }; 540 541 static bool findSighashFlags(int& flags, const std::string& flagStr) 542 { 543 flags = 0; 544 545 for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) { 546 if (flagStr == sighashOptions[i].flagStr) { 547 flags = sighashOptions[i].flags; 548 return true; 549 } 550 } 551 552 return false; 553 } 554 555 static CAmount AmountFromValue(const UniValue& value) 556 { 557 if (!value.isNum() && !value.isStr()) 558 throw std::runtime_error("Amount is not a number or string"); 559 CAmount amount; 560 if (!ParseFixedPoint(value.getValStr(), 8, &amount)) 561 throw std::runtime_error("Invalid amount"); 562 if (!MoneyRange(amount)) 563 throw std::runtime_error("Amount out of range"); 564 return amount; 565 } 566 567 static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName) 568 { 569 std::string strHex; 570 if (v.isStr()) 571 strHex = v.getValStr(); 572 if (!IsHex(strHex)) 573 throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')"); 574 return ParseHex(strHex); 575 } 576 577 static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr) 578 { 579 int nHashType = SIGHASH_ALL; 580 581 if (flagStr.size() > 0) 582 if (!findSighashFlags(nHashType, flagStr)) 583 throw std::runtime_error("unknown sighash flag/sign option"); 584 585 // mergedTx will end up with all the signatures; it 586 // starts as a clone of the raw tx: 587 CMutableTransaction mergedTx{tx}; 588 const CMutableTransaction txv{tx}; 589 CCoinsViewCache view{&CoinsViewEmpty::Get()}; 590 591 if (!registers.contains("privatekeys")) 592 throw std::runtime_error("privatekeys register variable must be set."); 593 FillableSigningProvider tempKeystore; 594 UniValue keysObj = registers["privatekeys"]; 595 596 for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) { 597 if (!keysObj[kidx].isStr()) 598 throw std::runtime_error("privatekey not a std::string"); 599 CKey key = DecodeSecret(keysObj[kidx].getValStr()); 600 if (!key.IsValid()) { 601 throw std::runtime_error("privatekey not valid"); 602 } 603 tempKeystore.AddKey(key); 604 } 605 606 // Add previous txouts given in the RPC call: 607 if (!registers.contains("prevtxs")) 608 throw std::runtime_error("prevtxs register variable must be set."); 609 UniValue prevtxsObj = registers["prevtxs"]; 610 { 611 for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) { 612 const UniValue& prevOut = prevtxsObj[previdx]; 613 if (!prevOut.isObject()) 614 throw std::runtime_error("expected prevtxs internal object"); 615 616 std::map<std::string, UniValue::VType> types = { 617 {"txid", UniValue::VSTR}, 618 {"vout", UniValue::VNUM}, 619 {"scriptPubKey", UniValue::VSTR}, 620 }; 621 if (!prevOut.checkObject(types)) 622 throw std::runtime_error("prevtxs internal object typecheck fail"); 623 624 auto txid{Txid::FromHex(prevOut["txid"].get_str())}; 625 if (!txid) { 626 throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')"); 627 } 628 629 const int nOut = prevOut["vout"].getInt<int>(); 630 if (nOut < 0) 631 throw std::runtime_error("vout cannot be negative"); 632 633 COutPoint out(*txid, nOut); 634 std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); 635 CScript scriptPubKey(pkData.begin(), pkData.end()); 636 637 { 638 const Coin& coin = view.AccessCoin(out); 639 if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) { 640 std::string err("Previous output scriptPubKey mismatch:\n"); 641 err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+ 642 ScriptToAsmStr(scriptPubKey); 643 throw std::runtime_error(err); 644 } 645 Coin newcoin; 646 newcoin.out.scriptPubKey = scriptPubKey; 647 newcoin.out.nValue = MAX_MONEY; 648 if (prevOut.exists("amount")) { 649 newcoin.out.nValue = AmountFromValue(prevOut["amount"]); 650 } 651 newcoin.nHeight = 1; 652 view.AddCoin(out, std::move(newcoin), true); 653 } 654 655 // if redeemScript given and private keys given, 656 // add redeemScript to the tempKeystore so it can be signed: 657 if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) && 658 prevOut.exists("redeemScript")) { 659 UniValue v = prevOut["redeemScript"]; 660 std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript")); 661 CScript redeemScript(rsData.begin(), rsData.end()); 662 tempKeystore.AddCScript(redeemScript); 663 } 664 } 665 } 666 667 const FillableSigningProvider& keystore = tempKeystore; 668 669 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); 670 671 // Sign what we can: 672 for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { 673 CTxIn& txin = mergedTx.vin[i]; 674 const Coin& coin = view.AccessCoin(txin.prevout); 675 if (coin.IsSpent()) { 676 continue; 677 } 678 const CScript& prevPubKey = coin.out.scriptPubKey; 679 const CAmount& amount = coin.out.nValue; 680 681 SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out); 682 // Only sign SIGHASH_SINGLE if there's a corresponding output: 683 if (!fHashSingle || (i < mergedTx.vout.size())) 684 ProduceSignature(keystore, MutableTransactionSignatureCreator(mergedTx, i, amount, {.sighash_type = nHashType}), prevPubKey, sigdata); 685 686 if (amount == MAX_MONEY && !sigdata.scriptWitness.IsNull()) { 687 throw std::runtime_error(strprintf("Missing amount for CTxOut with scriptPubKey=%s", HexStr(prevPubKey))); 688 } 689 690 UpdateInput(txin, sigdata); 691 } 692 693 tx = mergedTx; 694 } 695 696 static void MutateTx(CMutableTransaction& tx, const std::string& command, 697 const std::string& commandVal) 698 { 699 std::unique_ptr<ECC_Context> ecc; 700 701 if (command == "nversion") 702 MutateTxVersion(tx, commandVal); 703 else if (command == "locktime") 704 MutateTxLocktime(tx, commandVal); 705 else if (command == "replaceable") { 706 MutateTxRBFOptIn(tx, commandVal); 707 } 708 709 else if (command == "delin") 710 MutateTxDelInput(tx, commandVal); 711 else if (command == "in") 712 MutateTxAddInput(tx, commandVal); 713 714 else if (command == "delout") 715 MutateTxDelOutput(tx, commandVal); 716 else if (command == "outaddr") 717 MutateTxAddOutAddr(tx, commandVal); 718 else if (command == "outpubkey") { 719 ecc.reset(new ECC_Context()); 720 MutateTxAddOutPubKey(tx, commandVal); 721 } else if (command == "outmultisig") { 722 ecc.reset(new ECC_Context()); 723 MutateTxAddOutMultiSig(tx, commandVal); 724 } else if (command == "outscript") 725 MutateTxAddOutScript(tx, commandVal); 726 else if (command == "outdata") 727 MutateTxAddOutData(tx, commandVal); 728 729 else if (command == "sign") { 730 ecc.reset(new ECC_Context()); 731 MutateTxSign(tx, commandVal); 732 } 733 734 else if (command == "load") 735 RegisterLoad(commandVal); 736 737 else if (command == "set") 738 RegisterSet(commandVal); 739 740 else 741 throw std::runtime_error("unknown command"); 742 } 743 744 static void OutputTxJSON(const CTransaction& tx) 745 { 746 UniValue entry(UniValue::VOBJ); 747 TxToUniv(tx, /*block_hash=*/uint256(), entry); 748 749 std::string jsonOutput = entry.write(4); 750 tfm::format(std::cout, "%s\n", jsonOutput); 751 } 752 753 static void OutputTxHash(const CTransaction& tx) 754 { 755 std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id) 756 757 tfm::format(std::cout, "%s\n", strHexHash); 758 } 759 760 static void OutputTxHex(const CTransaction& tx) 761 { 762 std::string strHex = EncodeHexTx(tx); 763 764 tfm::format(std::cout, "%s\n", strHex); 765 } 766 767 static void OutputTx(const CTransaction& tx) 768 { 769 if (gArgs.GetBoolArg("-json", false)) 770 OutputTxJSON(tx); 771 else if (gArgs.GetBoolArg("-txid", false)) 772 OutputTxHash(tx); 773 else 774 OutputTxHex(tx); 775 } 776 777 static std::string readStdin() 778 { 779 char buf[4096]; 780 std::string ret; 781 782 while (!feof(stdin)) { 783 size_t bread = fread(buf, 1, sizeof(buf), stdin); 784 ret.append(buf, bread); 785 if (bread < sizeof(buf)) 786 break; 787 } 788 789 if (ferror(stdin)) 790 throw std::runtime_error("error reading stdin"); 791 792 return TrimString(ret); 793 } 794 795 static int CommandLineRawTx(int argc, char* argv[]) 796 { 797 std::string strPrint; 798 int nRet = 0; 799 try { 800 // Skip switches; Permit common stdin convention "-" 801 while (argc > 1 && IsSwitchChar(argv[1][0]) && 802 (argv[1][1] != 0)) { 803 argc--; 804 argv++; 805 } 806 807 CMutableTransaction tx; 808 int startArg; 809 810 if (!fCreateBlank) { 811 // require at least one param 812 if (argc < 2) 813 throw std::runtime_error("too few parameters"); 814 815 // param: hex-encoded bitcoin transaction 816 std::string strHexTx(argv[1]); 817 if (strHexTx == "-") // "-" implies standard input 818 strHexTx = readStdin(); 819 820 if (!DecodeHexTx(tx, strHexTx, true)) 821 throw std::runtime_error("invalid transaction encoding"); 822 823 startArg = 2; 824 } else 825 startArg = 1; 826 827 for (int i = startArg; i < argc; i++) { 828 std::string arg = argv[i]; 829 std::string key, value; 830 size_t eqpos = arg.find('='); 831 if (eqpos == std::string::npos) 832 key = arg; 833 else { 834 key = arg.substr(0, eqpos); 835 value = arg.substr(eqpos + 1); 836 } 837 838 MutateTx(tx, key, value); 839 } 840 841 OutputTx(CTransaction(tx)); 842 } 843 catch (const std::exception& e) { 844 strPrint = std::string("error: ") + e.what(); 845 nRet = EXIT_FAILURE; 846 } 847 catch (...) { 848 PrintExceptionContinue(nullptr, "CommandLineRawTx()"); 849 throw; 850 } 851 852 if (strPrint != "") { 853 tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint); 854 } 855 return nRet; 856 } 857 858 MAIN_FUNCTION 859 { 860 SetupEnvironment(); 861 862 try { 863 int ret = AppInitRawTx(argc, argv); 864 if (ret != CONTINUE_EXECUTION) 865 return ret; 866 } 867 catch (const std::exception& e) { 868 PrintExceptionContinue(&e, "AppInitRawTx()"); 869 return EXIT_FAILURE; 870 } catch (...) { 871 PrintExceptionContinue(nullptr, "AppInitRawTx()"); 872 return EXIT_FAILURE; 873 } 874 875 int ret = EXIT_FAILURE; 876 try { 877 ret = CommandLineRawTx(argc, argv); 878 } 879 catch (const std::exception& e) { 880 PrintExceptionContinue(&e, "CommandLineRawTx()"); 881 } catch (...) { 882 PrintExceptionContinue(nullptr, "CommandLineRawTx()"); 883 } 884 return ret; 885 }