LCOV - code coverage report
Current view: top level - src/rpc - rawtransaction.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 568 1350 42.1 %
Date: 2026-06-25 07:23:51 Functions: 28 52 53.8 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include <base58.h>
       8             : #include <chain.h>
       9             : #include <chainparams.h>
      10             : #include <coins.h>
      11             : #include <consensus/amount.h>
      12             : #include <consensus/tx_verify.h>
      13             : #include <consensus/validation.h>
      14             : #include <core_io.h>
      15             : #include <index/spentindex.h>
      16             : #include <index/txindex.h>
      17             : #include <init.h>
      18             : #include <key_io.h>
      19             : #include <node/blockstorage.h>
      20             : #include <node/coin.h>
      21             : #include <node/context.h>
      22             : #include <node/psbt.h>
      23             : #include <node/transaction.h>
      24             : #include <policy/packages.h>
      25             : #include <policy/policy.h>
      26             : #include <policy/settings.h>
      27             : #include <primitives/transaction.h>
      28             : #include <psbt.h>
      29             : #include <rpc/blockchain.h>
      30             : #include <rpc/rawtransaction_util.h>
      31             : #include <rpc/server.h>
      32             : #include <rpc/server_util.h>
      33             : #include <rpc/util.h>
      34             : #include <script/script.h>
      35             : #include <script/sign.h>
      36             : #include <script/signingprovider.h>
      37             : #include <script/standard.h>
      38             : #include <txmempool.h>
      39             : #include <uint256.h>
      40             : #include <util/bip32.h>
      41             : #include <util/check.h>
      42             : #include <util/strencodings.h>
      43             : #include <util/string.h>
      44             : #include <util/translation.h>
      45             : #include <util/vector.h>
      46             : #include <validation.h>
      47             : #include <validationinterface.h>
      48             : 
      49             : #include <chainlock/chainlock.h>
      50             : #include <evo/assetlocktx.h>
      51             : #include <evo/cbtx.h>
      52             : #include <evo/chainhelper.h>
      53             : #include <evo/creditpool.h>
      54             : #include <evo/mnhftx.h>
      55             : #include <evo/providertx.h>
      56             : #include <evo/specialtx.h>
      57             : #include <instantsend/instantsend.h>
      58             : #include <instantsend/lock.h>
      59             : #include <llmq/commitment.h>
      60             : #include <llmq/context.h>
      61             : #include <util/helpers.h>
      62             : 
      63             : #include <cstdint>
      64             : #include <numeric>
      65             : 
      66             : #include <univalue.h>
      67             : 
      68             : using node::AnalyzePSBT;
      69             : using node::GetTransaction;
      70             : using node::NodeContext;
      71             : using node::PSBTAnalysis;
      72             : 
      73           0 : void TxToJSON(const CTransaction& tx, const uint256 hashBlock, const  CTxMemPool& mempool, const CChainState& active_chainstate, const chainlock::Chainlocks& chainlocks, const llmq::CInstantSendManager& isman, UniValue& entry, TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS)
      74             : {
      75           0 :     CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS);
      76             : 
      77           0 :     uint256 txid = tx.GetHash();
      78           0 :     CSpentIndexTxInfo *txSpentInfoPtr{nullptr};
      79             : 
      80             :     // Add spent information if spentindex is enabled
      81           0 :     CSpentIndexTxInfo txSpentInfo;
      82           0 :     if (g_spentindex) {
      83             :         // Sync once before all queries to ensure consistent snapshot
      84           0 :         g_spentindex->BlockUntilSyncedToCurrentChain();
      85             : 
      86           0 :         txSpentInfo = CSpentIndexTxInfo{};
      87             :         // Collect spent info for inputs
      88           0 :         for (const auto& txin : tx.vin) {
      89           0 :             if (!tx.IsCoinBase()) {
      90           0 :                 CSpentIndexValue spentInfo;
      91           0 :                 CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
      92           0 :                 if (g_spentindex->GetSpentInfo(spentKey, spentInfo)) {
      93           0 :                     txSpentInfo.mSpentInfo.emplace(spentKey, spentInfo);
      94           0 :                 }
      95           0 :             }
      96             :         }
      97             :         // Collect spent info for outputs
      98           0 :         for (unsigned int i = 0; i < tx.vout.size(); i++) {
      99           0 :             CSpentIndexValue spentInfo;
     100           0 :             CSpentIndexKey spentKey(txid, i);
     101           0 :             if (g_spentindex->GetSpentInfo(spentKey, spentInfo)) {
     102           0 :                 txSpentInfo.mSpentInfo.emplace(spentKey, spentInfo);
     103           0 :             }
     104           0 :         }
     105             : 
     106             :         // Now check mempool (which requires mempool.cs).
     107             :         //
     108             :         // Mempool entry overwrites index entry if present.
     109             :         // During reorg, mempool may have newer state than index (which updates asynchronously).
     110             :         {
     111           0 :             LOCK(mempool.cs);
     112           0 :             for (const auto& txin : tx.vin) {
     113           0 :                 if (!tx.IsCoinBase()) {
     114           0 :                     CSpentIndexValue spentInfo;
     115           0 :                     CSpentIndexKey spentKey(txin.prevout.hash, txin.prevout.n);
     116           0 :                     if (mempool.getSpentIndex(spentKey, spentInfo)) {
     117             :                         // Mempool entry overwrites index entry if present
     118           0 :                         txSpentInfo.mSpentInfo[spentKey] = spentInfo;
     119           0 :                     }
     120           0 :                 }
     121             :             }
     122           0 :             for (unsigned int i = 0; i < tx.vout.size(); i++) {
     123           0 :                 CSpentIndexValue spentInfo;
     124           0 :                 CSpentIndexKey spentKey(txid, i);
     125           0 :                 if (mempool.getSpentIndex(spentKey, spentInfo)) {
     126             :                     // Mempool entry overwrites index entry if present
     127           0 :                     txSpentInfo.mSpentInfo[spentKey] = spentInfo;
     128           0 :                 }
     129           0 :             }
     130           0 :         }
     131             : 
     132           0 :         txSpentInfoPtr = &txSpentInfo;
     133           0 :     }
     134             : 
     135           0 :     LOCK(::cs_main);
     136             :     // Call into TxToUniv() in bitcoin-common to decode the transaction hex.
     137             :     //
     138             :     // Blockchain contextual information (confirmations and blocktime) is not
     139             :     // available to code in bitcoin-common, so we query them here and push the
     140             :     // data into the returned UniValue.
     141             : 
     142           0 :     TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, /*serialize_flags=*/0, /*txundo=*/nullptr, verbosity, txSpentInfoPtr);
     143             : 
     144           0 :     bool chainLock = false;
     145           0 :     if (!hashBlock.IsNull()) {
     146           0 :         entry.pushKV("blockhash", hashBlock.GetHex());
     147           0 :         const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock);
     148           0 :         if (pindex) {
     149           0 :             if (active_chainstate.m_chain.Contains(pindex)) {
     150           0 :                 entry.pushKV("height", pindex->nHeight);
     151           0 :                 entry.pushKV("confirmations", 1 + active_chainstate.m_chain.Height() - pindex->nHeight);
     152           0 :                 entry.pushKV("time", pindex->GetBlockTime());
     153           0 :                 entry.pushKV("blocktime", pindex->GetBlockTime());
     154           0 :                 chainLock = chainlocks.HasChainLock(pindex->nHeight, pindex->GetBlockHash());
     155           0 :             } else {
     156           0 :                 entry.pushKV("height", -1);
     157           0 :                 entry.pushKV("confirmations", 0);
     158             :             }
     159           0 :         }
     160           0 :     }
     161             : 
     162           0 :     bool fLocked = isman.IsLocked(txid);
     163           0 :     entry.pushKV("instantlock", fLocked || chainLock);
     164           0 :     entry.pushKV("instantlock_internal", fLocked);
     165           0 :     entry.pushKV("chainlock", chainLock);
     166           0 : }
     167             : 
     168         191 : static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
     169             : {
     170        3629 :     return {
     171         191 :         {RPCResult::Type::STR_HEX, "txid", txid_field_doc},
     172         191 :         {RPCResult::Type::NUM, "size", "The serialized transaction size"},
     173         191 :         {RPCResult::Type::NUM, "version", "The version"},
     174         191 :         {RPCResult::Type::NUM, "type", "The type"},
     175         191 :         {RPCResult::Type::NUM_TIME, "locktime", "The lock time"},
     176         382 :         {RPCResult::Type::ARR, "vin", "",
     177         382 :         {
     178         382 :             {RPCResult::Type::OBJ, "", "",
     179        1146 :             {
     180         191 :                 {RPCResult::Type::STR_HEX, "coinbase", /*optional=*/true, "The coinbase value (only if coinbase transaction)"},
     181         191 :                 {RPCResult::Type::STR_HEX, "txid", /*optional=*/true, "The transaction id (if not coinbase transaction)"},
     182         191 :                 {RPCResult::Type::NUM, "vout", /*optional=*/true, "The output number (if not coinbase transaction)"},
     183         382 :                 {RPCResult::Type::OBJ, "scriptSig", /*optional=*/true, "The script (if not coinbase transaction)",
     184         573 :                 {
     185         191 :                     {RPCResult::Type::STR, "asm", "Disassembly of the signature script"},
     186         191 :                     {RPCResult::Type::STR_HEX, "hex", "The raw signature script bytes, hex-encoded"},
     187             :                 }},
     188         191 :                 {RPCResult::Type::NUM, "sequence", "The script sequence number"},
     189             :             }},
     190             :         }},
     191         382 :         {RPCResult::Type::ARR, "vout", "",
     192         382 :         {
     193         382 :             {RPCResult::Type::OBJ, "", "",
     194         764 :             {
     195         191 :                 {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
     196         191 :                 {RPCResult::Type::NUM, "n", "index"},
     197         382 :                 {RPCResult::Type::OBJ, "scriptPubKey", "",
     198        1146 :                 {
     199         191 :                     {RPCResult::Type::STR, "asm", "Disassembly of the public key script"},
     200         191 :                     {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
     201         191 :                     {RPCResult::Type::STR_HEX, "hex", "The raw public key script bytes, hex-encoded"},
     202         191 :                     {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
     203         191 :                     {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address (only if a well-defined address exists)"},
     204             :                 }},
     205             :             }},
     206             :         }},
     207         191 :         {RPCResult::Type::NUM, "extraPayloadSize", /*optional=*/true, "Size of DIP2 extra payload. Only present if it's a special TX"},
     208         191 :         {RPCResult::Type::STR_HEX, "extraPayload", /*optional=*/true, "Hex-encoded DIP2 extra payload data. Only present if it's a special TX"},
     209         191 :         CProRegTx::GetJsonHelp(/*key=*/"proRegTx", /*optional=*/true),
     210         191 :         CProUpServTx::GetJsonHelp(/*key=*/"proUpServTx", /*optional=*/true),
     211         191 :         CProUpRegTx::GetJsonHelp(/*key=*/"proUpRegTx", /*optional=*/true),
     212         191 :         CProUpRevTx::GetJsonHelp(/*key=*/"proUpRevTx", /*optional=*/true),
     213         191 :         CCbTx::GetJsonHelp(/*key=*/"cbTx", /*optional=*/true),
     214         191 :         llmq::CFinalCommitmentTxPayload::GetJsonHelp(/*key=*/"qcTx", /*optional=*/true),
     215         191 :         MNHFTxPayload::GetJsonHelp(/*key=*/"mnhfTx", /*optional=*/true),
     216         191 :         CAssetLockPayload::GetJsonHelp(/*key=*/"assetLockTx", /*optional=*/true),
     217         191 :         CAssetUnlockPayload::GetJsonHelp(/*key=*/"assetUnlockTx", /*optional=*/true),
     218             :     };
     219           0 : }
     220             : 
     221         194 : static std::vector<RPCArg> CreateTxDoc()
     222             : {
     223         776 :     return {
     224         388 :         {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs",
     225         388 :             {
     226         388 :                 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
     227         776 :                     {
     228         194 :                         {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
     229         194 :                         {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
     230         194 :                         {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' argument"}, "The sequence number"},
     231             :                     },
     232             :                 },
     233             :             },
     234             :         },
     235         388 :         {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n"
     236             :                 "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n"
     237             :                 "At least one output of either type must be specified.\n"
     238             :                 "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
     239             :                 "                             accepted as second parameter.",
     240         582 :             {
     241         388 :                 {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
     242         388 :                     {
     243         194 :                         {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the Dash address, the value (float or string) is the amount in " + CURRENCY_UNIT},
     244             :                     },
     245             :                 },
     246         388 :                 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
     247         388 :                     {
     248         194 :                         {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
     249             :                     },
     250             :                 },
     251             :             },
     252             :         },
     253         194 :         {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
     254             :     };
     255           0 : }
     256             : 
     257             : // Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors
     258           0 : PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const CoreContext& context, const HidingSigningProvider& provider)
     259             : {
     260             :     // Unserialize the transactions
     261           0 :     PartiallySignedTransaction psbtx;
     262           0 :     std::string error;
     263           0 :     if (!DecodeBase64PSBT(psbtx, psbt_string, error)) {
     264           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
     265             :     }
     266             : 
     267           0 :     if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain();
     268           0 :     const NodeContext& node = EnsureAnyNodeContext(context);
     269             : 
     270             :     // Fetch previous transactions:
     271             :     // First, look in the txindex and the mempool
     272           0 :     for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
     273           0 :         PSBTInput& psbt_input = psbtx.inputs.at(i);
     274           0 :         const CTxIn& tx_in = psbtx.tx->vin.at(i);
     275             : 
     276             :         // The `non_witness_utxo` is the whole previous transaction
     277           0 :         if (psbt_input.non_witness_utxo) continue;
     278             : 
     279           0 :         CTransactionRef tx;
     280             : 
     281             :         // Look in the txindex
     282           0 :         if (g_txindex) {
     283           0 :             uint256 block_hash;
     284           0 :             g_txindex->FindTx(tx_in.prevout.hash, block_hash, tx);
     285           0 :         }
     286             :         // If we still don't have it look in the mempool
     287           0 :         if (!tx) {
     288           0 :             tx = node.mempool->get(tx_in.prevout.hash);
     289           0 :         }
     290           0 :         if (tx) {
     291           0 :             psbt_input.non_witness_utxo = tx;
     292           0 :         }
     293           0 :     }
     294             : 
     295             :     // In Bitcoin, if we still haven't found all of the inputs, the utxo set
     296             :     // is searched and segwit inputs are updated with just the utxo. Dash does
     297             :     // not support segwit, so this fallback is not applicable.
     298             : 
     299           0 :     const PrecomputedTransactionData& txdata = PrecomputePSBTData(psbtx);
     300             : 
     301           0 :     for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
     302           0 :         if (PSBTInputSigned(psbtx.inputs.at(i))) {
     303           0 :             continue;
     304             :         }
     305             : 
     306             :         // Update script/keypath information using descriptor data.
     307             :         // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures
     308             :         // we don't actually care about those here, in fact.
     309           0 :         SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, /*sighash=*/1);
     310           0 :     }
     311             : 
     312             :     // Update script/keypath information using descriptor data.
     313           0 :     for (unsigned int i = 0; i < psbtx.tx->vout.size(); ++i) {
     314           0 :         UpdatePSBTOutput(provider, psbtx, i);
     315           0 :     }
     316             : 
     317           0 :     RemoveUnnecessaryTransactions(psbtx, /*sighash_type=*/1);
     318             : 
     319           0 :     return psbtx;
     320           0 : }
     321             : 
     322          94 : static RPCHelpMan getrawtransaction()
     323             : {
     324          94 :     return RPCHelpMan{
     325          94 :                 "getrawtransaction",
     326          94 :                 "Return the raw transaction data.\n\n"
     327             : 
     328             :                 "By default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n"
     329             :                 "and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block.\n"
     330             :                 "If a blockhash argument is passed, it will return the transaction if\n"
     331             :                 "the specified block is available and the transaction is in that block.\n\n"
     332             :                 "Hint: Use gettransaction for wallet transactions.\n\n"
     333             : 
     334             :                 "If verbose is 'true', returns an Object with information about 'txid'.\n\n"
     335             :                 "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.",
     336         376 :                 {
     337          94 :                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
     338          94 :                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If false, return a string, otherwise return a json object"},
     339          94 :                     {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "The block in which to look for the transaction"},
     340             :                 },
     341         282 :                 {
     342         188 :                     RPCResult{"if verbose is not set or set to false",
     343          94 :                          RPCResult::Type::STR, "data", "The serialized, hex-encoded data for 'txid'"
     344             :                      },
     345         188 :                      RPCResult{"if verbose is set to true",
     346          94 :                          RPCResult::Type::OBJ, "", "",
     347          94 :                          Cat<std::vector<RPCResult>>(
     348        1034 :                          {
     349          94 :                              {RPCResult::Type::BOOL, "in_active_chain", /*optional=*/true, "Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)"},
     350          94 :                              {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "the block hash"},
     351          94 :                              {RPCResult::Type::NUM, "height", "The block height"},
     352          94 :                              {RPCResult::Type::NUM, "confirmations", /*optional=*/true, "The confirmations"},
     353          94 :                              {RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME},
     354          94 :                              {RPCResult::Type::NUM, "time", /*optional=*/true, "Same as \"blocktime\""},
     355          94 :                              {RPCResult::Type::BOOL, "instantlock", "Current transaction lock state"},
     356          94 :                              {RPCResult::Type::BOOL, "instantlock_internal", "Current internal transaction lock state"},
     357          94 :                              {RPCResult::Type::BOOL, "chainlock", "The state of the corresponding block ChainLock"},
     358          94 :                              {RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded data for 'txid'"},
     359             :                          },
     360          94 :                          DecodeTxDoc(/*txid_field_doc=*/"The transaction id (same as provided)")),
     361             :                     },
     362             :                 },
     363          94 :                 RPCExamples{
     364          94 :                     HelpExampleCli("getrawtransaction", "\"mytxid\"")
     365          94 :             + HelpExampleCli("getrawtransaction", "\"mytxid\" true")
     366          94 :             + HelpExampleRpc("getrawtransaction", "\"mytxid\", true")
     367          94 :             + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"")
     368          94 :             + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"")
     369             :                 },
     370          95 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     371             : {
     372           1 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
     373           1 :     ChainstateManager& chainman = EnsureChainman(node);
     374             : 
     375           1 :     bool in_active_chain = true;
     376           1 :     uint256 hash = ParseHashV(request.params[0], "parameter 1");
     377           0 :     const CBlockIndex* blockindex = nullptr;
     378             : 
     379           0 :     if (hash == Params().GenesisBlock().hashMerkleRoot) {
     380             :         // Special exception for the genesis block coinbase transaction
     381           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
     382             :     }
     383             : 
     384             :     // Accept either a bool (true) or a num (>=1) to indicate verbose output.
     385           0 :     bool fVerbose = false;
     386           0 :     if (!request.params[1].isNull()) {
     387           0 :         fVerbose = request.params[1].isNum() ? (request.params[1].getInt<int>() != 0) : request.params[1].get_bool();
     388           0 :     }
     389             : 
     390           0 :     if (!request.params[2].isNull()) {
     391           0 :         LOCK(cs_main);
     392             : 
     393           0 :         uint256 blockhash = ParseHashV(request.params[2], "parameter 3");
     394           0 :         blockindex = chainman.m_blockman.LookupBlockIndex(blockhash);
     395           0 :         if (!blockindex) {
     396           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found");
     397             :         }
     398           0 :         in_active_chain = chainman.ActiveChain().Contains(blockindex);
     399           0 :     }
     400             : 
     401           0 :     bool f_txindex_ready = false;
     402           0 :     if (g_txindex && !blockindex) {
     403           0 :         f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain();
     404           0 :     }
     405             : 
     406           0 :     uint256 hash_block;
     407           0 :     const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), hash, Params().GetConsensus(), hash_block);
     408           0 :     if (!tx) {
     409           0 :         std::string errmsg;
     410           0 :         if (blockindex) {
     411           0 :             const bool block_has_data = WITH_LOCK(::cs_main, return blockindex->nStatus & BLOCK_HAVE_DATA);
     412           0 :             if (!block_has_data) {
     413           0 :                 throw JSONRPCError(RPC_MISC_ERROR, "Block not available");
     414             :             }
     415           0 :             errmsg = "No such transaction found in the provided block";
     416           0 :         } else if (!g_txindex) {
     417           0 :             errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries";
     418           0 :         } else if (!f_txindex_ready) {
     419           0 :             errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed";
     420           0 :         } else {
     421           0 :             errmsg = "No such mempool or blockchain transaction";
     422             :         }
     423           0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions.");
     424           0 :     }
     425             : 
     426           0 :     if (!fVerbose) {
     427           0 :         return EncodeHexTx(*tx);
     428             :     }
     429             : 
     430           0 :     const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
     431           0 :     const CTxMemPool& mempool = EnsureMemPool(node);
     432           0 :     CHECK_NONFATAL(node.chainlocks);
     433             : 
     434           0 :     UniValue result(UniValue::VOBJ);
     435           0 :     if (blockindex) result.pushKV("in_active_chain", in_active_chain);
     436           0 :     TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, *llmq_ctx.isman, result);
     437           0 :     return result;
     438           1 : },
     439             :     };
     440           0 : }
     441             : 
     442          92 : static RPCHelpMan getrawtransactionmulti() {
     443          92 :     return RPCHelpMan{
     444          92 :             "getrawtransactionmulti",
     445          92 :             "\nReturns the raw transaction data for multiple transactions.\n"
     446             :             "\nThis call is an extension of getrawtransaction that supports multiple transactions.\n"
     447             :             "It accepts a map of block hashes to a list of transaction hashes.\n"
     448             :             "A block hash of 0 indicates transactions not yet mined or in the mempool.\n",
     449         276 :             {
     450         184 :                     {"transactions", RPCArg::Type::OBJ, RPCArg::Optional::NO,
     451          92 :                      "A JSON object with block hashes as keys and lists of transaction hashes as values (no more than 100 in total)",
     452         184 :                      {
     453         184 :                              {"blockhash", RPCArg::Type::ARR, RPCArg::Optional::OMITTED,
     454          92 :                               "The block hash and the list of transaction ids to fetch",
     455         184 :                               {
     456          92 :                                       {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The transaction id"},
     457             :                               }},
     458             :                      }},
     459          92 :                     {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
     460          92 :                      "If false, return a string, otherwise return a json object"},
     461             :             },
     462          92 :             RPCResult{
     463          92 :                 RPCResult::Type::OBJ, "", "",
     464         368 :                 {
     465         184 :                     {"If verbose is not set or set to false",
     466          92 :                         RPCResult::Type::STR_HEX, "txid", "The serialized, hex-encoded data for 'txid'"},
     467         184 :                     {"if verbose is set to true",
     468          92 :                         RPCResult::Type::OBJ, "txid", "The decoded network-serialized transaction.",
     469         184 :                         {
     470          92 :                             {RPCResult::Type::ELISION, "", "The layout is the same as the output of getrawtransaction."},
     471             :                         }},
     472          92 :                     {"If tx is unknown", RPCResult::Type::STR, "txid", "None"},
     473             :                 },
     474             :             },
     475          92 :             RPCExamples{
     476         184 :                     HelpExampleCli("getrawtransactionmulti",
     477          92 :                                    R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]}')")
     478         184 :                     + HelpExampleRpc("getrawtransactionmulti",
     479          92 :                                      R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]})")
     480             :             },
     481          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     482             : {
     483             :     // Parse arguments
     484           0 :     UniValue transactions{request.params[0].get_obj()};
     485             :     // Accept either a bool (true) or a num (>=1) to indicate verbose output.
     486           0 :     bool fVerbose{false};
     487           0 :     if (!request.params[1].isNull()) {
     488           0 :         fVerbose = request.params[1].isNum() ? (request.params[1].getInt<int>() != 0) : request.params[1].get_bool();
     489           0 :     }
     490             : 
     491           0 :     const NodeContext& node{EnsureAnyNodeContext(request.context)};
     492           0 :     const ChainstateManager& chainman{EnsureChainman(node)};
     493           0 :     const LLMQContext& llmq_ctx{EnsureLLMQContext(node)};
     494           0 :     CHECK_NONFATAL(node.chainlocks);
     495           0 :     CTxMemPool& mempool{EnsureMemPool(node)};
     496             : 
     497           0 :     if (transactions.size() > 100) {
     498           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 blocks and txids only");
     499             :     }
     500             : 
     501           0 :     size_t count{0};
     502           0 :     UniValue result(UniValue::VOBJ);
     503           0 :     for (const std::string& blockhash_str : transactions.getKeys()) {
     504           0 :         const uint256 blockhash{uint256S(blockhash_str)};
     505           0 :         const UniValue txids = transactions[blockhash_str].get_array();
     506             : 
     507           0 :         const CBlockIndex* blockindex{blockhash.IsNull() ? nullptr : WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(blockhash))};
     508           0 :         if (blockindex == nullptr && !blockhash.IsNull()) {
     509           0 :             for (const auto idx : util::irange(txids.size())) {
     510           0 :                 result.pushKV(txids[idx].get_str(), "None");
     511             :             }
     512           0 :             continue;
     513             :         }
     514             : 
     515           0 :         count += txids.size();
     516           0 :         if (count > 100) {
     517           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 txids in total");
     518             :         }
     519           0 :         for (const auto idx : util::irange(txids.size())) {
     520           0 :             const std::string txid_str = txids[idx].get_str();
     521           0 :             const uint256 txid = ParseHashV(txid_str, "transaction id");
     522             : 
     523           0 :             uint256 hash_block;
     524           0 :             const CTransactionRef tx = GetTransaction(blockindex, &mempool, txid, Params().GetConsensus(), hash_block);
     525           0 :             if (!tx) {
     526           0 :                 result.pushKV(txid_str, "None");
     527           0 :             } else if (fVerbose) {
     528           0 :                 UniValue tx_data{UniValue::VOBJ};
     529           0 :                 TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, *llmq_ctx.isman, tx_data);
     530           0 :                 result.pushKV(txid_str, tx_data);
     531           0 :             } else {
     532           0 :                 result.pushKV(txid_str, EncodeHexTx(*tx));
     533             :             }
     534           0 :         }
     535           0 :     }
     536           0 :     return result;
     537           0 : },
     538             :     };
     539           0 : }
     540             : 
     541          92 : static RPCHelpMan getislocks()
     542             : {
     543         184 :     return RPCHelpMan{"getislocks",
     544          92 :         "\nReturns the raw InstantSend lock data for each txids. Returns Null if there is no known IS yet.",
     545         184 :         {
     546         184 :             {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction ids (no more than 100)",
     547         184 :                 {
     548          92 :                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
     549             :                 },
     550             :             },
     551             :         },
     552          92 :         RPCResult{
     553          92 :             RPCResult::Type::ARR, "", "Response is an array with the same size as the input txids",
     554         276 :                 {{RPCResult::Type::OBJ, "", "",
     555         644 :                 {
     556          92 :                     {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
     557         184 :                     {RPCResult::Type::ARR, "inputs", "The inputs",
     558         184 :                     {
     559         184 :                         {RPCResult::Type::OBJ, "", "",
     560         276 :                             {
     561          92 :                                 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
     562          92 :                                 {RPCResult::Type::NUM, "vout", "The output number"},
     563             :                             },
     564             :                         },
     565             :                     }},
     566          92 :                     {RPCResult::Type::STR_HEX, "id", "Request ID"},
     567          92 :                     {RPCResult::Type::STR_HEX, "cycleHash", "The Cycle Hash"},
     568          92 :                     {RPCResult::Type::STR_HEX, "signature", "The InstantSend's BLS signature"},
     569          92 :                     {RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded data for 'txid'"},
     570             :                 }},
     571         184 :                 RPCResult{"if no InstantSend Lock is known for specified txid",
     572          92 :                      RPCResult::Type::STR, "data", "Just 'None' string"
     573             :                 },
     574             :             }},
     575          92 :         RPCExamples{
     576          92 :             HelpExampleCli("getislocks", "'[\"txid\",...]'")
     577          92 :             + HelpExampleRpc("getislocks", "'[\"txid\",...]'")
     578             :         },
     579          92 :     [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     580             : {
     581           0 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
     582             : 
     583           0 :     UniValue result_arr(UniValue::VARR);
     584           0 :     UniValue txids = request.params[0].get_array();
     585           0 :     if (txids.size() > 100) {
     586           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 txids only");
     587             :     }
     588             : 
     589           0 :     const LLMQContext& llmq_ctx = EnsureLLMQContext(node);
     590           0 :     for (const auto idx : util::irange(txids.size())) {
     591           0 :         const uint256 txid(ParseHashV(txids[idx], "txid"));
     592             : 
     593           0 :         if (const instantsend::InstantSendLockPtr islock = llmq_ctx.isman->GetInstantSendLockByTxid(txid); islock != nullptr) {
     594           0 :             UniValue objIS(UniValue::VOBJ);
     595           0 :             objIS.pushKV("txid", islock->txid.ToString());
     596           0 :             UniValue inputs(UniValue::VARR);
     597           0 :             for (const auto out : islock->inputs) {
     598           0 :                 UniValue outpoint(UniValue::VOBJ);
     599           0 :                 outpoint.pushKV("txid", out.hash.ToString());
     600           0 :                 outpoint.pushKV("vout", static_cast<int64_t>(out.n));
     601           0 :                 inputs.push_back(outpoint);
     602           0 :             }
     603           0 :             objIS.pushKV("inputs", inputs);
     604           0 :             objIS.pushKV("id", islock->GetRequestId().ToString());
     605           0 :             objIS.pushKV("cycleHash", islock->cycleHash.ToString());
     606           0 :             objIS.pushKV("signature", islock->sig.ToString());
     607             :             {
     608           0 :                 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
     609           0 :                 ssTx << *islock;
     610           0 :                 objIS.pushKV("hex", HexStr(ssTx));
     611           0 :             }
     612           0 :             result_arr.push_back(objIS);
     613           0 :         } else {
     614           0 :             result_arr.push_back("None");
     615             :         }
     616             :     }
     617           0 :     return result_arr;
     618             : 
     619           0 : },
     620             :     };
     621           0 : }
     622             : 
     623          94 : static RPCHelpMan gettxchainlocks()
     624             : {
     625          94 :     return RPCHelpMan{
     626          94 :         "gettxchainlocks",
     627          94 :         "\nReturns the block height at which each transaction was mined, and indicates whether it is in the mempool, ChainLocked, or neither.\n",
     628         188 :         {
     629         188 :             {"txids", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction ids (no more than 100)",
     630         188 :                 {
     631          94 :                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A transaction hash"},
     632             :                 },
     633             :             },
     634             :         },
     635          94 :         RPCResult{
     636          94 :             RPCResult::Type::ARR, "", "Response is an array with the same size as the input txids",
     637         188 :             {
     638         188 :                 {RPCResult::Type::OBJ, "", "",
     639         376 :                 {
     640          94 :                     {RPCResult::Type::NUM, "height", "The block height"},
     641          94 :                     {RPCResult::Type::BOOL, "chainlock", "The state of the corresponding block ChainLock"},
     642          94 :                     {RPCResult::Type::BOOL, "mempool", "Mempool status for the transaction"},
     643             :                 }},
     644             :             }
     645             :         },
     646          94 :         RPCExamples{
     647          94 :             HelpExampleCli("gettxchainlocks", "'[\"mytxid\",...]'")
     648          94 :         + HelpExampleRpc("gettxchainlocks", "[\"mytxid\",...]")
     649             :         },
     650          94 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     651             : {
     652           0 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
     653           0 :     const ChainstateManager& chainman = EnsureChainman(node);
     654           0 :     const CChainState& active_chainstate = chainman.ActiveChainstate();
     655           0 :     CHECK_NONFATAL(node.chainlocks);
     656             : 
     657           0 :     UniValue result_arr(UniValue::VARR);
     658           0 :     UniValue txids = request.params[0].get_array();
     659           0 :     if (txids.size() > 100) {
     660           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 txids only");
     661             :     }
     662             : 
     663           0 :     if (g_txindex) {
     664           0 :         g_txindex->BlockUntilSyncedToCurrentChain();
     665           0 :     }
     666             : 
     667           0 :     for (const auto idx : util::irange(txids.size())) {
     668           0 :         UniValue result(UniValue::VOBJ);
     669           0 :         const uint256 txid(ParseHashV(txids[idx], "txid"));
     670           0 :         if (txid == Params().GenesisBlock().hashMerkleRoot) {
     671             :             // Special exception for the genesis block coinbase transaction
     672           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved");
     673             :         }
     674             : 
     675           0 :         uint256 hash_block;
     676           0 :         int height{-1};
     677           0 :         bool chainLock{false};
     678             : 
     679           0 :         const auto tx_ref = GetTransaction(nullptr, node.mempool.get(), txid, Params().GetConsensus(), hash_block);
     680             : 
     681           0 :         if (tx_ref == nullptr) {
     682           0 :             result.pushKV("height", -1);
     683           0 :             result.pushKV("chainlock", false);
     684           0 :             result.pushKV("mempool", false);
     685           0 :             result_arr.push_back(result);
     686           0 :             continue;
     687             :         }
     688             : 
     689           0 :         if (!hash_block.IsNull()) {
     690           0 :             LOCK(cs_main);
     691           0 :             const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hash_block);
     692           0 :             if (pindex && active_chainstate.m_chain.Contains(pindex)) {
     693           0 :                 height = pindex->nHeight;
     694           0 :             }
     695           0 :         }
     696           0 :         if (height != -1) {
     697           0 :             chainLock = node.chainlocks->HasChainLock(height, hash_block);
     698           0 :         }
     699           0 :         result.pushKV("height", height);
     700           0 :         result.pushKV("chainlock", chainLock);
     701           0 :         result.pushKV("mempool", height == -1);
     702           0 :         result_arr.push_back(result);
     703           0 :     }
     704           0 :     return result_arr;
     705           0 : },
     706             :     };
     707           0 : }
     708             : 
     709          92 : static RPCHelpMan getassetunlockstatuses()
     710             : {
     711          92 :     return RPCHelpMan{
     712          92 :             "getassetunlockstatuses",
     713          92 :             "\nReturns the status of given Asset Unlock indexes at the tip of the chain or at a specific block height if specified.\n",
     714         276 :             {
     715         184 :                     {"indexes", RPCArg::Type::ARR, RPCArg::Optional::NO, "The Asset Unlock indexes (no more than 100)",
     716         184 :                      {
     717          92 :                              {"index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "An Asset Unlock index"},
     718             :                      },
     719             :                     },
     720          92 :                     {"height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The maximum block height to check"},
     721             :             },
     722          92 :             RPCResult{
     723          92 :                     RPCResult::Type::ARR, "", "Response is an array with the same size as the input txids",
     724         184 :                     {
     725         184 :                             {RPCResult::Type::OBJ, "", "",
     726         276 :                              {
     727          92 :                                 {RPCResult::Type::NUM, "index", "The Asset Unlock index"},
     728          92 :                                 {RPCResult::Type::STR, "status", "Status of the Asset Unlock index: {chainlocked|mined|mempooled|unknown}"},
     729             :                              }},
     730             :                     }
     731             :             },
     732          92 :             RPCExamples{
     733          92 :                     HelpExampleCli("getassetunlockstatuses", "'[\"myindex\",...]'")
     734          92 :                     + HelpExampleRpc("getassetunlockstatuses", "[\"myindex\",...]")
     735             :             },
     736          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     737             : {
     738           0 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
     739           0 :     const CTxMemPool& mempool = EnsureMemPool(node);
     740           0 :     CHECK_NONFATAL(node.chainlocks);
     741           0 :     const ChainstateManager& chainman = EnsureChainman(node);
     742           0 :     auto& chain_helper = chainman.ActiveChainstate().ChainHelper();
     743           0 :     UniValue result_arr(UniValue::VARR);
     744           0 :     const UniValue str_indexes = request.params[0].get_array();
     745           0 :     if (str_indexes.size() > 100) {
     746           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 indexes only");
     747             :     }
     748             : 
     749           0 :     if (g_txindex) {
     750           0 :         g_txindex->BlockUntilSyncedToCurrentChain();
     751           0 :     }
     752             : 
     753           0 :     const CBlockIndex* pTipBlockIndex{WITH_LOCK(cs_main, return chainman.ActiveChain().Tip())};
     754             : 
     755           0 :     if (!pTipBlockIndex) {
     756           0 :         throw JSONRPCError(RPC_INTERNAL_ERROR, "No blocks in chain");
     757             :     }
     758             : 
     759           0 :     std::optional<CCreditPool> poolCL{std::nullopt};
     760           0 :     std::optional<CCreditPool> poolOnTip{std::nullopt};
     761           0 :     std::optional<int> nSpecificCoreHeight{std::nullopt};
     762             : 
     763           0 :     if (!request.params[1].isNull()) {
     764           0 :         nSpecificCoreHeight = request.params[1].getInt<int>();
     765           0 :         if (nSpecificCoreHeight.value() < 0 || nSpecificCoreHeight.value() > chainman.ActiveChain().Height()) {
     766           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
     767             :         }
     768           0 :         poolCL = std::make_optional(chain_helper.GetCreditPool(chainman.ActiveChain()[nSpecificCoreHeight.value()]));
     769           0 :     }
     770             :     else {
     771           0 :         const auto pBlockIndexBestCL = [&]() -> const CBlockIndex* {
     772           0 :             const auto best_clsig = node.chainlocks->GetBestChainLock();
     773           0 :             if (!best_clsig.IsNull()) {
     774           0 :                 return pTipBlockIndex->GetAncestor(best_clsig.getHeight());
     775             :             }
     776             :             // If no CL info is available, try to use CbTx CL information
     777           0 :             if (const auto cbtx_best_cl = GetNonNullCoinbaseChainlock(pTipBlockIndex)) {
     778           0 :                 return pTipBlockIndex->GetAncestor(pTipBlockIndex->nHeight - cbtx_best_cl->second - 1);
     779             :             }
     780             :             // no CL info, no CbTx CL
     781           0 :             return nullptr;
     782           0 :         }();
     783             : 
     784             :         // We need in 2 credit pools: at tip of chain and on best CL to know if tx is mined or chainlocked
     785             :         // Sometimes that's two different blocks, sometimes not and we need to initialize 2nd creditPoolManager
     786           0 :         poolCL = pBlockIndexBestCL ?
     787           0 :                  std::make_optional(chain_helper.GetCreditPool(pBlockIndexBestCL)) :
     788           0 :                  std::nullopt;
     789             : 
     790           0 :         poolOnTip = [&]() -> std::optional<CCreditPool> {
     791           0 :             if (pTipBlockIndex != pBlockIndexBestCL) {
     792           0 :                 return std::make_optional(chain_helper.GetCreditPool(pTipBlockIndex));
     793             :             }
     794           0 :             return std::nullopt;
     795           0 :         }();
     796             :     }
     797             : 
     798           0 :     for (const auto i : util::irange(str_indexes.size())) {
     799           0 :         UniValue obj(UniValue::VOBJ);
     800           0 :         uint64_t index{};
     801           0 :         if (!ParseUInt64(str_indexes[i].get_str(), &index)) {
     802           0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid index");
     803             :         }
     804           0 :         obj.pushKV("index", index);
     805           0 :         auto status_to_push = [&]() -> std::string {
     806           0 :             if (poolCL.has_value() && poolCL->indexes.Contains(index)) {
     807           0 :                 return "chainlocked";
     808             :             }
     809           0 :             if (poolOnTip.has_value() && poolOnTip->indexes.Contains(index)) {
     810           0 :                 return "mined";
     811             :             }
     812           0 :             bool is_mempooled = [&]() {
     813           0 :                 LOCK(mempool.cs);
     814           0 :                 return std::any_of(mempool.mapTx.begin(), mempool.mapTx.end(), [index](const CTxMemPoolEntry &e) {
     815           0 :                     if (e.GetTx().nType == CAssetUnlockPayload::SPECIALTX_TYPE) {
     816           0 :                         if (auto opt_assetUnlockTx = GetTxPayload<CAssetUnlockPayload>(e.GetTx())) {
     817           0 :                             return index == opt_assetUnlockTx->getIndex();
     818             :                         } else {
     819           0 :                             throw JSONRPCError(RPC_TRANSACTION_ERROR, "bad-assetunlocktx-payload");
     820             :                         }
     821             :                     }
     822           0 :                     return false;
     823           0 :                 });
     824           0 :             }();
     825           0 :             return is_mempooled && !nSpecificCoreHeight.has_value() ? "mempooled" : "unknown";
     826           0 :         };
     827           0 :         obj.pushKV("status", status_to_push());
     828           0 :         result_arr.push_back(obj);
     829           0 :     }
     830             : 
     831           0 :     return result_arr;
     832           0 : },
     833             :     };
     834           0 : }
     835             : 
     836         102 : static RPCHelpMan createrawtransaction()
     837             : {
     838         204 :     return RPCHelpMan{"createrawtransaction",
     839         102 :                 "\nCreate a transaction spending the given inputs and creating new outputs.\n"
     840             :                 "Outputs can be addresses or data.\n"
     841             :                 "Returns hex-encoded raw transaction.\n"
     842             :                 "Note that the transaction's inputs are not signed, and\n"
     843             :                 "it is not stored in the wallet or transmitted to the network.\n",
     844         102 :                 CreateTxDoc(),
     845         102 :                 RPCResult{
     846         102 :                     RPCResult::Type::STR_HEX, "transaction", "hex string of the transaction"
     847             :                 },
     848         102 :                 RPCExamples{
     849         102 :                     HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
     850         102 :             + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
     851         102 :             + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"")
     852         102 :             + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
     853             :                 },
     854         111 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     855             : {
     856          36 :     RPCTypeCheck(request.params, {
     857           9 :         UniValue::VARR,
     858           9 :         UniValueType(), // ARR or OBJ, checked later
     859           9 :         UniValue::VNUM,
     860             :         }, true
     861             :     );
     862             : 
     863           8 :     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2]);
     864             : 
     865           8 :     return EncodeHexTx(CTransaction(rawTx));
     866           9 : },
     867             :     };
     868           0 : }
     869             : 
     870          97 : static RPCHelpMan decoderawtransaction()
     871             : {
     872         194 :     return RPCHelpMan{"decoderawtransaction",
     873          97 :                 "Return a JSON object representing the serialized, hex-encoded transaction.",
     874         194 :                 {
     875          97 :                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
     876             :                 },
     877          97 :                 RPCResult{
     878          97 :                     RPCResult::Type::OBJ, "", "",
     879          97 :                     DecodeTxDoc(/*txid_field_doc=*/"The transaction id"),
     880             :                 },
     881          97 :                 RPCExamples{
     882          97 :                     HelpExampleCli("decoderawtransaction", "\"hexstring\"")
     883          97 :             + HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
     884             :                 },
     885         100 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     886             : {
     887           5 :     RPCTypeCheck(request.params, {UniValue::VSTR});
     888             : 
     889           3 :     CMutableTransaction mtx;
     890             : 
     891           3 :     if (!DecodeHexTx(mtx, request.params[0].get_str()))
     892           2 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
     893             : 
     894           1 :     UniValue result(UniValue::VOBJ);
     895           1 :     TxToUniv(CTransaction(std::move(mtx)), /*block_hash=*/uint256(), /*entry=*/result, /*include_hex=*/false);
     896             : 
     897           1 :     return result;
     898           5 : },
     899             :     };
     900           0 : }
     901             : 
     902          92 : static RPCHelpMan decodescript()
     903             : {
     904          92 :     return RPCHelpMan{
     905          92 :         "decodescript",
     906          92 :         "\nDecode a hex-encoded script.\n",
     907         184 :         {
     908          92 :             {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"},
     909             :         },
     910          92 :         RPCResult{
     911          92 :             RPCResult::Type::OBJ, "", "",
     912         460 :             {
     913          92 :                 {RPCResult::Type::STR, "asm", "Script public key"},
     914          92 :                 {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"},
     915          92 :                 {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
     916          92 :                 {RPCResult::Type::STR, "address", /*optional=*/true, "The Dash address (only if a well-defined address exists)"},
     917             :             },
     918             :         },
     919          92 :         RPCExamples{
     920          92 :             HelpExampleCli("decodescript", "\"hexstring\"")
     921          92 :           + HelpExampleRpc("decodescript", "\"hexstring\"")
     922             :         },
     923          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     924             : {
     925           0 :     RPCTypeCheck(request.params, {UniValue::VSTR});
     926             : 
     927           0 :     UniValue r(UniValue::VOBJ);
     928           0 :     CScript script;
     929           0 :     if (request.params[0].get_str().size() > 0){
     930           0 :         std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
     931           0 :         script = CScript(scriptData.begin(), scriptData.end());
     932           0 :     } else {
     933             :         // Empty scripts are valid
     934             :     }
     935           0 :     ScriptToUniv(script, /*out=*/r, /*include_hex=*/false, /*include_address=*/true);
     936             : 
     937           0 :     std::vector<std::vector<unsigned char>> solutions_data;
     938           0 :     const TxoutType which_type{Solver(script, solutions_data)};
     939             : 
     940           0 :     if (which_type != TxoutType::SCRIPTHASH) {
     941             :         // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
     942             :         // don't return the address for a P2SH of the P2SH.
     943           0 :         r.pushKV("p2sh", EncodeDestination(ScriptHash(script)));
     944           0 :     }
     945             : 
     946           0 :     return r;
     947           0 : },
     948             :     };
     949           0 : }
     950             : 
     951          92 : static RPCHelpMan combinerawtransaction()
     952             : {
     953         184 :     return RPCHelpMan{"combinerawtransaction",
     954          92 :                 "\nCombine multiple partially signed transactions into one transaction.\n"
     955             :                 "The combined transaction may be another partially signed transaction or a \n"
     956             :                 "fully signed transaction.",
     957         184 :                 {
     958         184 :                     {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The of hex strings of partially signed transactions",
     959         184 :                         {
     960          92 :                             {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A hex-encoded raw transaction"},
     961             :                         },
     962             :                         },
     963             :                 },
     964          92 :                 RPCResult{
     965          92 :                     RPCResult::Type::STR, "", "The hex-encoded raw transaction with signature(s)"
     966             :                 },
     967          92 :                 RPCExamples{
     968          92 :                     HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')")
     969             :                 },
     970          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
     971             : {
     972             : 
     973           0 :     UniValue txs = request.params[0].get_array();
     974           0 :     std::vector<CMutableTransaction> txVariants(txs.size());
     975             : 
     976           0 :     for (unsigned int idx = 0; idx < txs.size(); idx++) {
     977           0 :         if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) {
     978           0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d. Make sure the tx has at least one input.", idx));
     979             :         }
     980           0 :     }
     981             : 
     982           0 :     if (txVariants.empty()) {
     983           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transactions");
     984             :     }
     985             : 
     986             :     // mergedTx will end up with all the signatures; it
     987             :     // starts as a clone of the rawtx:
     988           0 :     CMutableTransaction mergedTx(txVariants[0]);
     989             : 
     990             :     // Fetch previous transactions (inputs):
     991           0 :     CCoinsView viewDummy;
     992           0 :     CCoinsViewCache view(&viewDummy);
     993             :     {
     994           0 :         const NodeContext& node = EnsureAnyNodeContext(request.context);
     995           0 :         const CTxMemPool& mempool = EnsureMemPool(node);
     996           0 :         ChainstateManager& chainman = EnsureChainman(node);
     997           0 :         LOCK2(cs_main, mempool.cs);
     998           0 :         CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip();
     999           0 :         CCoinsViewMemPool viewMempool(&viewChain, mempool);
    1000           0 :         view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
    1001             : 
    1002           0 :         for (const CTxIn& txin : mergedTx.vin) {
    1003           0 :             view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail.
    1004             :         }
    1005             : 
    1006           0 :         view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
    1007           0 :     }
    1008             : 
    1009             :     // Use CTransaction for the constant parts of the
    1010             :     // transaction to avoid rehashing.
    1011           0 :     const CTransaction txConst(mergedTx);
    1012             :     // Sign what we can:
    1013           0 :     for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
    1014           0 :         CTxIn& txin = mergedTx.vin[i];
    1015           0 :         const Coin& coin = view.AccessCoin(txin.prevout);
    1016           0 :         if (coin.IsSpent()) {
    1017           0 :             throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent");
    1018             :         }
    1019           0 :         SignatureData sigdata;
    1020             : 
    1021             :         // ... and merge in other signatures:
    1022           0 :         for (const CMutableTransaction& txv : txVariants) {
    1023           0 :             if (txv.vin.size() > i) {
    1024           0 :                 sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out));
    1025           0 :             }
    1026             :         }
    1027           0 :         ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(mergedTx, i, coin.out.nValue, 1), coin.out.scriptPubKey, sigdata);
    1028             : 
    1029           0 :         UpdateInput(txin, sigdata);
    1030           0 :     }
    1031             : 
    1032           0 :     return EncodeHexTx(CTransaction(mergedTx));
    1033           0 : },
    1034             :     };
    1035           0 : }
    1036             : 
    1037          94 : static RPCHelpMan signrawtransactionwithkey()
    1038             : {
    1039         188 :     return RPCHelpMan{"signrawtransactionwithkey",
    1040          94 :                 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
    1041             :                 "The second argument is an array of base58-encoded private\n"
    1042             :                 "keys that will be the only keys used to sign the transaction.\n"
    1043             :                 "The third optional argument (may be null) is an array of previous transaction outputs that\n"
    1044             :                 "this transaction depends on but may not yet be in the block chain.\n",
    1045         470 :                 {
    1046          94 :                     {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
    1047         188 :                     {"privkeys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base58-encoded private keys for signing",
    1048         188 :                         {
    1049          94 :                             {"privatekey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "private key in base58-encoding"},
    1050             :                         },
    1051             :                         },
    1052         188 :                     {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
    1053         188 :                         {
    1054         188 :                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
    1055         564 :                                 {
    1056          94 :                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
    1057          94 :                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
    1058          94 :                                     {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
    1059          94 :                                     {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH or P2WSH) redeem script"},
    1060          94 :                                     {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "The amount spent"},
    1061             :                                 },
    1062             :                             },
    1063             :                         },
    1064             :                     },
    1065          94 :                     {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"ALL"}, "The signature hash type. Must be one of:\n"
    1066             :             "       \"ALL\"\n"
    1067             :             "       \"NONE\"\n"
    1068             :             "       \"SINGLE\"\n"
    1069             :             "       \"ALL|ANYONECANPAY\"\n"
    1070             :             "       \"NONE|ANYONECANPAY\"\n"
    1071             :             "       \"SINGLE|ANYONECANPAY\"\n"
    1072             :                     },
    1073             :                 },
    1074          94 :                 RPCResult{
    1075          94 :                     RPCResult::Type::OBJ, "", "",
    1076         376 :                     {
    1077          94 :                         {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
    1078          94 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    1079         188 :                         {RPCResult::Type::ARR, "errors", /*optional=*/true, "Script verification errors (if there are any)",
    1080         188 :                         {
    1081         188 :                             {RPCResult::Type::OBJ, "", "",
    1082         564 :                             {
    1083          94 :                                 {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
    1084          94 :                                 {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
    1085          94 :                                 {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
    1086          94 :                                 {RPCResult::Type::NUM, "sequence", "Script sequence number"},
    1087          94 :                                 {RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
    1088             :                             }},
    1089             :                         }},
    1090             :                     }
    1091             :                 },
    1092          94 :                 RPCExamples{
    1093          94 :                     HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
    1094          94 :             + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"")
    1095             :                 },
    1096          96 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1097             : {
    1098           2 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true);
    1099             : 
    1100           2 :     CMutableTransaction mtx;
    1101           2 :     if (!DecodeHexTx(mtx, request.params[0].get_str())) {
    1102           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
    1103             :     }
    1104             : 
    1105           2 :     FillableSigningProvider keystore;
    1106           2 :     const UniValue& keys = request.params[1].get_array();
    1107           4 :     for (unsigned int idx = 0; idx < keys.size(); ++idx) {
    1108           2 :         UniValue k = keys[idx];
    1109           2 :         CKey key = DecodeSecret(k.get_str());
    1110           2 :         if (!key.IsValid()) {
    1111           0 :             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
    1112             :         }
    1113           2 :         keystore.AddKey(key);
    1114           2 :     }
    1115             : 
    1116             :     // Fetch previous transactions (inputs):
    1117           2 :     std::map<COutPoint, Coin> coins;
    1118           4 :     for (const CTxIn& txin : mtx.vin) {
    1119           2 :         coins[txin.prevout]; // Create empty map entry keyed by prevout.
    1120             :     }
    1121           2 :     const NodeContext& node = EnsureAnyNodeContext(request.context);
    1122           2 :     FindCoins(node, coins);
    1123             : 
    1124             :     // Parse the prevtxs array
    1125           2 :     ParsePrevouts(request.params[2], &keystore, coins);
    1126             : 
    1127           2 :     UniValue result(UniValue::VOBJ);
    1128           2 :     SignTransaction(mtx, &keystore, coins, request.params[3], result);
    1129           2 :     return result;
    1130           2 : },
    1131             :     };
    1132           0 : }
    1133             : 
    1134         146 : const RPCResult decodepsbt_inputs{
    1135         146 :     RPCResult::Type::ARR, "inputs", "",
    1136         292 :     {
    1137         292 :         {RPCResult::Type::OBJ, "", "",
    1138        1898 :         {
    1139         292 :             {RPCResult::Type::OBJ, "non_witness_utxo", /*optional=*/true, "Decoded network transaction for non-witness UTXOs",
    1140         292 :             {
    1141         146 :                 {RPCResult::Type::ELISION, "",""},
    1142             :             }},
    1143         292 :             {RPCResult::Type::OBJ_DYN, "partial_signatures", /*optional=*/true, "",
    1144         292 :             {
    1145         146 :                 {RPCResult::Type::STR, "pubkey", "The public key and signature that corresponds to it."},
    1146             :             }},
    1147         146 :             {RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"},
    1148         292 :             {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
    1149         584 :             {
    1150         146 :                 {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
    1151         146 :                 {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
    1152         146 :                 {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
    1153             :             }},
    1154         292 :             {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
    1155         292 :             {
    1156         292 :                 {RPCResult::Type::OBJ, "", "",
    1157         584 :                 {
    1158         146 :                     {RPCResult::Type::STR, "pubkey", "The public key with the derivation path as the value."},
    1159         146 :                     {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"},
    1160         146 :                     {RPCResult::Type::STR, "path", "The path"},
    1161             :                 }},
    1162             :             }},
    1163         292 :             {RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "",
    1164         438 :             {
    1165         146 :                 {RPCResult::Type::STR, "asm", "Disassembly of the final signature script"},
    1166         146 :                 {RPCResult::Type::STR_HEX, "hex", "The raw final signature script bytes, hex-encoded"},
    1167             :             }},
    1168         292 :             {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/true, "",
    1169         292 :             {
    1170         146 :                 {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."},
    1171             :             }},
    1172         292 :             {RPCResult::Type::OBJ_DYN, "sha256_preimages", /*optional=*/true, "",
    1173         292 :             {
    1174         146 :                 {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."},
    1175             :             }},
    1176         292 :             {RPCResult::Type::OBJ_DYN, "hash160_preimages", /*optional=*/true, "",
    1177         292 :             {
    1178         146 :                 {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."},
    1179             :             }},
    1180         292 :             {RPCResult::Type::OBJ_DYN, "hash256_preimages", /*optional=*/true, "",
    1181         292 :             {
    1182         146 :                 {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."},
    1183             :             }},
    1184         292 :             {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown input fields",
    1185         292 :             {
    1186         146 :                 {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"},
    1187             :             }},
    1188         292 :             {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The input proprietary map",
    1189         292 :             {
    1190         292 :                 {RPCResult::Type::OBJ, "", "",
    1191         730 :                 {
    1192         146 :                     {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"},
    1193         146 :                     {RPCResult::Type::NUM, "subtype", "The number for the subtype"},
    1194         146 :                     {RPCResult::Type::STR_HEX, "key", "The hex for the key"},
    1195         146 :                     {RPCResult::Type::STR_HEX, "value", "The hex for the value"},
    1196             :                 }},
    1197             :             }},
    1198             :         }},
    1199             :     }
    1200             : };
    1201             : 
    1202         146 : const RPCResult decodepsbt_outputs{
    1203         146 :     RPCResult::Type::ARR, "outputs", "",
    1204         292 :     {
    1205         292 :         {RPCResult::Type::OBJ, "", "",
    1206         730 :         {
    1207         292 :             {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "",
    1208         584 :             {
    1209         146 :                 {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"},
    1210         146 :                 {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"},
    1211         146 :                 {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
    1212             :             }},
    1213         292 :             {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "",
    1214         292 :             {
    1215         292 :                 {RPCResult::Type::OBJ, "", "",
    1216         584 :                 {
    1217         146 :                     {RPCResult::Type::STR, "pubkey", "The public key this path corresponds to"},
    1218         146 :                     {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"},
    1219         146 :                     {RPCResult::Type::STR, "path", "The path"},
    1220             :                 }},
    1221             :             }},
    1222         292 :             {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown global fields",
    1223         292 :             {
    1224         146 :                 {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"},
    1225             :             }},
    1226         292 :             {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The output proprietary map",
    1227         292 :             {
    1228         292 :                 {RPCResult::Type::OBJ, "", "",
    1229         730 :                 {
    1230         146 :                     {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"},
    1231         146 :                     {RPCResult::Type::NUM, "subtype", "The number for the subtype"},
    1232         146 :                     {RPCResult::Type::STR_HEX, "key", "The hex for the key"},
    1233         146 :                     {RPCResult::Type::STR_HEX, "value", "The hex for the value"},
    1234             :                 }},
    1235             :             }},
    1236             :         }},
    1237             :     }
    1238             : };
    1239             : 
    1240          92 : static RPCHelpMan decodepsbt()
    1241             : {
    1242          92 :     return RPCHelpMan{
    1243          92 :         "decodepsbt",
    1244          92 :         "Return a JSON object representing the serialized, base64-encoded partially signed blockchain transaction.",
    1245         184 :                 {
    1246          92 :                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"},
    1247             :                 },
    1248          92 :                 RPCResult{
    1249          92 :                     RPCResult::Type::OBJ, "", "",
    1250         644 :                     {
    1251         184 :                         {RPCResult::Type::OBJ, "tx", "The decoded network-serialized unsigned transaction.",
    1252         184 :                         {
    1253          92 :                             {RPCResult::Type::ELISION, "", "The layout is the same as the output of decoderawtransaction."},
    1254             :                         }},
    1255         184 :                         {RPCResult::Type::ARR, "global_xpubs", "",
    1256         184 :                         {
    1257         184 :                             {RPCResult::Type::OBJ, "", "",
    1258         368 :                             {
    1259          92 :                                 {RPCResult::Type::STR, "xpub", "The extended public key this path corresponds to"},
    1260          92 :                                 {RPCResult::Type::STR_HEX, "master_fingerprint", "The fingerprint of the master key"},
    1261          92 :                                 {RPCResult::Type::STR, "path", "The path"},
    1262             :                             }},
    1263             :                         }},
    1264          92 :                         {RPCResult::Type::NUM, "psbt_version", "The PSBT version number. Not to be confused with the unsigned transaction version"},
    1265         184 :                         {RPCResult::Type::ARR, "proprietary", "The global proprietary map",
    1266         184 :                         {
    1267         184 :                             {RPCResult::Type::OBJ, "", "",
    1268         460 :                             {
    1269          92 :                                 {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"},
    1270          92 :                                 {RPCResult::Type::NUM, "subtype", "The number for the subtype"},
    1271          92 :                                 {RPCResult::Type::STR_HEX, "key", "The hex for the key"},
    1272          92 :                                 {RPCResult::Type::STR_HEX, "value", "The hex for the value"},
    1273             :                             }},
    1274             :                         }},
    1275         184 :                         {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields",
    1276         184 :                         {
    1277          92 :                              {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"},
    1278             :                         }},
    1279          92 :                         decodepsbt_inputs,
    1280          92 :                         decodepsbt_outputs,
    1281          92 :                         {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."},
    1282             :                     }
    1283             :                 },
    1284          92 :                 RPCExamples{
    1285          92 :                     HelpExampleCli("decodepsbt", "\"psbt\"")
    1286             :                 },
    1287          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1288             : {
    1289           0 :     RPCTypeCheck(request.params, {UniValue::VSTR});
    1290             : 
    1291             :     // Unserialize the transactions
    1292           0 :     PartiallySignedTransaction psbtx;
    1293           0 :     std::string error;
    1294           0 :     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
    1295           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1296             :     }
    1297             : 
    1298           0 :     UniValue result(UniValue::VOBJ);
    1299             : 
    1300             :     // Add the decoded tx
    1301           0 :     UniValue tx_univ(UniValue::VOBJ);
    1302           0 :     TxToUniv(CTransaction(*psbtx.tx), /*block_hash=*/uint256(), /*entry=*/tx_univ, /*include_hex=*/false);
    1303           0 :     result.pushKV("tx", tx_univ);
    1304             : 
    1305             :     // Add the global xpubs
    1306           0 :     UniValue global_xpubs(UniValue::VARR);
    1307           0 :     for (std::pair<KeyOriginInfo, std::set<CExtPubKey>> xpub_pair : psbtx.m_xpubs) {
    1308           0 :         for (auto& xpub : xpub_pair.second) {
    1309           0 :             std::vector<unsigned char> ser_xpub;
    1310           0 :             ser_xpub.assign(BIP32_EXTKEY_WITH_VERSION_SIZE, 0);
    1311           0 :             xpub.EncodeWithVersion(ser_xpub.data());
    1312             : 
    1313           0 :             UniValue keypath(UniValue::VOBJ);
    1314           0 :             keypath.pushKV("xpub", EncodeBase58Check(ser_xpub));
    1315           0 :             keypath.pushKV("master_fingerprint", HexStr(Span<unsigned char>(xpub_pair.first.fingerprint, xpub_pair.first.fingerprint + 4)));
    1316           0 :             keypath.pushKV("path", WriteHDKeypath(xpub_pair.first.path));
    1317           0 :             global_xpubs.push_back(keypath);
    1318           0 :         }
    1319           0 :     }
    1320           0 :     result.pushKV("global_xpubs", global_xpubs);
    1321             : 
    1322             :     // PSBT version
    1323           0 :     result.pushKV("psbt_version", static_cast<uint64_t>(psbtx.GetVersion()));
    1324             : 
    1325             :     // Proprietary
    1326           0 :     UniValue proprietary(UniValue::VARR);
    1327           0 :     for (const auto& entry : psbtx.m_proprietary) {
    1328           0 :         UniValue this_prop(UniValue::VOBJ);
    1329           0 :         this_prop.pushKV("identifier", HexStr(entry.identifier));
    1330           0 :         this_prop.pushKV("subtype", entry.subtype);
    1331           0 :         this_prop.pushKV("key", HexStr(entry.key));
    1332           0 :         this_prop.pushKV("value", HexStr(entry.value));
    1333           0 :         proprietary.push_back(this_prop);
    1334           0 :     }
    1335           0 :     result.pushKV("proprietary", proprietary);
    1336             : 
    1337             :     // Unknown data
    1338           0 :     UniValue unknowns(UniValue::VOBJ);
    1339           0 :     for (auto entry : psbtx.unknown) {
    1340           0 :         unknowns.pushKV(HexStr(entry.first), HexStr(entry.second));
    1341           0 :     }
    1342           0 :     result.pushKV("unknown", unknowns);
    1343             : 
    1344             :     // inputs
    1345           0 :     CAmount total_in = 0;
    1346           0 :     bool have_all_utxos = true;
    1347           0 :     UniValue inputs(UniValue::VARR);
    1348           0 :     for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
    1349           0 :         const PSBTInput& input = psbtx.inputs[i];
    1350           0 :         UniValue in(UniValue::VOBJ);
    1351             :         // UTXOs
    1352           0 :         bool have_a_utxo = false;
    1353           0 :         CTxOut txout;
    1354           0 :         if (input.non_witness_utxo) {
    1355           0 :             txout = input.non_witness_utxo->vout[psbtx.tx->vin[i].prevout.n];
    1356             : 
    1357           0 :             UniValue non_wit(UniValue::VOBJ);
    1358           0 :             TxToUniv(*input.non_witness_utxo, /*block_hash=*/uint256(), /*entry=*/non_wit, /*include_hex=*/false);
    1359           0 :             in.pushKV("non_witness_utxo", non_wit);
    1360             : 
    1361           0 :             have_a_utxo = true;
    1362           0 :         }
    1363           0 :         if (have_a_utxo) {
    1364           0 :             if (MoneyRange(txout.nValue) && MoneyRange(total_in + txout.nValue)) {
    1365           0 :                 total_in += txout.nValue;
    1366           0 :             } else {
    1367             :                 // Hack to just not show fee later
    1368           0 :                 have_all_utxos = false;
    1369             :             }
    1370           0 :         } else {
    1371           0 :             have_all_utxos = false;
    1372             :         }
    1373             : 
    1374             :         // Partial sigs
    1375           0 :         if (!input.partial_sigs.empty()) {
    1376           0 :             UniValue partial_sigs(UniValue::VOBJ);
    1377           0 :             for (const auto& sig : input.partial_sigs) {
    1378           0 :                 partial_sigs.pushKV(HexStr(sig.second.first), HexStr(sig.second.second));
    1379             :             }
    1380           0 :             in.pushKV("partial_signatures", partial_sigs);
    1381           0 :         }
    1382             : 
    1383             :         // Sighash
    1384           0 :         if (input.sighash_type != std::nullopt) {
    1385           0 :             in.pushKV("sighash", SighashToStr((unsigned char)*input.sighash_type));
    1386           0 :         }
    1387             : 
    1388             :         // Redeem script
    1389           0 :         if (!input.redeem_script.empty()) {
    1390           0 :             UniValue r(UniValue::VOBJ);
    1391           0 :             ScriptToUniv(input.redeem_script, /*out=*/r);
    1392           0 :             in.pushKV("redeem_script", r);
    1393           0 :         }
    1394             : 
    1395             :         // keypaths
    1396           0 :         if (!input.hd_keypaths.empty()) {
    1397           0 :             UniValue keypaths(UniValue::VARR);
    1398           0 :             for (auto entry : input.hd_keypaths) {
    1399           0 :                 UniValue keypath(UniValue::VOBJ);
    1400           0 :                 keypath.pushKV("pubkey", HexStr(entry.first));
    1401             : 
    1402           0 :                 keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
    1403           0 :                 keypath.pushKV("path", WriteHDKeypath(entry.second.path));
    1404           0 :                 keypaths.push_back(keypath);
    1405           0 :             }
    1406           0 :             in.pushKV("bip32_derivs", keypaths);
    1407           0 :         }
    1408             : 
    1409             :         // Final scriptSig
    1410           0 :         if (!input.final_script_sig.empty()) {
    1411           0 :             UniValue scriptsig(UniValue::VOBJ);
    1412           0 :             scriptsig.pushKV("asm", ScriptToAsmStr(input.final_script_sig, true));
    1413           0 :             scriptsig.pushKV("hex", HexStr(input.final_script_sig));
    1414           0 :             in.pushKV("final_scriptSig", scriptsig);
    1415           0 :         }
    1416             : 
    1417             :         // Ripemd160 hash preimages
    1418           0 :         if (!input.ripemd160_preimages.empty()) {
    1419           0 :             UniValue ripemd160_preimages(UniValue::VOBJ);
    1420           0 :             for (const auto& [hash, preimage] : input.ripemd160_preimages) {
    1421           0 :                 ripemd160_preimages.pushKV(HexStr(hash), HexStr(preimage));
    1422             :             }
    1423           0 :             in.pushKV("ripemd160_preimages", ripemd160_preimages);
    1424           0 :         }
    1425             : 
    1426             :         // Sha256 hash preimages
    1427           0 :         if (!input.sha256_preimages.empty()) {
    1428           0 :             UniValue sha256_preimages(UniValue::VOBJ);
    1429           0 :             for (const auto& [hash, preimage] : input.sha256_preimages) {
    1430           0 :                 sha256_preimages.pushKV(HexStr(hash), HexStr(preimage));
    1431             :             }
    1432           0 :             in.pushKV("sha256_preimages", sha256_preimages);
    1433           0 :         }
    1434             : 
    1435             :         // Hash160 hash preimages
    1436           0 :         if (!input.hash160_preimages.empty()) {
    1437           0 :             UniValue hash160_preimages(UniValue::VOBJ);
    1438           0 :             for (const auto& [hash, preimage] : input.hash160_preimages) {
    1439           0 :                 hash160_preimages.pushKV(HexStr(hash), HexStr(preimage));
    1440             :             }
    1441           0 :             in.pushKV("hash160_preimages", hash160_preimages);
    1442           0 :         }
    1443             : 
    1444             :         // Hash256 hash preimages
    1445           0 :         if (!input.hash256_preimages.empty()) {
    1446           0 :             UniValue hash256_preimages(UniValue::VOBJ);
    1447           0 :             for (const auto& [hash, preimage] : input.hash256_preimages) {
    1448           0 :                 hash256_preimages.pushKV(HexStr(hash), HexStr(preimage));
    1449             :             }
    1450           0 :             in.pushKV("hash256_preimages", hash256_preimages);
    1451           0 :         }
    1452             : 
    1453             :         // Proprietary
    1454           0 :         if (!input.m_proprietary.empty()) {
    1455           0 :             UniValue proprietary(UniValue::VARR);
    1456           0 :             for (const auto& entry : input.m_proprietary) {
    1457           0 :                 UniValue this_prop(UniValue::VOBJ);
    1458           0 :                 this_prop.pushKV("identifier", HexStr(entry.identifier));
    1459           0 :                 this_prop.pushKV("subtype", entry.subtype);
    1460           0 :                 this_prop.pushKV("key", HexStr(entry.key));
    1461           0 :                 this_prop.pushKV("value", HexStr(entry.value));
    1462           0 :                 proprietary.push_back(this_prop);
    1463           0 :             }
    1464           0 :             in.pushKV("proprietary", proprietary);
    1465           0 :         }
    1466             : 
    1467             :         // Unknown data
    1468           0 :         if (input.unknown.size() > 0) {
    1469           0 :             UniValue unknowns(UniValue::VOBJ);
    1470           0 :             for (auto entry : input.unknown) {
    1471           0 :                 unknowns.pushKV(HexStr(entry.first), HexStr(entry.second));
    1472           0 :             }
    1473           0 :             in.pushKV("unknown", unknowns);
    1474           0 :         }
    1475             : 
    1476           0 :         inputs.push_back(in);
    1477           0 :     }
    1478           0 :     result.pushKV("inputs", inputs);
    1479             : 
    1480             :     // outputs
    1481           0 :     CAmount output_value = 0;
    1482           0 :     UniValue outputs(UniValue::VARR);
    1483           0 :     for (unsigned int i = 0; i < psbtx.outputs.size(); ++i) {
    1484           0 :         const PSBTOutput& output = psbtx.outputs[i];
    1485           0 :         UniValue out(UniValue::VOBJ);
    1486             :         // Redeem script
    1487           0 :         if (!output.redeem_script.empty()) {
    1488           0 :             UniValue r(UniValue::VOBJ);
    1489           0 :             ScriptToUniv(output.redeem_script, /*out=*/r);
    1490           0 :             out.pushKV("redeem_script", r);
    1491           0 :         }
    1492             : 
    1493             :         // keypaths
    1494           0 :         if (!output.hd_keypaths.empty()) {
    1495           0 :             UniValue keypaths(UniValue::VARR);
    1496           0 :             for (auto entry : output.hd_keypaths) {
    1497           0 :                 UniValue keypath(UniValue::VOBJ);
    1498           0 :                 keypath.pushKV("pubkey", HexStr(entry.first));
    1499           0 :                 keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
    1500           0 :                 keypath.pushKV("path", WriteHDKeypath(entry.second.path));
    1501           0 :                 keypaths.push_back(keypath);
    1502           0 :             }
    1503           0 :             out.pushKV("bip32_derivs", keypaths);
    1504           0 :         }
    1505             : 
    1506             :         // Proprietary
    1507           0 :         if (!output.m_proprietary.empty()) {
    1508           0 :             UniValue proprietary(UniValue::VARR);
    1509           0 :             for (const auto& entry : output.m_proprietary) {
    1510           0 :                 UniValue this_prop(UniValue::VOBJ);
    1511           0 :                 this_prop.pushKV("identifier", HexStr(entry.identifier));
    1512           0 :                 this_prop.pushKV("subtype", entry.subtype);
    1513           0 :                 this_prop.pushKV("key", HexStr(entry.key));
    1514           0 :                 this_prop.pushKV("value", HexStr(entry.value));
    1515           0 :                 proprietary.push_back(this_prop);
    1516           0 :             }
    1517           0 :             out.pushKV("proprietary", proprietary);
    1518           0 :         }
    1519             : 
    1520             :         // Unknown data
    1521           0 :         if (output.unknown.size() > 0) {
    1522           0 :             UniValue unknowns(UniValue::VOBJ);
    1523           0 :             for (auto entry : output.unknown) {
    1524           0 :                 unknowns.pushKV(HexStr(entry.first), HexStr(entry.second));
    1525           0 :             }
    1526           0 :             out.pushKV("unknown", unknowns);
    1527           0 :         }
    1528             : 
    1529           0 :         outputs.push_back(out);
    1530             : 
    1531             :         // Fee calculation
    1532           0 :         if (MoneyRange(psbtx.tx->vout[i].nValue) && MoneyRange(output_value + psbtx.tx->vout[i].nValue)) {
    1533           0 :             output_value += psbtx.tx->vout[i].nValue;
    1534           0 :         } else {
    1535             :             // Hack to just not show fee later
    1536           0 :             have_all_utxos = false;
    1537             :         }
    1538           0 :     }
    1539           0 :     result.pushKV("outputs", outputs);
    1540           0 :     if (have_all_utxos) {
    1541           0 :         result.pushKV("fee", ValueFromAmount(total_in - output_value));
    1542           0 :     }
    1543             : 
    1544           0 :     return result;
    1545           0 : },
    1546             :     };
    1547           0 : }
    1548             : 
    1549          92 : static RPCHelpMan combinepsbt()
    1550             : {
    1551         184 :     return RPCHelpMan{"combinepsbt",
    1552          92 :         "\nCombine multiple partially signed blockchain transactions into one transaction.\n"
    1553             :         "Implements the Combiner role.\n",
    1554         184 :         {
    1555         184 :             {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions",
    1556         184 :                 {
    1557          92 :                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A base64 string of a PSBT"},
    1558             :                 },
    1559             :                 },
    1560             :         },
    1561          92 :         RPCResult{
    1562          92 :             RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"
    1563             :         },
    1564          92 :         RPCExamples{
    1565          92 :             HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')")
    1566             :         },
    1567          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1568             : {
    1569           0 :     RPCTypeCheck(request.params, {UniValue::VARR}, true);
    1570             : 
    1571             :     // Unserialize the transactions
    1572           0 :     std::vector<PartiallySignedTransaction> psbtxs;
    1573           0 :     UniValue txs = request.params[0].get_array();
    1574           0 :     if (txs.empty()) {
    1575           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txs' cannot be empty");
    1576             :     }
    1577           0 :     for (unsigned int i = 0; i < txs.size(); ++i) {
    1578           0 :         PartiallySignedTransaction psbtx;
    1579           0 :         std::string error;
    1580           0 :         if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) {
    1581           0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1582             :         }
    1583           0 :         psbtxs.push_back(psbtx);
    1584           0 :     }
    1585             : 
    1586           0 :     PartiallySignedTransaction merged_psbt;
    1587           0 :     const TransactionError error = CombinePSBTs(merged_psbt, psbtxs);
    1588           0 :     if (error != TransactionError::OK) {
    1589           0 :         throw JSONRPCTransactionError(error);
    1590             :     }
    1591             : 
    1592           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1593           0 :     ssTx << merged_psbt;
    1594           0 :     return EncodeBase64(ssTx);
    1595           0 : },
    1596             :     };
    1597           0 : }
    1598             : 
    1599          92 : static RPCHelpMan finalizepsbt()
    1600             : {
    1601         184 :     return RPCHelpMan{"finalizepsbt",
    1602          92 :                 "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
    1603             :                 "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
    1604             :                 "created which has the final_scriptSig field filled for inputs that are complete.\n"
    1605             :                 "Implements the Finalizer and Extractor roles.\n",
    1606         276 :                 {
    1607          92 :                     {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
    1608          92 :                     {"extract", RPCArg::Type::BOOL, RPCArg::Default{true}, "If true and the transaction is complete,\n"
    1609             :             "                             extract and return the complete transaction in normal network serialization instead of the PSBT."},
    1610             :                 },
    1611          92 :                 RPCResult{
    1612          92 :                     RPCResult::Type::OBJ, "", "",
    1613         368 :                     {
    1614          92 :                         {RPCResult::Type::STR, "psbt", /*optional=*/true, "The base64-encoded partially signed transaction if not extracted"},
    1615          92 :                         {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The hex-encoded network transaction if extracted"},
    1616          92 :                         {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
    1617             :                     }
    1618             :                 },
    1619          92 :                 RPCExamples{
    1620          92 :                     HelpExampleCli("finalizepsbt", "\"psbt\"")
    1621             :                 },
    1622          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1623             : {
    1624           0 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true);
    1625             : 
    1626             :     // Unserialize the transactions
    1627           0 :     PartiallySignedTransaction psbtx;
    1628           0 :     std::string error;
    1629           0 :     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
    1630           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1631             :     }
    1632             : 
    1633           0 :     bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());
    1634             : 
    1635           0 :     CMutableTransaction mtx;
    1636           0 :     bool complete = FinalizeAndExtractPSBT(psbtx, mtx);
    1637             : 
    1638           0 :     UniValue result(UniValue::VOBJ);
    1639           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1640           0 :     std::string result_str;
    1641             : 
    1642           0 :     if (complete && extract) {
    1643           0 :         ssTx << mtx;
    1644           0 :         result_str = HexStr(ssTx);
    1645           0 :         result.pushKV("hex", result_str);
    1646           0 :     } else {
    1647           0 :         ssTx << psbtx;
    1648           0 :         result_str = EncodeBase64(ssTx.str());
    1649           0 :         result.pushKV("psbt", result_str);
    1650             :     }
    1651           0 :     result.pushKV("complete", complete);
    1652             : 
    1653           0 :     return result;
    1654           0 : },
    1655             :     };
    1656           0 : }
    1657             : 
    1658          92 : static RPCHelpMan createpsbt()
    1659             : {
    1660         184 :     return RPCHelpMan{"createpsbt",
    1661          92 :                 "\nCreates a transaction in the Partially Signed Transaction format.\n"
    1662             :                 "Implements the Creator role.\n",
    1663          92 :                 CreateTxDoc(),
    1664          92 :                 RPCResult{
    1665          92 :                     RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"
    1666             :                 },
    1667          92 :                 RPCExamples{
    1668          92 :                     HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
    1669             :                 },
    1670          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1671             : {
    1672             : 
    1673           0 :     RPCTypeCheck(request.params, {
    1674           0 :         UniValue::VARR,
    1675           0 :         UniValueType(), // ARR or OBJ, checked later
    1676           0 :         UniValue::VNUM,
    1677             :         }, true
    1678             :     );
    1679             : 
    1680           0 :     CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2]);
    1681             : 
    1682             :     // Make a blank psbt
    1683           0 :     PartiallySignedTransaction psbtx;
    1684           0 :     psbtx.tx = rawTx;
    1685           0 :     for (unsigned int i = 0; i < rawTx.vin.size(); ++i) {
    1686           0 :         psbtx.inputs.emplace_back();
    1687           0 :     }
    1688           0 :     for (unsigned int i = 0; i < rawTx.vout.size(); ++i) {
    1689           0 :         psbtx.outputs.emplace_back();
    1690           0 :     }
    1691             : 
    1692             :     // Serialize the PSBT
    1693           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1694           0 :     ssTx << psbtx;
    1695             : 
    1696           0 :     return EncodeBase64(ssTx);
    1697           0 : },
    1698             :     };
    1699           0 : }
    1700             : 
    1701          92 : static RPCHelpMan converttopsbt()
    1702             : {
    1703         184 :     return RPCHelpMan{"converttopsbt",
    1704          92 :                 "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n"
    1705             :                 "createpsbt and walletcreatefundedpsbt should be used for new applications.\n",
    1706         276 :                 {
    1707          92 :                     {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"},
    1708          92 :                     {"permitsigdata", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, any signatures in the input will be discarded and conversion\n"
    1709             :                             "                              will continue. If false, RPC will fail if any signatures are present."},
    1710             :                 },
    1711          92 :                 RPCResult{
    1712          92 :                     RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"
    1713             :                 },
    1714          92 :                 RPCExamples{
    1715             :                             "\nCreate a transaction\n"
    1716          92 :                             + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") +
    1717             :                             "\nConvert the transaction to a PSBT\n"
    1718          92 :                             + HelpExampleCli("converttopsbt", "\"rawtransaction\"")
    1719             :                 },
    1720          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1721             : {
    1722           0 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true);
    1723             : 
    1724             :     // parse hex string from parameter
    1725           0 :     CMutableTransaction tx;
    1726           0 :     bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool();
    1727           0 :     if (!DecodeHexTx(tx, request.params[0].get_str())) {
    1728           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
    1729             :     }
    1730             : 
    1731             :     // Remove all scriptSigs from inputs
    1732           0 :     for (CTxIn& input : tx.vin) {
    1733           0 :         if (!input.scriptSig.empty() && !permitsigdata) {
    1734           0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs");
    1735             :         }
    1736           0 :         input.scriptSig.clear();
    1737             :     }
    1738             : 
    1739             :     // Make a blank psbt
    1740           0 :     PartiallySignedTransaction psbtx;
    1741           0 :     psbtx.tx = tx;
    1742           0 :     for (unsigned int i = 0; i < tx.vin.size(); ++i) {
    1743           0 :         psbtx.inputs.emplace_back();
    1744           0 :     }
    1745           0 :     for (unsigned int i = 0; i < tx.vout.size(); ++i) {
    1746           0 :         psbtx.outputs.emplace_back();
    1747           0 :     }
    1748             : 
    1749             :     // Serialize the PSBT
    1750           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1751           0 :     ssTx << psbtx;
    1752             : 
    1753           0 :     return EncodeBase64(ssTx);
    1754           0 : },
    1755             :     };
    1756           0 : }
    1757             : 
    1758          92 : static RPCHelpMan utxoupdatepsbt()
    1759             : {
    1760         184 :     return RPCHelpMan{"utxoupdatepsbt",
    1761          92 :             "\nUpdates a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n",
    1762         276 :             {
    1763          92 :                 {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
    1764         276 :                 {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "An array of either strings or objects", {
    1765          92 :                     {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
    1766         276 :                     {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", {
    1767          92 :                          {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
    1768          92 :                          {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"},
    1769             :                     }},
    1770             :                 }},
    1771             :             },
    1772          92 :             RPCResult {
    1773          92 :                     RPCResult::Type::STR, "", "The base64-encoded partially signed transaction with inputs updated"
    1774             :             },
    1775          92 :             RPCExamples {
    1776          92 :                 HelpExampleCli("utxoupdatepsbt", "\"psbt\"")
    1777             :             },
    1778          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1779             : {
    1780           0 :     RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true);
    1781             : 
    1782             : 
    1783             :     // Parse descriptors, if any.
    1784           0 :     FlatSigningProvider provider;
    1785           0 :     if (!request.params[1].isNull()) {
    1786           0 :         auto descs = request.params[1].get_array();
    1787           0 :         for (size_t i = 0; i < descs.size(); ++i) {
    1788           0 :             EvalDescriptorStringOrObject(descs[i], provider);
    1789           0 :         }
    1790           0 :     }
    1791             : 
    1792             :     // We don't actually need private keys further on; hide them as a precaution.
    1793           0 :     const PartiallySignedTransaction& psbtx = ProcessPSBT(
    1794           0 :         request.params[0].get_str(),
    1795           0 :         request.context,
    1796           0 :         HidingSigningProvider(&provider, /*hide_secret=*/true, /*hide_origin=*/false));
    1797             : 
    1798           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1799           0 :     ssTx << psbtx;
    1800           0 :     return EncodeBase64(ssTx);
    1801           0 : },
    1802             :     };
    1803           0 : }
    1804             : 
    1805          92 : static RPCHelpMan joinpsbts()
    1806             : {
    1807         184 :     return RPCHelpMan{"joinpsbts",
    1808          92 :             "\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n"
    1809             :             "No input in any of the PSBTs can be in more than one of the PSBTs.\n",
    1810         184 :             {
    1811         184 :                 {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions",
    1812         184 :                     {
    1813          92 :                         {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
    1814             :                     }}
    1815             :             },
    1816          92 :             RPCResult {
    1817          92 :                     RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"
    1818             :             },
    1819          92 :             RPCExamples {
    1820          92 :                 HelpExampleCli("joinpsbts", "\"psbt\"")
    1821             :             },
    1822          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1823             : {
    1824           0 :     RPCTypeCheck(request.params, {UniValue::VARR}, true);
    1825             : 
    1826             :     // Unserialize the transactions
    1827           0 :     std::vector<PartiallySignedTransaction> psbtxs;
    1828           0 :     UniValue txs = request.params[0].get_array();
    1829             : 
    1830           0 :     if (txs.size() <= 1) {
    1831           0 :         throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs.");
    1832             :     }
    1833             : 
    1834           0 :     uint16_t best_version = 1;
    1835           0 :     uint32_t best_locktime = 0xffffffff;
    1836           0 :     for (unsigned int i = 0; i < txs.size(); ++i) {
    1837           0 :         PartiallySignedTransaction psbtx;
    1838           0 :         std::string error;
    1839           0 :         if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) {
    1840           0 :             throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1841             :         }
    1842           0 :         psbtxs.push_back(psbtx);
    1843             :         // Choose the highest version number
    1844           0 :         if (static_cast<uint16_t>(psbtx.tx->nVersion) > best_version) {
    1845           0 :             best_version = static_cast<uint16_t>(psbtx.tx->nVersion);
    1846           0 :         }
    1847             :         // Choose the lowest lock time
    1848           0 :         if (psbtx.tx->nLockTime < best_locktime) {
    1849           0 :             best_locktime = psbtx.tx->nLockTime;
    1850           0 :         }
    1851           0 :     }
    1852             : 
    1853             :     // Create a blank psbt where everything will be added
    1854           0 :     PartiallySignedTransaction merged_psbt;
    1855           0 :     merged_psbt.tx = CMutableTransaction();
    1856           0 :     merged_psbt.tx->nVersion = static_cast<int16_t>(best_version);
    1857           0 :     merged_psbt.tx->nLockTime = best_locktime;
    1858             : 
    1859             :     // Merge
    1860           0 :     for (auto& psbt : psbtxs) {
    1861           0 :         for (unsigned int i = 0; i < psbt.tx->vin.size(); ++i) {
    1862           0 :             if (!merged_psbt.AddInput(psbt.tx->vin[i], psbt.inputs[i])) {
    1863           0 :                 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input %s:%d exists in multiple PSBTs", psbt.tx->vin[i].prevout.hash.ToString(), psbt.tx->vin[i].prevout.n));
    1864             :             }
    1865           0 :         }
    1866           0 :         for (unsigned int i = 0; i < psbt.tx->vout.size(); ++i) {
    1867           0 :             merged_psbt.AddOutput(psbt.tx->vout[i], psbt.outputs[i]);
    1868           0 :         }
    1869           0 :         for (auto& xpub_pair : psbt.m_xpubs) {
    1870           0 :             if (merged_psbt.m_xpubs.count(xpub_pair.first) == 0) {
    1871           0 :                 merged_psbt.m_xpubs[xpub_pair.first] = xpub_pair.second;
    1872           0 :             } else {
    1873           0 :                 merged_psbt.m_xpubs[xpub_pair.first].insert(xpub_pair.second.begin(), xpub_pair.second.end());
    1874             :             }
    1875             :         }
    1876           0 :         merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end());
    1877             :     }
    1878             : 
    1879           0 :     CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
    1880           0 :     ssTx << merged_psbt;
    1881           0 :     return EncodeBase64(ssTx);
    1882           0 : },
    1883             :     };
    1884           0 : }
    1885             : 
    1886          92 : static RPCHelpMan analyzepsbt()
    1887             : {
    1888         184 :     return RPCHelpMan{"analyzepsbt",
    1889          92 :             "\nAnalyzes and provides information about the current status of a PSBT and its inputs\n",
    1890         184 :             {
    1891          92 :                 {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
    1892             :             },
    1893          92 :             RPCResult {
    1894          92 :                 RPCResult::Type::OBJ, "", "",
    1895         644 :                 {
    1896         184 :                     {RPCResult::Type::ARR, "inputs", /*optional=*/true, "",
    1897         184 :                     {
    1898         184 :                         {RPCResult::Type::OBJ, "", "",
    1899         460 :                         {
    1900          92 :                             {RPCResult::Type::BOOL, "has_utxo", "Whether a UTXO is provided"},
    1901          92 :                             {RPCResult::Type::BOOL, "is_final", "Whether the input is finalized"},
    1902         184 :                             {RPCResult::Type::OBJ, "missing", /*optional=*/true, "Things that are missing that are required to complete this input",
    1903         368 :                             {
    1904         184 :                                 {RPCResult::Type::ARR, "pubkeys", /*optional=*/true, "",
    1905         184 :                                 {
    1906          92 :                                     {RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing"},
    1907             :                                 }},
    1908         184 :                                 {RPCResult::Type::ARR, "signatures", /*optional=*/true, "",
    1909         184 :                                 {
    1910          92 :                                     {RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose signature is missing"},
    1911             :                                 }},
    1912          92 :                                 {RPCResult::Type::STR_HEX, "redeemscript", /*optional=*/true, "Hash160 of the redeemScript that is missing"},
    1913             :                             }},
    1914          92 :                             {RPCResult::Type::STR, "next", /*optional=*/true, "Role of the next person that this input needs to go to"},
    1915             :                         }},
    1916             :                     }},
    1917          92 :                     {RPCResult::Type::NUM, "estimated_vsize", /*optional=*/true, "Estimated vsize of the final signed transaction"},
    1918          92 :                     {RPCResult::Type::STR_AMOUNT, "estimated_feerate", /*optional=*/true, "Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + "/kB. Shown only if all UTXO slots in the PSBT have been filled"},
    1919          92 :                     {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled"},
    1920          92 :                     {RPCResult::Type::STR, "next", "Role of the next person that this psbt needs to go to"},
    1921          92 :                     {RPCResult::Type::STR, "error", /*optional=*/true, "Error message if there is one"},
    1922             :                 }
    1923             :             },
    1924          92 :             RPCExamples {
    1925          92 :                 HelpExampleCli("analyzepsbt", "\"psbt\"")
    1926             :             },
    1927          92 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
    1928             : {
    1929           0 :     RPCTypeCheck(request.params, {UniValue::VSTR});
    1930             : 
    1931             :     // Unserialize the transaction
    1932           0 :     PartiallySignedTransaction psbtx;
    1933           0 :     std::string error;
    1934           0 :     if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
    1935           0 :         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
    1936             :     }
    1937             : 
    1938           0 :     PSBTAnalysis psbta = AnalyzePSBT(psbtx);
    1939             : 
    1940           0 :     UniValue result(UniValue::VOBJ);
    1941           0 :     UniValue inputs_result(UniValue::VARR);
    1942           0 :     for (const auto& input : psbta.inputs) {
    1943           0 :         UniValue input_univ(UniValue::VOBJ);
    1944           0 :         UniValue missing(UniValue::VOBJ);
    1945             : 
    1946           0 :         input_univ.pushKV("has_utxo", input.has_utxo);
    1947           0 :         input_univ.pushKV("is_final", input.is_final);
    1948           0 :         input_univ.pushKV("next", PSBTRoleName(input.next));
    1949             : 
    1950           0 :         if (!input.missing_pubkeys.empty()) {
    1951           0 :             UniValue missing_pubkeys_univ(UniValue::VARR);
    1952           0 :             for (const CKeyID& pubkey : input.missing_pubkeys) {
    1953           0 :                 missing_pubkeys_univ.push_back(HexStr(pubkey));
    1954             :             }
    1955           0 :             missing.pushKV("pubkeys", missing_pubkeys_univ);
    1956           0 :         }
    1957           0 :         if (!input.missing_redeem_script.IsNull()) {
    1958           0 :             missing.pushKV("redeemscript", HexStr(input.missing_redeem_script));
    1959           0 :         }
    1960           0 :         if (!input.missing_sigs.empty()) {
    1961           0 :             UniValue missing_sigs_univ(UniValue::VARR);
    1962           0 :             for (const CKeyID& pubkey : input.missing_sigs) {
    1963           0 :                 missing_sigs_univ.push_back(HexStr(pubkey));
    1964             :             }
    1965           0 :             missing.pushKV("signatures", missing_sigs_univ);
    1966           0 :         }
    1967           0 :         if (!missing.getKeys().empty()) {
    1968           0 :             input_univ.pushKV("missing", missing);
    1969           0 :         }
    1970           0 :         inputs_result.push_back(input_univ);
    1971           0 :     }
    1972           0 :     if (!inputs_result.empty()) result.pushKV("inputs", inputs_result);
    1973             : 
    1974           0 :     if (psbta.estimated_vsize) {
    1975           0 :         result.pushKV("estimated_vsize", (int)*psbta.estimated_vsize);
    1976           0 :     }
    1977           0 :     if (psbta.estimated_feerate) {
    1978           0 :         result.pushKV("estimated_feerate", ValueFromAmount(psbta.estimated_feerate->GetFeePerK()));
    1979           0 :     }
    1980           0 :     if (psbta.fee) {
    1981           0 :         result.pushKV("fee", ValueFromAmount(*psbta.fee));
    1982           0 :     }
    1983           0 :     result.pushKV("next", PSBTRoleName(psbta.next));
    1984           0 :     if (!psbta.error.empty()) {
    1985           0 :         result.pushKV("error", psbta.error);
    1986           0 :     }
    1987             : 
    1988           0 :     return result;
    1989           0 : },
    1990             :     };
    1991           0 : }
    1992             : 
    1993         178 : void RegisterRawTransactionRPCCommands(CRPCTable& t)
    1994             : {
    1995        1006 :     static const CRPCCommand commands[]{
    1996          46 :         {"rawtransactions", &getassetunlockstatuses},
    1997          46 :         {"rawtransactions", &getrawtransaction},
    1998          46 :         {"rawtransactions", &getrawtransactionmulti},
    1999          46 :         {"rawtransactions", &getislocks},
    2000          46 :         {"rawtransactions", &gettxchainlocks},
    2001          46 :         {"rawtransactions", &createrawtransaction},
    2002          46 :         {"rawtransactions", &decoderawtransaction},
    2003          46 :         {"rawtransactions", &decodescript},
    2004          46 :         {"rawtransactions", &combinerawtransaction},
    2005          46 :         {"rawtransactions", &signrawtransactionwithkey},
    2006          46 :         {"rawtransactions", &decodepsbt},
    2007          46 :         {"rawtransactions", &combinepsbt},
    2008          46 :         {"rawtransactions", &finalizepsbt},
    2009          46 :         {"rawtransactions", &createpsbt},
    2010          46 :         {"rawtransactions", &converttopsbt},
    2011          46 :         {"rawtransactions", &utxoupdatepsbt},
    2012          46 :         {"rawtransactions", &joinpsbts},
    2013          46 :         {"rawtransactions", &analyzepsbt},
    2014             :     };
    2015        3382 :     for (const auto& c : commands) {
    2016        3204 :         t.appendCommand(c.name, &c);
    2017             :     }
    2018         178 : }

Generated by: LCOV version 1.16