Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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.
501}502scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));503}505// construct TxOut, append to transaction output list506CTxOut txout(value, scriptPubKey);507tx.vout.push_back(txout);508}510static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)511{512const auto idx{ToIntegral<uint32_t>(strInIdx)};513if (!idx || idx >= tx.vin.size()) {514throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");515}516tx.vin.erase(tx.vin.begin() + *idx);517}519static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)520{521const auto idx{ToIntegral<uint32_t>(strOutIdx)};522if (!idx || idx >= tx.vout.size()) {523throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");524}525tx.vout.erase(tx.vout.begin() + *idx);526}528static const unsigned int N_SIGHASH_OPTS = 7;529static const struct {530const char *flagStr;531int flags;532} sighashOptions[N_SIGHASH_OPTS] = {533{"DEFAULT", SIGHASH_DEFAULT},534{"ALL", SIGHASH_ALL},535{"NONE", SIGHASH_NONE},536{"SINGLE", SIGHASH_SINGLE},537{"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},538{"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},539{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},540};542static bool findSighashFlags(int& flags, const std::string& flagStr)543{544flags = 0;546for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {547if (flagStr == sighashOptions[i].flagStr) {548flags = sighashOptions[i].flags;549return true;550}551}553return false;554}556static CAmount AmountFromValue(const UniValue& value)557{558if (!value.isNum() && !value.isStr())559throw std::runtime_error("Amount is not a number or string");560int64_t amount;561if (!ParseFixedPoint(value.getValStr(), 8, &amount))562throw std::runtime_error("Invalid amount");563if (!MoneyRange(amount))564throw std::runtime_error("Amount out of range");565return amount;566}568static std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)569{570std::string strHex;571if (v.isStr())572strHex = v.getValStr();573if (!IsHex(strHex))574throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");575return ParseHex(strHex);576}578static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)579{580int nHashType = SIGHASH_ALL;582if (flagStr.size() > 0)583if (!findSighashFlags(nHashType, flagStr))584throw std::runtime_error("unknown sighash flag/sign option");586// mergedTx will end up with all the signatures; it587// starts as a clone of the raw tx:588CMutableTransaction mergedTx{tx};589const CMutableTransaction txv{tx};590CCoinsViewCache view{&CoinsViewEmpty::Get()};592if (!registers.contains("privatekeys"))593throw std::runtime_error("privatekeys register variable must be set.");594FillableSigningProvider tempKeystore;595UniValue keysObj = registers["privatekeys"];597for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {598if (!keysObj[kidx].isStr())599throw std::runtime_error("privatekey not a std::string");600CKey key = DecodeSecret(keysObj[kidx].getValStr());601if (!key.IsValid()) {602throw std::runtime_error("privatekey not valid");603}604tempKeystore.AddKey(key);605}607// Add previous txouts given in the RPC call:608if (!registers.contains("prevtxs"))609throw std::runtime_error("prevtxs register variable must be set.");610UniValue prevtxsObj = registers["prevtxs"];611{612for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {613const UniValue& prevOut = prevtxsObj[previdx];614if (!prevOut.isObject())615throw std::runtime_error("expected prevtxs internal object");617std::map<std::string, UniValue::VType> types = {618{"txid", UniValue::VSTR},619{"vout", UniValue::VNUM},620{"scriptPubKey", UniValue::VSTR},621};622if (!prevOut.checkObject(types))623throw std::runtime_error("prevtxs internal object typecheck fail");625auto txid{Txid::FromHex(prevOut["txid"].get_str())};626if (!txid) {627throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')");628}630const int nOut = prevOut["vout"].getInt<int>();631if (nOut < 0)632throw std::runtime_error("vout cannot be negative");634COutPoint out(*txid, nOut);635std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));636CScript scriptPubKey(pkData.begin(), pkData.end());638{639const Coin& coin = view.AccessCoin(out);640if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {641std::string err("Previous output scriptPubKey mismatch:\n");642err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+643ScriptToAsmStr(scriptPubKey);644throw std::runtime_error(err);645}646Coin newcoin;647newcoin.out.scriptPubKey = scriptPubKey;648newcoin.out.nValue = MAX_MONEY;649if (prevOut.exists("amount")) {650newcoin.out.nValue = AmountFromValue(prevOut["amount"]);651}652newcoin.nHeight = 1;653view.AddCoin(out, std::move(newcoin), true);654}656// if redeemScript given and private keys given,657// add redeemScript to the tempKeystore so it can be signed:658if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&659prevOut.exists("redeemScript")) {660UniValue v = prevOut["redeemScript"];661std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));662CScript redeemScript(rsData.begin(), rsData.end());663tempKeystore.AddCScript(redeemScript);664}665}666}668const FillableSigningProvider& keystore = tempKeystore;670bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);672// Sign what we can:673for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {674CTxIn& txin = mergedTx.vin[i];675const Coin& coin = view.AccessCoin(txin.prevout);676if (coin.IsSpent()) {677continue;678}679const CScript& prevPubKey = coin.out.scriptPubKey;680const CAmount& amount = coin.out.nValue;682SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);683// Only sign SIGHASH_SINGLE if there's a corresponding output:684if (!fHashSingle || (i < mergedTx.vout.size()))685ProduceSignature(keystore, MutableTransactionSignatureCreator(mergedTx, i, amount, {.sighash_type = nHashType}), prevPubKey, sigdata);687if (amount == MAX_MONEY && !sigdata.scriptWitness.IsNull()) {688throw std::runtime_error(strprintf("Missing amount for CTxOut with scriptPubKey=%s", HexStr(prevPubKey)));689}691UpdateInput(txin, sigdata);692}694tx = mergedTx;695}697static void MutateTx(CMutableTransaction& tx, const std::string& command,698const std::string& commandVal)699{700std::unique_ptr<ECC_Context> ecc;702if (command == "nversion")703MutateTxVersion(tx, commandVal);704else if (command == "locktime")705MutateTxLocktime(tx, commandVal);706else if (command == "replaceable") {707MutateTxRBFOptIn(tx, commandVal);708}710else if (command == "delin")711MutateTxDelInput(tx, commandVal);712else if (command == "in")713MutateTxAddInput(tx, commandVal);715else if (command == "delout")716MutateTxDelOutput(tx, commandVal);717else if (command == "outaddr")718MutateTxAddOutAddr(tx, commandVal);719else if (command == "outpubkey") {720ecc.reset(new ECC_Context());721MutateTxAddOutPubKey(tx, commandVal);722} else if (command == "outmultisig") {723ecc.reset(new ECC_Context());724MutateTxAddOutMultiSig(tx, commandVal);725} else if (command == "outscript")726MutateTxAddOutScript(tx, commandVal);727else if (command == "outdata")728MutateTxAddOutData(tx, commandVal);730else if (command == "sign") {731ecc.reset(new ECC_Context());732MutateTxSign(tx, commandVal);733}735else if (command == "load")736RegisterLoad(commandVal);738else if (command == "set")739RegisterSet(commandVal);741else742throw std::runtime_error("unknown command");743}745static void OutputTxJSON(const CTransaction& tx)746{747UniValue entry(UniValue::VOBJ);748TxToUniv(tx, /*block_hash=*/uint256(), entry);750std::string jsonOutput = entry.write(4);
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.