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 : }
|