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.
1751rbf = request.params[3].get_bool();1752}1753CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf, self.Arg<uint32_t>("version"));1755// Make a blank psbt1756uint32_t psbt_version = 2;1757if (!request.params[5].isNull()) {1758psbt_version = request.params[5].getInt<uint32_t>();1759}1760if (psbt_version != 2 && psbt_version != 0) {1761throw JSONRPCError(RPC_INVALID_PARAMETER, "The PSBT version can only be 2 or 0");1762}1763PartiallySignedTransaction psbtx(rawTx, psbt_version);1765// Serialize the PSBT1766DataStream ssTx{};1767ssTx << psbtx;1769return EncodeBase64(ssTx);1770},1771};1772}1774static RPCMethod converttopsbt()1775{1776return RPCMethod{1777"converttopsbt",1778"Converts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"1779"createpsbt and walletcreatefundedpsbt should be used for new applications.\n",1780{1781{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},1782{"permitsigdata", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, any signatures in the input will be discarded and conversion\n"1783" will continue. If false, RPC will fail if any signatures are present."},1784{"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"1785"If iswitness is not present, heuristic tests will be used in decoding.\n"1786"If true, only witness deserialization will be tried.\n"1787"If false, only non-witness deserialization will be tried.\n"1788"This boolean should reflect whether the transaction has inputs\n"1789"(e.g. fully valid, or on-chain transactions), if known by the caller."1790},1791{"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use."},1792},1793RPCResult{1794RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"1795},1796RPCExamples{1797"\nCreate a transaction\n"1798+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") +1799"\nConvert the transaction to a PSBT\n"1800+ HelpExampleCli("converttopsbt", "\"rawtransaction\"")1801},1802[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1803{1804// parse hex string from parameter1805CMutableTransaction tx;1806bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();1807bool witness_specified = !request.params[2].isNull();1808bool iswitness = witness_specified ? request.params[2].get_bool() : false;1809const bool try_witness = witness_specified ? iswitness : true;1810const bool try_no_witness = witness_specified ? !iswitness : true;1811if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {1812throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");1813}1815// Remove all scriptSigs and scriptWitnesses from inputs1816for (CTxIn& input : tx.vin) {1817if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && !permitsigdata) {1818throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs and scriptWitnesses");1819}1820input.scriptSig.clear();1821input.scriptWitness.SetNull();1822}1824// Make a blank psbt1825uint32_t psbt_version = 2;1826if (!request.params[3].isNull()) {1827psbt_version = request.params[3].getInt<uint32_t>();1828}1829if (psbt_version != 2 && psbt_version != 0) {1830throw JSONRPCError(RPC_INVALID_PARAMETER, "The PSBT version can only be 2 or 0");1831}1832PartiallySignedTransaction psbtx(tx, psbt_version);1834// Serialize the PSBT1835DataStream ssTx{};1836ssTx << psbtx;1838return EncodeBase64(ssTx);1839},1840};1841}1843static RPCMethod utxoupdatepsbt()1844{1845return RPCMethod{1846"utxoupdatepsbt",1847"Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n",1848{1849{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},1850{"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of either strings or objects", {1851{"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},1852{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {1853{"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},1854{"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"},1855}},1856}},1857},1858RPCResult {1859RPCResult::Type::STR, "", "The base64-encoded partially signed transaction with inputs updated"1860},1861RPCExamples {1862HelpExampleCli("utxoupdatepsbt", "\"psbt\"")1863},1864[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1865{1866// Parse descriptors, if any.1867FlatSigningProvider provider;1868if (!request.params[1].isNull()) {1869auto descs = request.params[1].get_array();1870for (size_t i = 0; i < descs.size(); ++i) {1871EvalDescriptorStringOrObject(descs[i], provider);1872}1873}1875// We don't actually need private keys further on; hide them as a precaution.1876const PartiallySignedTransaction& psbtx = ProcessPSBT(1877request.params[0].get_str(),1878request.context,1879HidingSigningProvider(&provider, /*hide_secret=*/true, /*hide_origin=*/false),1880/*sighash_type=*/std::nullopt,1881/*finalize=*/false);1883DataStream ssTx{};1884ssTx << psbtx;1885return EncodeBase64(ssTx);1886},1887};1888}1890static RPCMethod joinpsbts()1891{1892return RPCMethod{1893"joinpsbts",1894"Joins multiple distinct version 0 PSBTs with different inputs and outputs into one version 0 PSBT with inputs and outputs from all of the PSBTs\n"1895"No input in any of the PSBTs can be in more than one of the PSBTs.\n",1896{1897{"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions",1898{1899{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}1900}}1901},1902RPCResult {1903RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"1904},1905RPCExamples {1906HelpExampleCli("joinpsbts", "\"psbt\"")1907},1908[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1909{1910// Unserialize the transactions1911std::vector<PartiallySignedTransaction> psbtxs;1912UniValue txs = request.params[0].get_array();1914if (txs.size() <= 1) {1915throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs.");1916}1918uint32_t best_version = 1;1919uint32_t best_locktime = 0xffffffff;1920for (unsigned int i = 0; i < txs.size(); ++i) {1921util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(txs[i].get_str());1922if (!psbt_res) {1923throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original));1924}1925psbtxs.push_back(*psbt_res);1926const PartiallySignedTransaction& psbtx = psbtxs.back();1927if (psbtx.GetVersion() != 0) {1928throw JSONRPCError(RPC_INVALID_PARAMETER, "joinpsbts only operates on version 0 PSBTs");1929}1930// Choose the highest version number1931if (psbtx.tx_version > best_version) {1932best_version = psbtx.tx_version;1933}1934// Choose the lowest lock time1935uint32_t psbt_locktime = psbtx.fallback_locktime.value_or(0);1936if (psbt_locktime < best_locktime) {1937best_locktime = psbt_locktime;1938}1939}1941// Create a blank psbt where everything will be added1942CMutableTransaction tx;1943tx.version = best_version;1944tx.nLockTime = best_locktime;1945PartiallySignedTransaction merged_psbt(tx, psbtxs.at(0).GetVersion());1947// Merge1948for (auto& psbt : psbtxs) {1949for (const PSBTInput& input : psbt.inputs) {1950if (!merged_psbt.AddInput(input)) {1951throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input %s:%d exists in multiple PSBTs", input.prev_txid.ToString(), input.prev_out));1952}1953}1954for (const PSBTOutput& output : psbt.outputs) {1955merged_psbt.AddOutput(output);1956}1957merged_psbt.MergeGlobalXPubs(psbt);1958merged_psbt.m_proprietary.insert(psbt.m_proprietary.begin(), psbt.m_proprietary.end());1959merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end());1960}1962// Shuffle the inputs and outputs for privacy1963std::shuffle(merged_psbt.inputs.begin(), merged_psbt.inputs.end(), FastRandomContext());1964std::shuffle(merged_psbt.outputs.begin(), merged_psbt.outputs.end(), FastRandomContext());1966DataStream ssTx{};1967ssTx << merged_psbt;1968return EncodeBase64(ssTx);1969},1970};1971}1973static RPCMethod analyzepsbt()1974{1975return RPCMethod{1976"analyzepsbt",1977"Analyzes and provides information about the current status of a PSBT and its inputs\n",1978{1979{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}1980},1981RPCResult {1982RPCResult::Type::OBJ, "", "",1983{1984{RPCResult::Type::ARR, "inputs", /*optional=*/true, "",1985{1986{RPCResult::Type::OBJ, "", "",1987{1988{RPCResult::Type::BOOL, "has_utxo", "Whether a UTXO is provided"},1989{RPCResult::Type::BOOL, "is_final", "Whether the input is finalized"},1990{RPCResult::Type::OBJ, "missing", /*optional=*/true, "Things that are missing that are required to complete this input",1991{1992{RPCResult::Type::ARR, "pubkeys", /*optional=*/true, "",1993{1994{RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing"},1995}},1996{RPCResult::Type::ARR, "signatures", /*optional=*/true, "",1997{1998{RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose signature is missing"},1999}},2000{RPCResult::Type::STR_HEX, "redeemscript", /*optional=*/true, "Hash160 of the redeem script that is missing"},