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