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