Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2009-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <bitcoin-build-config.h> // IWYU pragma: keep7#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 <crypto/sha256.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>33#include <cstdio>34#include <functional>35#include <memory>37using util::SplitString;38using util::ToString;39using util::TrimString;40using util::TrimStringView;42static bool fCreateBlank;43static std::map<std::string,UniValue> registers;44static const int CONTINUE_EXECUTION=-1;46const TranslateFn G_TRANSLATION_FUN{nullptr};48static void SetupBitcoinTxArgs(ArgsManager &argsman)49{50SetupHelpOptions(argsman);52argsman.AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);53argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);54argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);55argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);56SetupChainParamsBaseOptions(argsman);58argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);59argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);60argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);61argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);62argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);63argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);64argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);65argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "66"Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "67"Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);68argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. "69"Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. "70"Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);71argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "72"Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "73"Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);74argsman.AddArg("replaceable(=N)", "Sets Replace-By-Fee (RBF) opt-in sequence number for input N. "75"If N is not provided, the command attempts to opt-in all available inputs for RBF. "76"If the transaction has no inputs, this option is ignored.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);77argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "78"This command requires JSON registers:"79"prevtxs=JSON object, "80"privatekeys=JSON object. "81"See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);83argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);84argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);85}87//88// This function returns either one of EXIT_ codes when it's expected to stop the process or89// CONTINUE_EXECUTION when it's expected to continue further.90//91static int AppInitRawTx(int argc, char* argv[])92{93SetupBitcoinTxArgs(gArgs);94std::string error;95if (!gArgs.ParseParameters(argc, argv, error)) {96tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);97return EXIT_FAILURE;98}100// Check for chain settings (Params() calls are only valid after this clause)101try {102SelectParams(gArgs.GetChainType());103} catch (const std::exception& e) {104tfm::format(std::cerr, "Error: %s\n", e.what());105return EXIT_FAILURE;106}108fCreateBlank = gArgs.GetBoolArg("-create", false);110if (argc < 2 || HelpRequested(gArgs) || gArgs.GetBoolArg("-version", false)) {111// First part of help message is specific to this utility112std::string strUsage = CLIENT_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";114if (gArgs.GetBoolArg("-version", false)) {115strUsage += FormatParagraph(LicenseInfo());116} else {117strUsage += "\n"118"The bitcoin-tx tool is used for creating and modifying bitcoin transactions.\n\n"119"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"120"\n"121"Usage: bitcoin-tx [options] <hex-tx> [commands]\n"122"or: bitcoin-tx [options] -create [commands]\n"123"\n";124strUsage += gArgs.GetHelpMessage();125}127tfm::format(std::cout, "%s", strUsage);129if (argc < 2) {130tfm::format(std::cerr, "Error: too few parameters\n");131return EXIT_FAILURE;132}133return EXIT_SUCCESS;134}135return CONTINUE_EXECUTION;136}138static void RegisterSetJson(const std::string& key, const std::string& rawJson)139{140UniValue val;141if (!val.read(rawJson)) {142std::string strErr = "Cannot parse JSON for key " + key;143throw std::runtime_error(strErr);144}146registers[key] = val;147}149static void RegisterSet(const std::string& strInput)150{151// separate NAME:VALUE in string152size_t pos = strInput.find(':');153if ((pos == std::string::npos) ||154(pos == 0) ||155(pos == (strInput.size() - 1)))156throw std::runtime_error("Register input requires NAME:VALUE");158std::string key = strInput.substr(0, pos);159std::string valStr = strInput.substr(pos + 1, std::string::npos);161RegisterSetJson(key, valStr);162}164static void RegisterLoad(const std::string& strInput)165{166// separate NAME:FILENAME in string167size_t pos = strInput.find(':');168if ((pos == std::string::npos) ||169(pos == 0) ||170(pos == (strInput.size() - 1)))171throw std::runtime_error("Register load requires NAME:FILENAME");173std::string key = strInput.substr(0, pos);174std::string filename = strInput.substr(pos + 1, std::string::npos);176FILE *f = fsbridge::fopen(filename.c_str(), "r");177if (!f) {178std::string strErr = "Cannot open file " + filename;179throw std::runtime_error(strErr);180}182// load file chunks into one big buffer183std::string valStr;184while ((!feof(f)) && (!ferror(f))) {185char buf[4096];186int bread = fread(buf, 1, sizeof(buf), f);187if (bread <= 0)188break;190valStr.insert(valStr.size(), buf, bread);191}193int error = ferror(f);194fclose(f);196if (error) {197std::string strErr = "Error reading file " + filename;198throw std::runtime_error(strErr);199}201// evaluate as JSON buffer register202RegisterSetJson(key, valStr);203}205static CAmount ExtractAndValidateValue(const std::string& strValue)206{207if (std::optional<CAmount> parsed = ParseMoney(strValue)) {208return parsed.value();209} else {210throw std::runtime_error("invalid TX output value");211}212}214static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)215{216const auto ver{ToIntegral<uint32_t>(cmdVal)};217if (!ver || *ver < 1 || *ver > TX_MAX_STANDARD_VERSION) {218throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");219}220tx.version = *ver;221}223static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)224{225const auto locktime{ToIntegral<uint32_t>(cmdVal)};226if (!locktime) {227throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");228}229tx.nLockTime = *locktime;230}232static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)233{234const auto idx{ToIntegral<uint32_t>(strInIdx)};235if (strInIdx != "" && (!idx || *idx >= tx.vin.size())) {236throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");237}239// set the nSequence to MAX_INT - 2 (= RBF opt in flag)240uint32_t cnt{0};241for (CTxIn& txin : tx.vin) {242if (strInIdx == "" || cnt == *idx) {243if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {244txin.nSequence = MAX_BIP125_RBF_SEQUENCE;245}246}247++cnt;248}249}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.