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.
1501UniValue r(UniValue::VOBJ);1502ScriptToUniv(output.witness_script, /*out=*/r);1503out.pushKV("witness_script", std::move(r));1504}1506// keypaths1507if (!output.hd_keypaths.empty()) {1508UniValue keypaths(UniValue::VARR);1509for (auto entry : output.hd_keypaths) {1510UniValue keypath(UniValue::VOBJ);1511keypath.pushKV("pubkey", HexStr(entry.first));1512keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint.data())));1513keypath.pushKV("path", WriteHDKeypath(entry.second.path));1514keypaths.push_back(std::move(keypath));1515}1516out.pushKV("bip32_derivs", std::move(keypaths));1517}1519// PSBTv2 stuff1520if (psbtx.GetVersion() >= 2) {1521out.pushKV("amount", ValueFromAmount(output.amount));1522UniValue spk(UniValue::VOBJ);1523ScriptToUniv(output.script, spk, /*include_hex=*/true, /*include_address=*/true);1524out.pushKV("script", spk);1525}1527// Taproot internal key1528if (!output.m_tap_internal_key.IsNull()) {1529out.pushKV("taproot_internal_key", HexStr(output.m_tap_internal_key));1530}1532// Taproot tree1533if (!output.m_tap_tree.empty()) {1534UniValue tree(UniValue::VARR);1535for (const auto& [depth, leaf_ver, script] : output.m_tap_tree) {1536UniValue elem(UniValue::VOBJ);1537elem.pushKV("depth", depth);1538elem.pushKV("leaf_ver", leaf_ver);1539elem.pushKV("script", HexStr(script));1540tree.push_back(std::move(elem));1541}1542out.pushKV("taproot_tree", std::move(tree));1543}1545// Taproot bip32 keypaths1546if (!output.m_tap_bip32_paths.empty()) {1547UniValue keypaths(UniValue::VARR);1548for (const auto& [xonly, leaf_origin] : output.m_tap_bip32_paths) {1549const auto& [leaf_hashes, origin] = leaf_origin;1550UniValue path_obj(UniValue::VOBJ);1551path_obj.pushKV("pubkey", HexStr(xonly));1552path_obj.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(origin.fingerprint.data())));1553path_obj.pushKV("path", WriteHDKeypath(origin.path));1554UniValue leaf_hashes_arr(UniValue::VARR);1555for (const auto& leaf_hash : leaf_hashes) {1556leaf_hashes_arr.push_back(HexStr(leaf_hash));1557}1558path_obj.pushKV("leaf_hashes", std::move(leaf_hashes_arr));1559keypaths.push_back(std::move(path_obj));1560}1561out.pushKV("taproot_bip32_derivs", std::move(keypaths));1562}1564// Write MuSig2 fields1565if (!output.m_musig2_participants.empty()) {1566UniValue musig_pubkeys(UniValue::VARR);1567for (const auto& [agg, parts] : output.m_musig2_participants) {1568UniValue musig_part(UniValue::VOBJ);1569musig_part.pushKV("aggregate_pubkey", HexStr(agg));1570UniValue part_pubkeys(UniValue::VARR);1571for (const auto& pub : parts) {1572part_pubkeys.push_back(HexStr(pub));1573}1574musig_part.pushKV("participant_pubkeys", part_pubkeys);1575musig_pubkeys.push_back(musig_part);1576}1577out.pushKV("musig2_participant_pubkeys", musig_pubkeys);1578}1580// Proprietary1581if (!output.m_proprietary.empty()) {1582UniValue proprietary(UniValue::VARR);1583for (const auto& entry : output.m_proprietary) {1584UniValue this_prop(UniValue::VOBJ);1585this_prop.pushKV("identifier", HexStr(entry.identifier));1586this_prop.pushKV("subtype", entry.subtype);1587this_prop.pushKV("key", HexStr(entry.key));1588this_prop.pushKV("value", HexStr(entry.value));1589proprietary.push_back(std::move(this_prop));1590}1591out.pushKV("proprietary", std::move(proprietary));1592}1594// Unknown data1595if (output.unknown.size() > 0) {1596UniValue unknowns(UniValue::VOBJ);1597for (auto [key, value] : output.unknown) {1598unknowns.pushKVEnd(HexStr(key), HexStr(value));1599}1600out.pushKV("unknown", std::move(unknowns));1601}1603outputs.push_back(std::move(out));1605// Fee calculation1606if (MoneyRange(output.amount) && MoneyRange(output_value + output.amount)) {1607output_value += output.amount;1608} else {1609// Hack to just not show fee later1610have_all_utxos = false;1611}1612}1613result.pushKV("outputs", std::move(outputs));1614if (have_all_utxos) {1615result.pushKV("fee", ValueFromAmount(total_in - output_value));1616}1618return result;1619},1620};1621}1623static RPCMethod combinepsbt()1624{1625return RPCMethod{1626"combinepsbt",1627"Combine multiple partially signed Bitcoin transactions into one transaction.\n"1628"Implements the Combiner role.\n",1629{1630{"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions",1631{1632{"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A base64 string of a PSBT"},1633},1634},1635},1636RPCResult{1637RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"1638},1639RPCExamples{1640HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')")1641},1642[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1643{1644// Unserialize the transactions1645std::vector<PartiallySignedTransaction> psbtxs;1646UniValue txs = request.params[0].get_array();1647if (txs.empty()) {1648throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txs' cannot be empty");1649}1650for (unsigned int i = 0; i < txs.size(); ++i) {1651util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(txs[i].get_str());1652if (!psbt_res) {1653throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original));1654}1655psbtxs.push_back(*psbt_res);1656}1658std::optional<PartiallySignedTransaction> merged_psbt = CombinePSBTs(psbtxs);1659if (!merged_psbt) {1660throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs not compatible (different transactions)");1661}1663DataStream ssTx{};1664ssTx << *merged_psbt;1665return EncodeBase64(ssTx);1666},1667};1668}1670static RPCMethod finalizepsbt()1671{1672return RPCMethod{"finalizepsbt",1673"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"1674"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"1675"created which has the final_scriptSig and final_scriptwitness fields filled for inputs that are complete.\n"1676"Implements the Finalizer and Extractor roles.\n",1677{1678{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},1679{"extract", RPCArg::Type::BOOL, RPCArg::Default{true}, "If true and the transaction is complete,\n"1680" extract and return the complete transaction in normal network serialization instead of the PSBT."},1681},1682RPCResult{1683RPCResult::Type::OBJ, "", "",1684{1685{RPCResult::Type::STR, "psbt", /*optional=*/true, "The base64-encoded partially signed transaction if not extracted"},1686{RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The hex-encoded network transaction if extracted"},1687{RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},1688}1689},1690RPCExamples{1691HelpExampleCli("finalizepsbt", "\"psbt\"")1692},1693[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1694{1695// Unserialize the transactions1696util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(request.params[0].get_str());1697if (!psbt_res) {1698throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original));1699}1700PartiallySignedTransaction psbtx = *psbt_res;1702bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());1704CMutableTransaction mtx;1705bool complete = FinalizeAndExtractPSBT(psbtx, mtx);1707UniValue result(UniValue::VOBJ);1708DataStream ssTx{};1709std::string result_str;1711if (complete && extract) {1712ssTx << TX_WITH_WITNESS(mtx);1713result_str = HexStr(ssTx);1714result.pushKV("hex", result_str);1715} else {1716ssTx << psbtx;1717result_str = EncodeBase64(ssTx.str());1718result.pushKV("psbt", result_str);1719}1720result.pushKV("complete", complete);1722return result;1723},1724};1725}1727static RPCMethod createpsbt()1728{1729return RPCMethod{1730"createpsbt",1731"Creates a transaction in the Partially Signed Transaction format.\n"1732"Implements the Creator role.\n"1733"Note that the transaction's inputs are not signed, and\n"1734"it is not stored in the wallet or transmitted to the network.\n",1735Cat<std::vector<RPCArg>>(1736CreateTxDoc(),1737{1738{"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use."},1739}1740),1741RPCResult{1742RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"1743},1744RPCExamples{1745HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")1746},1747[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1748{1749std::optional<bool> rbf;1750if (!request.params[3].isNull()) {