/root/bitcoin/src/rpc/rawtransaction.cpp
Line | Count | Source |
1 | | // Copyright (c) 2010 Satoshi Nakamoto |
2 | | // Copyright (c) 2009-present The Bitcoin Core developers |
3 | | // Distributed under the MIT software license, see the accompanying |
4 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | | |
6 | | #include <base58.h> |
7 | | #include <chain.h> |
8 | | #include <coins.h> |
9 | | #include <consensus/amount.h> |
10 | | #include <consensus/validation.h> |
11 | | #include <core_io.h> |
12 | | #include <index/txindex.h> |
13 | | #include <key_io.h> |
14 | | #include <node/blockstorage.h> |
15 | | #include <node/coin.h> |
16 | | #include <node/context.h> |
17 | | #include <node/psbt.h> |
18 | | #include <node/transaction.h> |
19 | | #include <node/types.h> |
20 | | #include <policy/packages.h> |
21 | | #include <policy/policy.h> |
22 | | #include <policy/rbf.h> |
23 | | #include <primitives/transaction.h> |
24 | | #include <psbt.h> |
25 | | #include <random.h> |
26 | | #include <rpc/blockchain.h> |
27 | | #include <rpc/rawtransaction_util.h> |
28 | | #include <rpc/server.h> |
29 | | #include <rpc/server_util.h> |
30 | | #include <rpc/util.h> |
31 | | #include <script/script.h> |
32 | | #include <script/sign.h> |
33 | | #include <script/signingprovider.h> |
34 | | #include <script/solver.h> |
35 | | #include <uint256.h> |
36 | | #include <undo.h> |
37 | | #include <util/bip32.h> |
38 | | #include <util/check.h> |
39 | | #include <util/strencodings.h> |
40 | | #include <util/string.h> |
41 | | #include <util/vector.h> |
42 | | #include <validation.h> |
43 | | #include <validationinterface.h> |
44 | | |
45 | | #include <cstdint> |
46 | | |
47 | | #include <univalue.h> |
48 | | |
49 | | using node::AnalyzePSBT; |
50 | | using node::FindCoins; |
51 | | using node::GetTransaction; |
52 | | using node::NodeContext; |
53 | | using node::PSBTAnalysis; |
54 | | |
55 | | static constexpr decltype(CTransaction::version) DEFAULT_RAWTX_VERSION{CTransaction::CURRENT_VERSION}; |
56 | | |
57 | | static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, |
58 | | Chainstate& active_chainstate, const CTxUndo* txundo = nullptr, |
59 | | TxVerbosity verbosity = TxVerbosity::SHOW_DETAILS) |
60 | 0 | { |
61 | 0 | CHECK_NONFATAL(verbosity >= TxVerbosity::SHOW_DETAILS); |
62 | | // Call into TxToUniv() in bitcoin-common to decode the transaction hex. |
63 | | // |
64 | | // Blockchain contextual information (confirmations and blocktime) is not |
65 | | // available to code in bitcoin-common, so we query them here and push the |
66 | | // data into the returned UniValue. |
67 | 0 | TxToUniv(tx, /*block_hash=*/uint256(), entry, /*include_hex=*/true, txundo, verbosity); |
68 | |
|
69 | 0 | if (!hashBlock.IsNull()) { Branch (69:9): [True: 0, False: 0]
|
70 | 0 | LOCK(cs_main); |
71 | |
|
72 | 0 | entry.pushKV("blockhash", hashBlock.GetHex()); |
73 | 0 | const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(hashBlock); |
74 | 0 | if (pindex) { Branch (74:13): [True: 0, False: 0]
|
75 | 0 | if (active_chainstate.m_chain.Contains(*pindex)) { Branch (75:17): [True: 0, False: 0]
|
76 | 0 | entry.pushKV("confirmations", 1 + active_chainstate.m_chain.Height() - pindex->nHeight); |
77 | 0 | entry.pushKV("time", pindex->GetBlockTime()); |
78 | 0 | entry.pushKV("blocktime", pindex->GetBlockTime()); |
79 | 0 | } |
80 | 0 | else |
81 | 0 | entry.pushKV("confirmations", 0); |
82 | 0 | } |
83 | 0 | } |
84 | 0 | } |
85 | | |
86 | | static std::vector<RPCArg> CreateTxDoc() |
87 | 279 | { |
88 | 279 | return { |
89 | 279 | {"inputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The inputs", |
90 | 279 | { |
91 | 279 | {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", |
92 | 279 | { |
93 | 279 | {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, |
94 | 279 | {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, |
95 | 279 | {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'replaceable' and 'locktime' arguments"}, "The sequence number"}, |
96 | 279 | }, |
97 | 279 | }, |
98 | 279 | }, |
99 | 279 | }, |
100 | 279 | {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs specified as key-value pairs.\n" |
101 | 279 | "Each key may only appear once, i.e. there can only be one 'data' output, and no address may be duplicated.\n" |
102 | 279 | "At least one output of either type must be specified.\n" |
103 | 279 | "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n" |
104 | 279 | " accepted as second parameter.", |
105 | 279 | { |
106 | 279 | {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "", |
107 | 279 | { |
108 | 279 | {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT}, |
109 | 279 | }, |
110 | 279 | }, |
111 | 279 | {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", |
112 | 279 | { |
113 | 279 | {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data that becomes a part of an OP_RETURN output"}, |
114 | 279 | }, |
115 | 279 | }, |
116 | 279 | }, |
117 | 279 | RPCArgOptions{.skip_type_check = true}}, |
118 | 279 | {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"}, |
119 | 279 | {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Marks this transaction as BIP125-replaceable.\n" |
120 | 279 | "Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."}, |
121 | 279 | {"version", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_RAWTX_VERSION}, "Transaction version"}, |
122 | 279 | }; |
123 | 279 | } |
124 | | |
125 | | // Update PSBT with information from the mempool, the UTXO set, the txindex, and the provided descriptors. |
126 | | // Optionally, sign the inputs that we can using information from the descriptors. |
127 | | PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std::any& context, const HidingSigningProvider& provider, std::optional<int> sighash_type, bool finalize) |
128 | 475 | { |
129 | | // Unserialize the transactions |
130 | 475 | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(psbt_string); |
131 | 475 | if (!psbt_res) { Branch (131:9): [True: 70, False: 405]
|
132 | 70 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
133 | 70 | } |
134 | 405 | PartiallySignedTransaction psbtx = *psbt_res; |
135 | | |
136 | 405 | if (g_txindex) g_txindex->BlockUntilSyncedToCurrentChain(); Branch (136:9): [True: 0, False: 405]
|
137 | 405 | const NodeContext& node = EnsureAnyNodeContext(context); |
138 | | |
139 | | // If we can't find the corresponding full transaction for all of our inputs, |
140 | | // this will be used to find just the utxos for the segwit inputs for which |
141 | | // the full transaction isn't found |
142 | 405 | std::map<COutPoint, Coin> coins; |
143 | | |
144 | | // Fetch previous transactions: |
145 | | // First, look in the txindex and the mempool |
146 | 405 | for (PSBTInput& psbt_input : psbtx.inputs) { Branch (146:32): [True: 345, False: 405]
|
147 | | // The `non_witness_utxo` is the whole previous transaction |
148 | 345 | if (psbt_input.non_witness_utxo) continue; Branch (148:13): [True: 0, False: 345]
|
149 | | |
150 | 345 | CTransactionRef tx; |
151 | | |
152 | | // Look in the txindex |
153 | 345 | if (g_txindex) { Branch (153:13): [True: 0, False: 345]
|
154 | 0 | if (auto result{g_txindex->FindTx(psbt_input.prev_txid)}) tx = result->tx; Branch (154:22): [True: 0, False: 0]
|
155 | 0 | } |
156 | | // If we still don't have it look in the mempool |
157 | 345 | if (!tx) { Branch (157:13): [True: 345, False: 0]
|
158 | 345 | tx = node.mempool->get(psbt_input.prev_txid); |
159 | 345 | } |
160 | 345 | if (tx) { Branch (160:13): [True: 0, False: 345]
|
161 | 0 | psbt_input.non_witness_utxo = tx; |
162 | 345 | } else { |
163 | 345 | coins[psbt_input.GetOutPoint()]; // Create empty map entry keyed by prevout |
164 | 345 | } |
165 | 345 | } |
166 | | |
167 | | // If we still haven't found all of the inputs, look for the missing ones in the utxo set |
168 | 405 | if (!coins.empty()) { Branch (168:9): [True: 341, False: 64]
|
169 | 341 | FindCoins(node, coins); |
170 | 345 | for (PSBTInput& input : psbtx.inputs) { Branch (170:31): [True: 345, False: 341]
|
171 | | // If there are still missing utxos, add them if they were found in the utxo set |
172 | 345 | if (!input.non_witness_utxo) { Branch (172:17): [True: 345, False: 0]
|
173 | 345 | const Coin& coin = coins.at(input.GetOutPoint()); |
174 | 345 | if (!coin.out.IsNull() && IsSegWitOutput(provider, coin.out.scriptPubKey)) { Branch (174:21): [True: 0, False: 345]
Branch (174:43): [True: 0, False: 0]
|
175 | 0 | input.witness_utxo = coin.out; |
176 | 0 | } |
177 | 345 | } |
178 | 345 | } |
179 | 341 | } |
180 | | |
181 | 405 | std::optional<PrecomputedTransactionData> txdata_res = PrecomputePSBTData(psbtx); |
182 | 405 | if (!txdata_res) { Branch (182:9): [True: 0, False: 405]
|
183 | 0 | throw JSONRPCPSBTError(common::PSBTError::INVALID_TX); |
184 | 0 | } |
185 | 405 | const PrecomputedTransactionData& txdata = *txdata_res; |
186 | | |
187 | 741 | for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) { Branch (187:30): [True: 345, False: 396]
|
188 | 345 | if (PSBTInputSigned(psbtx.inputs.at(i))) { Branch (188:13): [True: 1, False: 344]
|
189 | 1 | continue; |
190 | 1 | } |
191 | | |
192 | | // Update script/keypath information using descriptor data. |
193 | | // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures. |
194 | | // We only actually care about those if our signing provider doesn't hide private |
195 | | // information, as is the case with `descriptorprocesspsbt` |
196 | | // Only error for mismatching sighash types as it is critical that the sighash to sign with matches the PSBT's |
197 | 344 | const auto sign_result = SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, {.sighash_type = sighash_type, .finalize = finalize}, /*out_sigdata=*/nullptr); |
198 | 344 | if (!sign_result.has_value() && sign_result.error() == common::PSBTError::SIGHASH_MISMATCH) { Branch (198:13): [True: 343, False: 1]
Branch (198:41): [True: 9, False: 334]
|
199 | 9 | throw JSONRPCPSBTError(common::PSBTError::SIGHASH_MISMATCH); |
200 | 9 | } |
201 | 344 | } |
202 | | |
203 | | // Update script/keypath information using descriptor data. |
204 | 562 | for (unsigned int i = 0; i < psbtx.outputs.size(); ++i) { Branch (204:30): [True: 166, False: 396]
|
205 | 166 | UpdatePSBTOutput(provider, psbtx, i); |
206 | 166 | } |
207 | | |
208 | 396 | RemoveUnnecessaryTransactions(psbtx); |
209 | | |
210 | 396 | return psbtx; |
211 | 405 | } |
212 | | |
213 | | static RPCMethod getrawtransaction() |
214 | 28 | { |
215 | 28 | const std::vector<RPCResult> verbosity_1_block{ |
216 | 28 | {RPCResult::Type::BOOL, "in_active_chain", /*optional=*/true, "Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)"}, |
217 | 28 | {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "the block hash"}, |
218 | 28 | {RPCResult::Type::NUM, "vsize_adjusted", /*optional=*/true, "Sigop-adjusted virtual size in bytes, present for mempool transactions."}, |
219 | 28 | {RPCResult::Type::NUM, "confirmations", /*optional=*/true, "The confirmations"}, |
220 | 28 | {RPCResult::Type::NUM_TIME, "blocktime", /*optional=*/true, "The block time expressed in " + UNIX_EPOCH_TIME}, |
221 | 28 | {RPCResult::Type::NUM, "time", /*optional=*/true, "Same as \"blocktime\""}, |
222 | 28 | {RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded data for 'txid'"}, |
223 | 28 | }; |
224 | 28 | const auto v2_extras = Cat<std::vector<RPCResult>>( |
225 | 28 | std::vector<RPCResult>{{ |
226 | 28 | RPCResult::Type::NUM, "fee", /*optional=*/true, |
227 | 28 | "transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available" |
228 | 28 | }}, |
229 | 28 | TxDoc({.elision_mode = ElisionMode::Silent, |
230 | 28 | .prevout = true, |
231 | 28 | .prevout_optional = true, |
232 | 28 | .vin_inner_elision = "Same vin fields as verbosity = 1"})); |
233 | 28 | return RPCMethod{ |
234 | 28 | "getrawtransaction", |
235 | | |
236 | 28 | "By default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n" |
237 | 28 | "and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block.\n" |
238 | 28 | "If a blockhash argument is passed, it will return the transaction if\n" |
239 | 28 | "the specified block is available and the transaction is in that block.\n\n" |
240 | 28 | "Hint: Use gettransaction for wallet transactions.\n\n" |
241 | | |
242 | 28 | "If verbosity is 0 or omitted, returns the serialized transaction as a hex-encoded string.\n" |
243 | 28 | "If verbosity is 1, returns a JSON Object with information about the transaction.\n" |
244 | 28 | "If verbosity is 2, returns a JSON Object with information about the transaction, including fee and prevout information.", |
245 | 28 | { |
246 | 28 | {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, |
247 | 28 | {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for hex-encoded data, 1 for a JSON object, and 2 for JSON object with fee and prevout", |
248 | 28 | RPCArgOptions{.skip_type_check = true}}, |
249 | 28 | {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "The block in which to look for the transaction"}, |
250 | 28 | }, |
251 | 28 | { |
252 | 28 | RPCResult{"if verbosity is not set or set to 0", |
253 | 28 | RPCResult::Type::STR, "data", "The serialized transaction as a hex-encoded string for 'txid'" |
254 | 28 | }, |
255 | 28 | RPCResult{"if verbosity is set to 1", |
256 | 28 | RPCResult::Type::OBJ, "", "", |
257 | 28 | Cat<std::vector<RPCResult>>( |
258 | 28 | verbosity_1_block, |
259 | 28 | TxDoc({.txid_field_doc="The transaction id (same as provided)"})), |
260 | 28 | }, |
261 | 28 | RPCResult{"for verbosity = 2", RPCResult::Type::OBJ, "", "", |
262 | 28 | Cat(ElideGroup(verbosity_1_block, "Same output as verbosity = 1"), v2_extras)}, |
263 | 28 | }, |
264 | 28 | RPCExamples{ |
265 | 28 | HelpExampleCli("getrawtransaction", "\"mytxid\"") |
266 | 28 | + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") |
267 | 28 | + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") |
268 | 28 | + HelpExampleCli("getrawtransaction", "\"mytxid\" 0 \"myblockhash\"") |
269 | 28 | + HelpExampleCli("getrawtransaction", "\"mytxid\" 1 \"myblockhash\"") |
270 | 28 | + HelpExampleCli("getrawtransaction", "\"mytxid\" 2 \"myblockhash\"") |
271 | 28 | }, |
272 | 28 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
273 | 28 | { |
274 | 4 | const NodeContext& node = EnsureAnyNodeContext(request.context); |
275 | 4 | ChainstateManager& chainman = EnsureChainman(node); |
276 | | |
277 | 4 | auto txid{Txid::FromUint256(ParseHashV(request.params[0], "parameter 1"))}; |
278 | 4 | const CBlockIndex* blockindex = nullptr; |
279 | | |
280 | 4 | if (txid.ToUint256() == chainman.GetParams().GenesisBlock().hashMerkleRoot) { Branch (280:9): [True: 1, False: 3]
|
281 | | // Special exception for the genesis block coinbase transaction |
282 | 1 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved"); |
283 | 1 | } |
284 | | |
285 | 3 | int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/0, /*allow_bool=*/true)}; |
286 | | |
287 | 3 | if (!request.params[2].isNull()) { Branch (287:9): [True: 2, False: 1]
|
288 | 2 | LOCK(cs_main); |
289 | | |
290 | 2 | uint256 blockhash = ParseHashV(request.params[2], "parameter 3"); |
291 | 2 | blockindex = chainman.m_blockman.LookupBlockIndex(blockhash); |
292 | 2 | if (!blockindex) { Branch (292:13): [True: 1, False: 1]
|
293 | 1 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block hash not found"); |
294 | 1 | } |
295 | 2 | } |
296 | | |
297 | 2 | bool f_txindex_ready = false; |
298 | 2 | if (g_txindex && !blockindex) { Branch (298:9): [True: 0, False: 2]
Branch (298:22): [True: 0, False: 0]
|
299 | 0 | f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain(); |
300 | 0 | } |
301 | | |
302 | 2 | uint256 hash_block; |
303 | 2 | const CTransactionRef tx = GetTransaction(blockindex, node.mempool.get(), txid, chainman.m_blockman, hash_block); |
304 | 2 | if (!tx) { Branch (304:9): [True: 1, False: 1]
|
305 | 1 | std::string errmsg; |
306 | 1 | if (blockindex) { Branch (306:13): [True: 0, False: 1]
|
307 | 0 | const bool block_has_data = WITH_LOCK(::cs_main, return blockindex->nStatus & BLOCK_HAVE_DATA); |
308 | 0 | if (!block_has_data) { Branch (308:17): [True: 0, False: 0]
|
309 | 0 | throw JSONRPCError(RPC_MISC_ERROR, "Block not available"); |
310 | 0 | } |
311 | 0 | errmsg = "No such transaction found in the provided block"; |
312 | 1 | } else if (!g_txindex) { Branch (312:20): [True: 1, False: 0]
|
313 | 1 | errmsg = "No such mempool transaction. Use -txindex or provide a block hash to enable blockchain transaction queries"; |
314 | 1 | } else if (!f_txindex_ready) { Branch (314:20): [True: 0, False: 0]
|
315 | 0 | errmsg = "No such mempool transaction. Blockchain transactions are still in the process of being indexed"; |
316 | 0 | } else { |
317 | 0 | errmsg = "No such mempool or blockchain transaction"; |
318 | 0 | } |
319 | 1 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errmsg + ". Use gettransaction for wallet transactions."); |
320 | 1 | } |
321 | | |
322 | 1 | if (verbosity <= 0) { Branch (322:9): [True: 0, False: 1]
|
323 | 0 | return EncodeHexTx(*tx); |
324 | 0 | } |
325 | | |
326 | 1 | UniValue result(UniValue::VOBJ); |
327 | 1 | if (blockindex) { Branch (327:9): [True: 0, False: 1]
|
328 | 0 | LOCK(cs_main); |
329 | 0 | result.pushKV("in_active_chain", chainman.ActiveChain().Contains(*blockindex)); |
330 | 0 | } |
331 | | // If request is verbosity >= 1 but no blockhash was given, then look up the blockindex |
332 | 1 | if (request.params[2].isNull()) { Branch (332:9): [True: 0, False: 1]
|
333 | 0 | LOCK(cs_main); |
334 | 0 | blockindex = chainman.m_blockman.LookupBlockIndex(hash_block); // May be nullptr for mempool transactions |
335 | 0 | } |
336 | | |
337 | | // Add sigop-adjusted virtual size if the transaction exists in the mempool. |
338 | 1 | if (blockindex == nullptr && hash_block.IsNull() && node.mempool) { Branch (338:9): [True: 0, False: 1]
Branch (338:34): [True: 0, False: 0]
Branch (338:57): [True: 0, False: 0]
|
339 | 0 | auto info = node.mempool->info(tx->GetHash()); |
340 | 0 | if (info.tx) { Branch (340:13): [True: 0, False: 0]
|
341 | 0 | result.pushKV("vsize_adjusted", info.vsize); |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | 1 | if (verbosity == 1) { Branch (345:9): [True: 0, False: 1]
|
346 | 0 | TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); |
347 | 0 | return result; |
348 | 0 | } |
349 | | |
350 | 1 | CBlockUndo blockUndo; |
351 | 1 | CBlock block; |
352 | | |
353 | 1 | if (tx->IsCoinBase() || !blockindex || WITH_LOCK(::cs_main, return !(blockindex->nStatus & BLOCK_HAVE_MASK))) { Branch (353:9): [True: 1, False: 0]
Branch (353:9): [True: 0, False: 1]
Branch (353:29): [True: 0, False: 0]
|
354 | 0 | TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); |
355 | 0 | return result; |
356 | 0 | } |
357 | 1 | if (!chainman.m_blockman.ReadBlockUndo(blockUndo, *blockindex)) { Branch (357:9): [True: 0, False: 1]
|
358 | 0 | throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); |
359 | 0 | } |
360 | 1 | if (!chainman.m_blockman.ReadBlock(block, *blockindex)) { Branch (360:9): [True: 0, False: 1]
|
361 | 0 | throw JSONRPCError(RPC_INTERNAL_ERROR, "Block data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); |
362 | 0 | } |
363 | | |
364 | 1 | CTxUndo* undoTX {nullptr}; |
365 | 1 | auto it = std::find_if(block.vtx.begin(), block.vtx.end(), [tx](CTransactionRef t){ return *t == *tx; }); |
366 | 1 | if (it != block.vtx.end()) { Branch (366:9): [True: 0, False: 1]
|
367 | | // -1 as blockundo does not have coinbase tx |
368 | 0 | undoTX = &blockUndo.vtxundo.at(it - block.vtx.begin() - 1); |
369 | 0 | } |
370 | 1 | TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate(), undoTX, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); |
371 | 1 | return result; |
372 | 1 | }, |
373 | 28 | }; |
374 | 28 | } |
375 | | |
376 | | static RPCMethod createrawtransaction() |
377 | 44 | { |
378 | 44 | return RPCMethod{ |
379 | 44 | "createrawtransaction", |
380 | 44 | "Create a transaction spending the given inputs and creating new outputs.\n" |
381 | 44 | "Outputs can be addresses or data.\n" |
382 | 44 | "Returns hex-encoded raw transaction.\n" |
383 | 44 | "Note that the transaction's inputs are not signed, and\n" |
384 | 44 | "it is not stored in the wallet or transmitted to the network.\n", |
385 | 44 | CreateTxDoc(), |
386 | 44 | RPCResult{ |
387 | 44 | RPCResult::Type::STR_HEX, "transaction", "hex string of the transaction" |
388 | 44 | }, |
389 | 44 | RPCExamples{ |
390 | 44 | HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"") |
391 | 44 | + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") |
392 | 44 | + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"") |
393 | 44 | + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"") |
394 | 44 | }, |
395 | 44 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
396 | 44 | { |
397 | 23 | std::optional<bool> rbf; |
398 | 23 | if (!request.params[3].isNull()) { Branch (398:9): [True: 1, False: 22]
|
399 | 1 | rbf = request.params[3].get_bool(); |
400 | 1 | } |
401 | 23 | CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf, self.Arg<uint32_t>("version")); |
402 | | |
403 | 23 | return EncodeHexTx(CTransaction(rawTx)); |
404 | 23 | }, |
405 | 44 | }; |
406 | 44 | } |
407 | | |
408 | | static RPCMethod decoderawtransaction() |
409 | 433 | { |
410 | 433 | return RPCMethod{"decoderawtransaction", |
411 | 433 | "Return a JSON object representing the serialized, hex-encoded transaction.", |
412 | 433 | { |
413 | 433 | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"}, |
414 | 433 | {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" |
415 | 433 | "If iswitness is not present, heuristic tests will be used in decoding.\n" |
416 | 433 | "If true, only witness deserialization will be tried.\n" |
417 | 433 | "If false, only non-witness deserialization will be tried.\n" |
418 | 433 | "This boolean should reflect whether the transaction has inputs\n" |
419 | 433 | "(e.g. fully valid, or on-chain transactions), if known by the caller." |
420 | 433 | }, |
421 | 433 | }, |
422 | 433 | RPCResult{ |
423 | 433 | RPCResult::Type::OBJ, "", "", |
424 | 433 | TxDoc(), |
425 | 433 | }, |
426 | 433 | RPCExamples{ |
427 | 433 | HelpExampleCli("decoderawtransaction", "\"hexstring\"") |
428 | 433 | + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") |
429 | 433 | }, |
430 | 433 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
431 | 433 | { |
432 | 237 | CMutableTransaction mtx; |
433 | | |
434 | 237 | bool try_witness = request.params[1].isNull() ? true : request.params[1].get_bool(); Branch (434:24): [True: 227, False: 10]
|
435 | 237 | bool try_no_witness = request.params[1].isNull() ? true : !request.params[1].get_bool(); Branch (435:27): [True: 227, False: 10]
|
436 | | |
437 | 237 | if (!DecodeHexTx(mtx, request.params[0].get_str(), try_no_witness, try_witness)) { Branch (437:9): [True: 69, False: 168]
|
438 | 69 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
439 | 69 | } |
440 | | |
441 | 168 | UniValue result(UniValue::VOBJ); |
442 | 168 | TxToUniv(CTransaction(std::move(mtx)), /*block_hash=*/uint256(), /*entry=*/result, /*include_hex=*/false); |
443 | | |
444 | 168 | return result; |
445 | 237 | }, |
446 | 433 | }; |
447 | 433 | } |
448 | | |
449 | | static RPCMethod decodescript() |
450 | 1.58k | { |
451 | 1.58k | return RPCMethod{ |
452 | 1.58k | "decodescript", |
453 | 1.58k | "Decode a hex-encoded script.\n", |
454 | 1.58k | { |
455 | 1.58k | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"}, |
456 | 1.58k | }, |
457 | 1.58k | RPCResult{ |
458 | 1.58k | RPCResult::Type::OBJ, "", "", |
459 | 1.58k | { |
460 | 1.58k | {RPCResult::Type::STR, "asm", "Disassembly of the script"}, |
461 | 1.58k | {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, |
462 | 1.58k | {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"}, |
463 | 1.58k | {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, |
464 | 1.58k | {RPCResult::Type::STR, "p2sh", /*optional=*/true, |
465 | 1.58k | "address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"}, |
466 | 1.58k | {RPCResult::Type::OBJ, "segwit", /*optional=*/true, |
467 | 1.58k | "Result of a witness output script wrapping this redeem script (not returned for types that should not be wrapped)", |
468 | 1.58k | { |
469 | 1.58k | {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, |
470 | 1.58k | {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, |
471 | 1.58k | {RPCResult::Type::STR, "type", "The type of the output script (e.g. witness_v0_keyhash or witness_v0_scripthash)"}, |
472 | 1.58k | {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, |
473 | 1.58k | {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"}, |
474 | 1.58k | {RPCResult::Type::STR, "p2sh-segwit", "address of the P2SH script wrapping this witness redeem script"}, |
475 | 1.58k | }}, |
476 | 1.58k | }, |
477 | 1.58k | }, |
478 | 1.58k | RPCExamples{ |
479 | 1.58k | HelpExampleCli("decodescript", "\"hexstring\"") |
480 | 1.58k | + HelpExampleRpc("decodescript", "\"hexstring\"") |
481 | 1.58k | }, |
482 | 1.58k | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
483 | 1.58k | { |
484 | 783 | UniValue r(UniValue::VOBJ); |
485 | 783 | CScript script; |
486 | 783 | if (request.params[0].get_str().size() > 0){ Branch (486:9): [True: 782, False: 1]
|
487 | 782 | std::vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument")); |
488 | 782 | script = CScript(scriptData.begin(), scriptData.end()); |
489 | 782 | } else { |
490 | | // Empty scripts are valid |
491 | 1 | } |
492 | 783 | ScriptToUniv(script, /*out=*/r, /*include_hex=*/false, /*include_address=*/true); |
493 | | |
494 | 783 | std::vector<std::vector<unsigned char>> solutions_data; |
495 | 783 | const TxoutType which_type{Solver(script, solutions_data)}; |
496 | | |
497 | 783 | const bool can_wrap{[&] { |
498 | 752 | switch (which_type) { Branch (498:17): [True: 0, False: 752]
|
499 | 4 | case TxoutType::MULTISIG: Branch (499:9): [True: 4, False: 748]
|
500 | 736 | case TxoutType::NONSTANDARD: Branch (500:9): [True: 732, False: 20]
|
501 | 741 | case TxoutType::PUBKEY: Branch (501:9): [True: 5, False: 747]
|
502 | 741 | case TxoutType::PUBKEYHASH: Branch (502:9): [True: 0, False: 752]
|
503 | 742 | case TxoutType::WITNESS_V0_KEYHASH: Branch (503:9): [True: 1, False: 751]
|
504 | 743 | case TxoutType::WITNESS_V0_SCRIPTHASH: Branch (504:9): [True: 1, False: 751]
|
505 | | // Can be wrapped if the checks below pass |
506 | 743 | break; |
507 | 3 | case TxoutType::NULL_DATA: Branch (507:9): [True: 3, False: 749]
|
508 | 4 | case TxoutType::SCRIPTHASH: Branch (508:9): [True: 1, False: 751]
|
509 | 6 | case TxoutType::WITNESS_UNKNOWN: Branch (509:9): [True: 2, False: 750]
|
510 | 8 | case TxoutType::WITNESS_V1_TAPROOT: Branch (510:9): [True: 2, False: 750]
|
511 | 9 | case TxoutType::ANCHOR: Branch (511:9): [True: 1, False: 751]
|
512 | | // Should not be wrapped |
513 | 9 | return false; |
514 | 752 | } // no default case, so the compiler can warn about missing cases |
515 | 743 | if (!script.HasValidOps() || script.IsUnspendable()) { Branch (515:13): [True: 169, False: 574]
Branch (515:38): [True: 3, False: 571]
|
516 | 172 | return false; |
517 | 172 | } |
518 | 228k | for (CScript::const_iterator it{script.begin()}; it != script.end();) { Branch (518:58): [True: 227k, False: 532]
|
519 | 227k | opcodetype op; |
520 | 227k | CHECK_NONFATAL(script.GetOp(it, op)); |
521 | 227k | if (op == OP_CHECKSIGADD || IsOpSuccess(op)) { Branch (521:17): [True: 0, False: 227k]
Branch (521:41): [True: 39, False: 227k]
|
522 | 39 | return false; |
523 | 39 | } |
524 | 227k | } |
525 | 532 | return true; |
526 | 571 | }()}; |
527 | | |
528 | 783 | if (can_wrap) { Branch (528:9): [True: 532, False: 251]
|
529 | 532 | r.pushKV("p2sh", EncodeDestination(ScriptHash(script))); |
530 | | // P2SH and witness programs cannot be wrapped in P2WSH, if this script |
531 | | // is a witness program, don't return addresses for a segwit programs. |
532 | 532 | const bool can_wrap_P2WSH{[&] { |
533 | 532 | switch (which_type) { Branch (533:21): [True: 0, False: 532]
|
534 | 4 | case TxoutType::MULTISIG: Branch (534:13): [True: 4, False: 528]
|
535 | 9 | case TxoutType::PUBKEY: Branch (535:13): [True: 5, False: 527]
|
536 | | // Uncompressed pubkeys cannot be used with segwit checksigs. |
537 | | // If the script contains an uncompressed pubkey, skip encoding of a segwit program. |
538 | 21 | for (const auto& solution : solutions_data) { Branch (538:43): [True: 21, False: 4]
|
539 | 21 | if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) { Branch (539:25): [True: 15, False: 6]
Branch (539:25): [True: 5, False: 16]
Branch (539:51): [True: 5, False: 10]
|
540 | 5 | return false; |
541 | 5 | } |
542 | 21 | } |
543 | 4 | return true; |
544 | 521 | case TxoutType::NONSTANDARD: Branch (544:13): [True: 521, False: 11]
|
545 | 521 | case TxoutType::PUBKEYHASH: Branch (545:13): [True: 0, False: 532]
|
546 | | // Can be P2WSH wrapped |
547 | 521 | return true; |
548 | 0 | case TxoutType::NULL_DATA: Branch (548:13): [True: 0, False: 532]
|
549 | 0 | case TxoutType::SCRIPTHASH: Branch (549:13): [True: 0, False: 532]
|
550 | 0 | case TxoutType::WITNESS_UNKNOWN: Branch (550:13): [True: 0, False: 532]
|
551 | 1 | case TxoutType::WITNESS_V0_KEYHASH: Branch (551:13): [True: 1, False: 531]
|
552 | 2 | case TxoutType::WITNESS_V0_SCRIPTHASH: Branch (552:13): [True: 1, False: 531]
|
553 | 2 | case TxoutType::WITNESS_V1_TAPROOT: Branch (553:13): [True: 0, False: 532]
|
554 | 2 | case TxoutType::ANCHOR: Branch (554:13): [True: 0, False: 532]
|
555 | | // Should not be wrapped |
556 | 2 | return false; |
557 | 532 | } // no default case, so the compiler can warn about missing cases |
558 | 532 | NONFATAL_UNREACHABLE(); |
559 | 532 | }()}; |
560 | 532 | if (can_wrap_P2WSH) { Branch (560:13): [True: 525, False: 7]
|
561 | 525 | UniValue sr(UniValue::VOBJ); |
562 | 525 | CScript segwitScr; |
563 | 525 | FlatSigningProvider provider; |
564 | 525 | if (which_type == TxoutType::PUBKEY) { Branch (564:17): [True: 2, False: 523]
|
565 | 2 | segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0]))); |
566 | 523 | } else if (which_type == TxoutType::PUBKEYHASH) { Branch (566:24): [True: 0, False: 523]
|
567 | 0 | segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]})); |
568 | 523 | } else { |
569 | | // Scripts that are not fit for P2WPKH are encoded as P2WSH. |
570 | 523 | provider.scripts[CScriptID(script)] = script; |
571 | 523 | segwitScr = GetScriptForDestination(WitnessV0ScriptHash(script)); |
572 | 523 | } |
573 | 525 | ScriptToUniv(segwitScr, /*out=*/sr, /*include_hex=*/true, /*include_address=*/true, /*provider=*/&provider); |
574 | 525 | sr.pushKV("p2sh-segwit", EncodeDestination(ScriptHash(segwitScr))); |
575 | 525 | r.pushKV("segwit", std::move(sr)); |
576 | 525 | } |
577 | 532 | } |
578 | | |
579 | 783 | return r; |
580 | 783 | }, |
581 | 1.58k | }; |
582 | 1.58k | } |
583 | | |
584 | | static RPCMethod combinerawtransaction() |
585 | 130 | { |
586 | 130 | return RPCMethod{ |
587 | 130 | "combinerawtransaction", |
588 | 130 | "Combine multiple partially signed transactions into one transaction.\n" |
589 | 130 | "The combined transaction may be another partially signed transaction or a \n" |
590 | 130 | "fully signed transaction.", |
591 | 130 | { |
592 | 130 | {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The hex strings of partially signed transactions", |
593 | 130 | { |
594 | 130 | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A hex-encoded raw transaction"}, |
595 | 130 | }, |
596 | 130 | }, |
597 | 130 | }, |
598 | 130 | RPCResult{ |
599 | 130 | RPCResult::Type::STR, "", "The hex-encoded raw transaction with signature(s)" |
600 | 130 | }, |
601 | 130 | RPCExamples{ |
602 | 130 | HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')") |
603 | 130 | }, |
604 | 130 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
605 | 130 | { |
606 | | |
607 | 70 | UniValue txs = request.params[0].get_array(); |
608 | | |
609 | | // Can't merge < 2 items |
610 | 70 | if (txs.size() < 2) { Branch (610:9): [True: 8, False: 62]
|
611 | 8 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transactions. At least two transactions required."); |
612 | 8 | } |
613 | | |
614 | 62 | std::vector<CMutableTransaction> txVariants(txs.size()); |
615 | | |
616 | 182 | for (unsigned int idx = 0; idx < txs.size(); idx++) { Branch (616:32): [True: 121, False: 61]
|
617 | 121 | if (!DecodeHexTx(txVariants[idx], txs[idx].get_str())) { Branch (617:13): [True: 1, False: 120]
|
618 | 1 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed for tx %d. Make sure the tx has at least one input.", idx)); |
619 | 1 | } |
620 | 121 | } |
621 | | |
622 | 61 | { // Test Tx relation for mergeability. Strip scriptSigs and scriptWitnesses to facilitate txId comparison |
623 | 61 | std::vector<CMutableTransaction> tx_variants_copy(txVariants); |
624 | 61 | Txid first_txid{}; |
625 | 119 | for (unsigned int k{0}; k < tx_variants_copy.size(); ++k) { Branch (625:33): [True: 77, False: 42]
|
626 | | // Remove all scriptSigs and scriptWitnesses from inputs |
627 | 989 | for (CTxIn& input : tx_variants_copy[k].vin) { Branch (627:31): [True: 989, False: 77]
|
628 | 989 | input.scriptSig.clear(); |
629 | 989 | input.scriptWitness.SetNull(); |
630 | 989 | } |
631 | 77 | if (k == 0) { Branch (631:17): [True: 33, False: 44]
|
632 | 33 | first_txid = tx_variants_copy[k].GetHash(); |
633 | 44 | } else if (first_txid != tx_variants_copy[k].GetHash()) { Branch (633:24): [True: 19, False: 25]
|
634 | 19 | throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Transaction number %d not compatible with first transaction", k+1)); |
635 | 19 | } |
636 | 77 | } |
637 | 61 | } |
638 | | |
639 | | // mergedTx will end up with all the signatures; it |
640 | | // starts as a clone of the rawtx: |
641 | 42 | CMutableTransaction mergedTx(txVariants[0]); |
642 | | |
643 | | // Fetch previous transactions (inputs): |
644 | 42 | CCoinsViewCache view{&CoinsViewEmpty::Get()}; |
645 | 42 | { |
646 | 42 | NodeContext& node = EnsureAnyNodeContext(request.context); |
647 | 42 | const CTxMemPool& mempool = EnsureMemPool(node); |
648 | 42 | ChainstateManager& chainman = EnsureChainman(node); |
649 | 42 | LOCK2(cs_main, mempool.cs); |
650 | 42 | CCoinsViewCache &viewChain = chainman.ActiveChainstate().CoinsTip(); |
651 | 42 | CCoinsViewMemPool viewMempool(&viewChain, mempool); |
652 | 42 | view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view |
653 | | |
654 | 42 | for (const CTxIn& txin : mergedTx.vin) { Branch (654:32): [True: 22, False: 42]
|
655 | 22 | view.AccessCoin(txin.prevout); // Load entries from viewChain into view; can fail. |
656 | 22 | } |
657 | | |
658 | 42 | view.SetBackend(CoinsViewEmpty::Get()); // switch back to avoid locking mempool for too long |
659 | 42 | } |
660 | | |
661 | | // Use CTransaction for the constant parts of the |
662 | | // transaction to avoid rehashing. |
663 | 42 | const CTransaction txConst(mergedTx); |
664 | | // Sign what we can: |
665 | 42 | for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { Branch (665:30): [True: 10, False: 32]
|
666 | 10 | CTxIn& txin = mergedTx.vin[i]; |
667 | 10 | const Coin& coin = view.AccessCoin(txin.prevout); |
668 | 10 | if (coin.IsSpent()) { Branch (668:13): [True: 10, False: 0]
|
669 | 10 | throw JSONRPCError(RPC_VERIFY_ERROR, "Input not found or already spent"); |
670 | 10 | } |
671 | 0 | SignatureData sigdata; |
672 | | |
673 | | // ... and merge in other signatures: |
674 | 0 | for (const CMutableTransaction& txv : txVariants) { Branch (674:45): [True: 0, False: 0]
|
675 | 0 | if (txv.vin.size() > i) { Branch (675:17): [True: 0, False: 0]
|
676 | 0 | sigdata.MergeSignatureData(DataFromTransaction(txv, i, coin.out)); |
677 | 0 | } |
678 | 0 | } |
679 | 0 | ProduceSignature(DUMMY_SIGNING_PROVIDER, MutableTransactionSignatureCreator(mergedTx, i, coin.out.nValue, {.sighash_type = SIGHASH_ALL}), coin.out.scriptPubKey, sigdata); |
680 | |
|
681 | 0 | UpdateInput(txin, sigdata); |
682 | 0 | } |
683 | | |
684 | 32 | return EncodeHexTx(CTransaction(mergedTx)); |
685 | 42 | }, |
686 | 130 | }; |
687 | 130 | } |
688 | | |
689 | | static RPCMethod signrawtransactionwithkey() |
690 | 269 | { |
691 | 269 | return RPCMethod{ |
692 | 269 | "signrawtransactionwithkey", |
693 | 269 | "Sign inputs for raw transaction (serialized, hex-encoded).\n" |
694 | 269 | "The second argument is an array of base58-encoded private\n" |
695 | 269 | "keys that will be the only keys used to sign the transaction.\n" |
696 | 269 | "The third optional argument (may be null) is an array of previous transaction outputs that\n" |
697 | 269 | "this transaction depends on but may not yet be in the block chain.\n", |
698 | 269 | { |
699 | 269 | {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"}, |
700 | 269 | {"privkeys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base58-encoded private keys for signing", |
701 | 269 | { |
702 | 269 | {"privatekey", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "private key in base58-encoding"}, |
703 | 269 | }, |
704 | 269 | }, |
705 | 269 | {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The previous dependent transaction outputs", |
706 | 269 | { |
707 | 269 | {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", |
708 | 269 | { |
709 | 269 | {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, |
710 | 269 | {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, |
711 | 269 | {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "output script"}, |
712 | 269 | {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"}, |
713 | 269 | {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"}, |
714 | 269 | {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"}, |
715 | 269 | }, |
716 | 269 | }, |
717 | 269 | }, |
718 | 269 | }, |
719 | 269 | {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type. Must be one of:\n" |
720 | 269 | " \"DEFAULT\"\n" |
721 | 269 | " \"ALL\"\n" |
722 | 269 | " \"NONE\"\n" |
723 | 269 | " \"SINGLE\"\n" |
724 | 269 | " \"ALL|ANYONECANPAY\"\n" |
725 | 269 | " \"NONE|ANYONECANPAY\"\n" |
726 | 269 | " \"SINGLE|ANYONECANPAY\"\n" |
727 | 269 | }, |
728 | 269 | }, |
729 | 269 | RPCResult{ |
730 | 269 | RPCResult::Type::OBJ, "", "", |
731 | 269 | { |
732 | 269 | {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"}, |
733 | 269 | {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"}, |
734 | 269 | {RPCResult::Type::ARR, "errors", /*optional=*/true, "Script verification errors (if there are any)", |
735 | 269 | { |
736 | 269 | {RPCResult::Type::OBJ, "", "", |
737 | 269 | { |
738 | 269 | {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"}, |
739 | 269 | {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"}, |
740 | 269 | {RPCResult::Type::ARR, "witness", "", |
741 | 269 | { |
742 | 269 | {RPCResult::Type::STR_HEX, "witness", ""}, |
743 | 269 | }}, |
744 | 269 | {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"}, |
745 | 269 | {RPCResult::Type::NUM, "sequence", "Script sequence number"}, |
746 | 269 | {RPCResult::Type::STR, "error", "Verification or signing error related to the input"}, |
747 | 269 | }}, |
748 | 269 | }}, |
749 | 269 | } |
750 | 269 | }, |
751 | 269 | RPCExamples{ |
752 | 269 | HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"") |
753 | 269 | + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"") |
754 | 269 | }, |
755 | 269 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
756 | 269 | { |
757 | 88 | CMutableTransaction mtx; |
758 | 88 | if (!DecodeHexTx(mtx, request.params[0].get_str())) { Branch (758:9): [True: 1, False: 87]
|
759 | 1 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input."); |
760 | 1 | } |
761 | | |
762 | 87 | FlatSigningProvider keystore; |
763 | 87 | const UniValue& keys = request.params[1].get_array(); |
764 | 1.68k | for (unsigned int idx = 0; idx < keys.size(); ++idx) { Branch (764:32): [True: 1.60k, False: 80]
|
765 | 1.60k | UniValue k = keys[idx]; |
766 | 1.60k | CKey key = DecodeSecret(k.get_str()); |
767 | 1.60k | if (!key.IsValid()) { Branch (767:13): [True: 7, False: 1.60k]
|
768 | 7 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); |
769 | 7 | } |
770 | | |
771 | 1.60k | CPubKey pubkey = key.GetPubKey(); |
772 | 1.60k | CKeyID key_id = pubkey.GetID(); |
773 | 1.60k | keystore.pubkeys.emplace(key_id, pubkey); |
774 | 1.60k | keystore.keys.emplace(key_id, key); |
775 | 1.60k | } |
776 | | |
777 | | // Fetch previous transactions (inputs): |
778 | 80 | std::map<COutPoint, Coin> coins; |
779 | 3.52k | for (const CTxIn& txin : mtx.vin) { Branch (779:28): [True: 3.52k, False: 80]
|
780 | 3.52k | coins[txin.prevout]; // Create empty map entry keyed by prevout. |
781 | 3.52k | } |
782 | 80 | NodeContext& node = EnsureAnyNodeContext(request.context); |
783 | 80 | FindCoins(node, coins); |
784 | | |
785 | | // Parse the prevtxs array |
786 | 80 | ParsePrevouts(request.params[2], &keystore, coins); |
787 | | |
788 | 80 | UniValue result(UniValue::VOBJ); |
789 | 80 | SignTransaction(mtx, &keystore, coins, request.params[3], result); |
790 | 80 | return result; |
791 | 87 | }, |
792 | 269 | }; |
793 | 269 | } |
794 | | |
795 | | const RPCResult& DecodePSBTInputs() |
796 | 530 | { |
797 | 530 | static const RPCResult decodepsbt_inputs{ |
798 | 530 | RPCResult::Type::ARR, "inputs", "", |
799 | 530 | { |
800 | 530 | {RPCResult::Type::OBJ, "", "", |
801 | 530 | { |
802 | 530 | {RPCResult::Type::OBJ, "non_witness_utxo", /*optional=*/true, "Decoded network transaction for non-witness UTXOs", |
803 | 530 | TxDoc({.elision_mode = ElisionMode::WithSummary, .elision_summary = "The layout is the same as the output of decoderawtransaction."}) |
804 | 530 | }, |
805 | 530 | {RPCResult::Type::OBJ, "witness_utxo", /*optional=*/true, "Transaction output for witness UTXOs", |
806 | 530 | { |
807 | 530 | {RPCResult::Type::NUM, "amount", "The value in " + CURRENCY_UNIT}, |
808 | 530 | {RPCResult::Type::OBJ, "scriptPubKey", "", |
809 | 530 | { |
810 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the output script"}, |
811 | 530 | {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"}, |
812 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"}, |
813 | 530 | {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, |
814 | 530 | {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"}, |
815 | 530 | }}, |
816 | 530 | }}, |
817 | 530 | {RPCResult::Type::OBJ_DYN, "partial_signatures", /*optional=*/true, "", |
818 | 530 | { |
819 | 530 | {RPCResult::Type::STR, "pubkey", "The public key and signature that corresponds to it."}, |
820 | 530 | }}, |
821 | 530 | {RPCResult::Type::STR, "sighash", /*optional=*/true, "The sighash type to be used"}, |
822 | 530 | {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", |
823 | 530 | { |
824 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"}, |
825 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"}, |
826 | 530 | {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, |
827 | 530 | }}, |
828 | 530 | {RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "", |
829 | 530 | { |
830 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the witness script"}, |
831 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"}, |
832 | 530 | {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, |
833 | 530 | }}, |
834 | 530 | {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", |
835 | 530 | { |
836 | 530 | {RPCResult::Type::OBJ, "", "", |
837 | 530 | { |
838 | 530 | {RPCResult::Type::STR, "pubkey", "The public key with the derivation path as the value."}, |
839 | 530 | {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, |
840 | 530 | {RPCResult::Type::STR, "path", "The path"}, |
841 | 530 | }}, |
842 | 530 | }}, |
843 | 530 | {RPCResult::Type::OBJ, "final_scriptSig", /*optional=*/true, "", |
844 | 530 | { |
845 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the final signature script"}, |
846 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw final signature script bytes, hex-encoded"}, |
847 | 530 | }}, |
848 | 530 | {RPCResult::Type::ARR, "final_scriptwitness", /*optional=*/true, "", |
849 | 530 | { |
850 | 530 | {RPCResult::Type::STR_HEX, "", "hex-encoded witness data (if any)"}, |
851 | 530 | }}, |
852 | 530 | {RPCResult::Type::OBJ_DYN, "ripemd160_preimages", /*optional=*/ true, "", |
853 | 530 | { |
854 | 530 | {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, |
855 | 530 | }}, |
856 | 530 | {RPCResult::Type::OBJ_DYN, "sha256_preimages", /*optional=*/ true, "", |
857 | 530 | { |
858 | 530 | {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, |
859 | 530 | }}, |
860 | 530 | {RPCResult::Type::OBJ_DYN, "hash160_preimages", /*optional=*/ true, "", |
861 | 530 | { |
862 | 530 | {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, |
863 | 530 | }}, |
864 | 530 | {RPCResult::Type::OBJ_DYN, "hash256_preimages", /*optional=*/ true, "", |
865 | 530 | { |
866 | 530 | {RPCResult::Type::STR, "hash", "The hash and preimage that corresponds to it."}, |
867 | 530 | }}, |
868 | 530 | {RPCResult::Type::STR_HEX, "previous_txid", /*optional=*/true, "TXID of the transaction containing the output being spent by this input"}, |
869 | 530 | {RPCResult::Type::NUM, "previous_vout", /*optional=*/true, "Index of the output being spent"}, |
870 | 530 | {RPCResult::Type::NUM, "sequence", /*optional=*/true, "Sequence number for this input"}, |
871 | 530 | {RPCResult::Type::NUM, "time_locktime", /*optional=*/true, "Time-based locktime required for this input"}, |
872 | 530 | {RPCResult::Type::NUM, "height_locktime", /*optional=*/true, "Height-based locktime required for this input"}, |
873 | 530 | {RPCResult::Type::STR_HEX, "taproot_key_path_sig", /*optional=*/ true, "hex-encoded signature for the Taproot key path spend"}, |
874 | 530 | {RPCResult::Type::ARR, "taproot_script_path_sigs", /*optional=*/ true, "", |
875 | 530 | { |
876 | 530 | {RPCResult::Type::OBJ, "signature", /*optional=*/ true, "The signature for the pubkey and leaf hash combination", |
877 | 530 | { |
878 | 530 | {RPCResult::Type::STR, "pubkey", "The x-only pubkey for this signature"}, |
879 | 530 | {RPCResult::Type::STR, "leaf_hash", "The leaf hash for this signature"}, |
880 | 530 | {RPCResult::Type::STR, "sig", "The signature itself"}, |
881 | 530 | }}, |
882 | 530 | }}, |
883 | 530 | {RPCResult::Type::ARR, "taproot_scripts", /*optional=*/ true, "", |
884 | 530 | { |
885 | 530 | {RPCResult::Type::OBJ, "", "", |
886 | 530 | { |
887 | 530 | {RPCResult::Type::STR_HEX, "script", "A leaf script"}, |
888 | 530 | {RPCResult::Type::NUM, "leaf_ver", "The version number for the leaf script"}, |
889 | 530 | {RPCResult::Type::ARR, "control_blocks", "The control blocks for this script", |
890 | 530 | { |
891 | 530 | {RPCResult::Type::STR_HEX, "control_block", "A hex-encoded control block for this script"}, |
892 | 530 | }}, |
893 | 530 | }}, |
894 | 530 | }}, |
895 | 530 | {RPCResult::Type::ARR, "taproot_bip32_derivs", /*optional=*/ true, "", |
896 | 530 | { |
897 | 530 | {RPCResult::Type::OBJ, "", "", |
898 | 530 | { |
899 | 530 | {RPCResult::Type::STR, "pubkey", "The x-only public key this path corresponds to"}, |
900 | 530 | {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, |
901 | 530 | {RPCResult::Type::STR, "path", "The path"}, |
902 | 530 | {RPCResult::Type::ARR, "leaf_hashes", "The hashes of the leaves this pubkey appears in", |
903 | 530 | { |
904 | 530 | {RPCResult::Type::STR_HEX, "hash", "The hash of a leaf this pubkey appears in"}, |
905 | 530 | }}, |
906 | 530 | }}, |
907 | 530 | }}, |
908 | 530 | {RPCResult::Type::STR_HEX, "taproot_internal_key", /*optional=*/ true, "The hex-encoded Taproot x-only internal key"}, |
909 | 530 | {RPCResult::Type::STR_HEX, "taproot_merkle_root", /*optional=*/ true, "The hex-encoded Taproot merkle root"}, |
910 | 530 | {RPCResult::Type::ARR, "musig2_participant_pubkeys", /*optional=*/true, "", |
911 | 530 | { |
912 | 530 | {RPCResult::Type::OBJ, "", "", |
913 | 530 | { |
914 | 530 | {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which the participants create."}, |
915 | 530 | {RPCResult::Type::ARR, "participant_pubkeys", "", |
916 | 530 | { |
917 | 530 | {RPCResult::Type::STR_HEX, "pubkey", "The compressed public keys that are aggregated for aggregate_pubkey."}, |
918 | 530 | }}, |
919 | 530 | }}, |
920 | 530 | }}, |
921 | 530 | {RPCResult::Type::ARR, "musig2_pubnonces", /*optional=*/true, "", |
922 | 530 | { |
923 | 530 | {RPCResult::Type::OBJ, "", "", |
924 | 530 | { |
925 | 530 | {RPCResult::Type::STR_HEX, "participant_pubkey", "The compressed public key of the participant that created this pubnonce."}, |
926 | 530 | {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which this pubnonce is for."}, |
927 | 530 | {RPCResult::Type::STR_HEX, "leaf_hash", /*optional=*/true, "The hash of the leaf script that contains the aggregate pubkey being signed for. Omitted when signing for the internal key."}, |
928 | 530 | {RPCResult::Type::STR_HEX, "pubnonce", "The public nonce itself."}, |
929 | 530 | }}, |
930 | 530 | }}, |
931 | 530 | {RPCResult::Type::ARR, "musig2_partial_sigs", /*optional=*/true, "", |
932 | 530 | { |
933 | 530 | {RPCResult::Type::OBJ, "", "", |
934 | 530 | { |
935 | 530 | {RPCResult::Type::STR_HEX, "participant_pubkey", "The compressed public key of the participant that created this partial signature."}, |
936 | 530 | {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which this partial signature is for."}, |
937 | 530 | {RPCResult::Type::STR_HEX, "leaf_hash", /*optional=*/true, "The hash of the leaf script that contains the aggregate pubkey being signed for. Omitted when signing for the internal key."}, |
938 | 530 | {RPCResult::Type::STR_HEX, "partial_sig", "The partial signature itself."}, |
939 | 530 | }}, |
940 | 530 | }}, |
941 | 530 | {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/ true, "The unknown input fields", |
942 | 530 | { |
943 | 530 | {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, |
944 | 530 | }}, |
945 | 530 | {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The input proprietary map", |
946 | 530 | { |
947 | 530 | {RPCResult::Type::OBJ, "", "", |
948 | 530 | { |
949 | 530 | {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, |
950 | 530 | {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, |
951 | 530 | {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, |
952 | 530 | {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, |
953 | 530 | }}, |
954 | 530 | }}, |
955 | 530 | }}, |
956 | 530 | } |
957 | 530 | }; |
958 | 530 | return decodepsbt_inputs; |
959 | 530 | } |
960 | | |
961 | | const RPCResult& DecodePSBTOutputs() |
962 | 530 | { |
963 | 530 | static const RPCResult decodepsbt_outputs{ |
964 | 530 | RPCResult::Type::ARR, "outputs", "", |
965 | 530 | { |
966 | 530 | {RPCResult::Type::OBJ, "", "", |
967 | 530 | { |
968 | 530 | {RPCResult::Type::OBJ, "redeem_script", /*optional=*/true, "", |
969 | 530 | { |
970 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the redeem script"}, |
971 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw redeem script bytes, hex-encoded"}, |
972 | 530 | {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, |
973 | 530 | }}, |
974 | 530 | {RPCResult::Type::OBJ, "witness_script", /*optional=*/true, "", |
975 | 530 | { |
976 | 530 | {RPCResult::Type::STR, "asm", "Disassembly of the witness script"}, |
977 | 530 | {RPCResult::Type::STR_HEX, "hex", "The raw witness script bytes, hex-encoded"}, |
978 | 530 | {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"}, |
979 | 530 | }}, |
980 | 530 | {RPCResult::Type::ARR, "bip32_derivs", /*optional=*/true, "", |
981 | 530 | { |
982 | 530 | {RPCResult::Type::OBJ, "", "", |
983 | 530 | { |
984 | 530 | {RPCResult::Type::STR, "pubkey", "The public key this path corresponds to"}, |
985 | 530 | {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, |
986 | 530 | {RPCResult::Type::STR, "path", "The path"}, |
987 | 530 | }}, |
988 | 530 | }}, |
989 | 530 | {RPCResult::Type::NUM, "amount", /* optional=*/ true, "The amount (nValue) for this output"}, |
990 | 530 | {RPCResult::Type::OBJ, "script", /* optional=*/ true, "The output script (scriptPubKey) for this output", |
991 | 530 | ElideGroup(ScriptPubKeyDoc(), "The layout is the same as the output of scriptPubKeys in decoderawtransaction."), |
992 | 530 | }, |
993 | 530 | {RPCResult::Type::STR_HEX, "taproot_internal_key", /*optional=*/ true, "The hex-encoded Taproot x-only internal key"}, |
994 | 530 | {RPCResult::Type::ARR, "taproot_tree", /*optional=*/ true, "The tuples that make up the Taproot tree, in depth first search order", |
995 | 530 | { |
996 | 530 | {RPCResult::Type::OBJ, "tuple", /*optional=*/ true, "A single leaf script in the taproot tree", |
997 | 530 | { |
998 | 530 | {RPCResult::Type::NUM, "depth", "The depth of this element in the tree"}, |
999 | 530 | {RPCResult::Type::NUM, "leaf_ver", "The version of this leaf"}, |
1000 | 530 | {RPCResult::Type::STR, "script", "The hex-encoded script itself"}, |
1001 | 530 | }}, |
1002 | 530 | }}, |
1003 | 530 | {RPCResult::Type::ARR, "taproot_bip32_derivs", /*optional=*/ true, "", |
1004 | 530 | { |
1005 | 530 | {RPCResult::Type::OBJ, "", "", |
1006 | 530 | { |
1007 | 530 | {RPCResult::Type::STR, "pubkey", "The x-only public key this path corresponds to"}, |
1008 | 530 | {RPCResult::Type::STR, "master_fingerprint", "The fingerprint of the master key"}, |
1009 | 530 | {RPCResult::Type::STR, "path", "The path"}, |
1010 | 530 | {RPCResult::Type::ARR, "leaf_hashes", "The hashes of the leaves this pubkey appears in", |
1011 | 530 | { |
1012 | 530 | {RPCResult::Type::STR_HEX, "hash", "The hash of a leaf this pubkey appears in"}, |
1013 | 530 | }}, |
1014 | 530 | }}, |
1015 | 530 | }}, |
1016 | 530 | {RPCResult::Type::ARR, "musig2_participant_pubkeys", /*optional=*/true, "", |
1017 | 530 | { |
1018 | 530 | {RPCResult::Type::OBJ, "", "", |
1019 | 530 | { |
1020 | 530 | {RPCResult::Type::STR_HEX, "aggregate_pubkey", "The compressed aggregate public key for which the participants create."}, |
1021 | 530 | {RPCResult::Type::ARR, "participant_pubkeys", "", |
1022 | 530 | { |
1023 | 530 | {RPCResult::Type::STR_HEX, "pubkey", "The compressed public keys that are aggregated for aggregate_pubkey."}, |
1024 | 530 | }}, |
1025 | 530 | }}, |
1026 | 530 | }}, |
1027 | 530 | {RPCResult::Type::OBJ_DYN, "unknown", /*optional=*/true, "The unknown output fields", |
1028 | 530 | { |
1029 | 530 | {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, |
1030 | 530 | }}, |
1031 | 530 | {RPCResult::Type::ARR, "proprietary", /*optional=*/true, "The output proprietary map", |
1032 | 530 | { |
1033 | 530 | {RPCResult::Type::OBJ, "", "", |
1034 | 530 | { |
1035 | 530 | {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, |
1036 | 530 | {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, |
1037 | 530 | {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, |
1038 | 530 | {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, |
1039 | 530 | }}, |
1040 | 530 | }}, |
1041 | 530 | }}, |
1042 | 530 | } |
1043 | 530 | }; |
1044 | 530 | return decodepsbt_outputs; |
1045 | 530 | } |
1046 | | |
1047 | | static RPCMethod decodepsbt() |
1048 | 530 | { |
1049 | 530 | return RPCMethod{ |
1050 | 530 | "decodepsbt", |
1051 | 530 | "Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.", |
1052 | 530 | { |
1053 | 530 | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"}, |
1054 | 530 | }, |
1055 | 530 | RPCResult{ |
1056 | 530 | RPCResult::Type::OBJ, "", "", |
1057 | 530 | { |
1058 | 530 | {RPCResult::Type::OBJ, "tx", /*optional=*/true, "The decoded network-serialized unsigned transaction.", |
1059 | 530 | TxDoc({.elision_mode = ElisionMode::WithSummary, .elision_summary = "The layout is the same as the output of decoderawtransaction."}) |
1060 | 530 | }, |
1061 | 530 | {RPCResult::Type::ARR, "global_xpubs", "", |
1062 | 530 | { |
1063 | 530 | {RPCResult::Type::OBJ, "", "", |
1064 | 530 | { |
1065 | 530 | {RPCResult::Type::STR, "xpub", "The extended public key this path corresponds to"}, |
1066 | 530 | {RPCResult::Type::STR_HEX, "master_fingerprint", "The fingerprint of the master key"}, |
1067 | 530 | {RPCResult::Type::STR, "path", "The path"}, |
1068 | 530 | }}, |
1069 | 530 | }}, |
1070 | 530 | {RPCResult::Type::NUM, "tx_version", /* optional */ true, "The version number of the unsigned transaction. Not to be confused with PSBT version"}, |
1071 | 530 | {RPCResult::Type::NUM, "fallback_locktime", /* optional */ true, "The locktime to fallback to if no inputs specify a required locktime."}, |
1072 | 530 | {RPCResult::Type::NUM, "input_count", /* optional */ true, "The number of inputs in this psbt"}, |
1073 | 530 | {RPCResult::Type::NUM, "output_count", /* optional */ true, "The number of outputs in this psbt."}, |
1074 | 530 | {RPCResult::Type::BOOL, "inputs_modifiable", /* optional */ true, "Whether inputs can be modified"}, |
1075 | 530 | {RPCResult::Type::BOOL, "outputs_modifiable", /* optional */ true, "Whether outputs can be modified"}, |
1076 | 530 | {RPCResult::Type::BOOL, "has_sighash_single", /* optional */ true, "Whether this PSBT has SIGHASH_SINGLE inputs"}, |
1077 | 530 | {RPCResult::Type::NUM, "psbt_version", /* optional */ true, "The PSBT version number. Not to be confused with the unsigned transaction version"}, |
1078 | 530 | {RPCResult::Type::ARR, "proprietary", "The global proprietary map", |
1079 | 530 | { |
1080 | 530 | {RPCResult::Type::OBJ, "", "", |
1081 | 530 | { |
1082 | 530 | {RPCResult::Type::STR_HEX, "identifier", "The hex string for the proprietary identifier"}, |
1083 | 530 | {RPCResult::Type::NUM, "subtype", "The number for the subtype"}, |
1084 | 530 | {RPCResult::Type::STR_HEX, "key", "The hex for the key"}, |
1085 | 530 | {RPCResult::Type::STR_HEX, "value", "The hex for the value"}, |
1086 | 530 | }}, |
1087 | 530 | }}, |
1088 | 530 | {RPCResult::Type::OBJ_DYN, "unknown", "The unknown global fields", |
1089 | 530 | { |
1090 | 530 | {RPCResult::Type::STR_HEX, "key", "(key-value pair) An unknown key-value pair"}, |
1091 | 530 | }}, |
1092 | 530 | DecodePSBTInputs(), |
1093 | 530 | DecodePSBTOutputs(), |
1094 | 530 | {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid if all UTXOs slots in the PSBT have been filled."}, |
1095 | 530 | } |
1096 | 530 | }, |
1097 | 530 | RPCExamples{ |
1098 | 530 | HelpExampleCli("decodepsbt", "\"psbt\"") |
1099 | 530 | }, |
1100 | 530 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1101 | 530 | { |
1102 | | // Unserialize the transactions |
1103 | 176 | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(request.params[0].get_str()); |
1104 | 176 | if (!psbt_res) { Branch (1104:9): [True: 10, False: 166]
|
1105 | 10 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
1106 | 10 | } |
1107 | 166 | PartiallySignedTransaction psbtx = *psbt_res; |
1108 | | |
1109 | 166 | UniValue result(UniValue::VOBJ); |
1110 | | |
1111 | 166 | if (psbtx.GetVersion() < 2) { Branch (1111:9): [True: 166, False: 0]
|
1112 | | // Add the decoded tx |
1113 | 166 | UniValue tx_univ(UniValue::VOBJ); |
1114 | 166 | TxToUniv(CTransaction(*CHECK_NONFATAL(psbtx.GetUnsignedTx())), /*block_hash=*/uint256(), /*entry=*/tx_univ, /*include_hex=*/false); |
1115 | 166 | result.pushKV("tx", std::move(tx_univ)); |
1116 | 166 | } |
1117 | | |
1118 | | // Add the global xpubs |
1119 | 166 | UniValue global_xpubs(UniValue::VARR); |
1120 | 166 | for (std::pair<KeyOriginInfo, std::set<CExtPubKey>> xpub_pair : psbtx.m_xpubs) { Branch (1120:67): [True: 60, False: 166]
|
1121 | 66 | for (auto& xpub : xpub_pair.second) { Branch (1121:25): [True: 66, False: 60]
|
1122 | 66 | std::vector<unsigned char> ser_xpub; |
1123 | 66 | ser_xpub.assign(BIP32_EXTKEY_WITH_VERSION_SIZE, 0); |
1124 | 66 | xpub.EncodeWithVersion(ser_xpub.data()); |
1125 | | |
1126 | 66 | UniValue keypath(UniValue::VOBJ); |
1127 | 66 | keypath.pushKV("xpub", EncodeBase58Check(ser_xpub)); |
1128 | 66 | keypath.pushKV("master_fingerprint", HexStr(xpub_pair.first.fingerprint)); |
1129 | 66 | keypath.pushKV("path", WriteHDKeypath(xpub_pair.first.path)); |
1130 | 66 | global_xpubs.push_back(std::move(keypath)); |
1131 | 66 | } |
1132 | 60 | } |
1133 | 166 | result.pushKV("global_xpubs", std::move(global_xpubs)); |
1134 | | |
1135 | | // Add PSBTv2 stuff |
1136 | 166 | if (psbtx.GetVersion() >= 2) { Branch (1136:9): [True: 0, False: 166]
|
1137 | 0 | result.pushKV("tx_version", psbtx.tx_version); |
1138 | 0 | if (psbtx.fallback_locktime.has_value()) { Branch (1138:13): [True: 0, False: 0]
|
1139 | 0 | result.pushKV("fallback_locktime", static_cast<uint64_t>(*psbtx.fallback_locktime)); |
1140 | 0 | } |
1141 | 0 | result.pushKV("input_count", (uint64_t)psbtx.inputs.size()); |
1142 | 0 | result.pushKV("output_count", (uint64_t)psbtx.outputs.size()); |
1143 | 0 | if (psbtx.m_tx_modifiable.has_value()) { Branch (1143:13): [True: 0, False: 0]
|
1144 | 0 | result.pushKV("inputs_modifiable", psbtx.m_tx_modifiable->test(0)); |
1145 | 0 | result.pushKV("outputs_modifiable", psbtx.m_tx_modifiable->test(1)); |
1146 | 0 | result.pushKV("has_sighash_single", psbtx.m_tx_modifiable->test(2)); |
1147 | 0 | } |
1148 | 0 | } |
1149 | | |
1150 | | // PSBT version |
1151 | 166 | result.pushKV("psbt_version", psbtx.GetVersion()); |
1152 | | |
1153 | | // Proprietary |
1154 | 166 | UniValue proprietary(UniValue::VARR); |
1155 | 166 | for (const auto& entry : psbtx.m_proprietary) { Branch (1155:28): [True: 27, False: 166]
|
1156 | 27 | UniValue this_prop(UniValue::VOBJ); |
1157 | 27 | this_prop.pushKV("identifier", HexStr(entry.identifier)); |
1158 | 27 | this_prop.pushKV("subtype", entry.subtype); |
1159 | 27 | this_prop.pushKV("key", HexStr(entry.key)); |
1160 | 27 | this_prop.pushKV("value", HexStr(entry.value)); |
1161 | 27 | proprietary.push_back(std::move(this_prop)); |
1162 | 27 | } |
1163 | 166 | result.pushKV("proprietary", std::move(proprietary)); |
1164 | | |
1165 | | // Unknown data |
1166 | 166 | UniValue unknowns(UniValue::VOBJ); |
1167 | 289 | for (auto entry : psbtx.unknown) { Branch (1167:21): [True: 289, False: 166]
|
1168 | 289 | unknowns.pushKV(HexStr(entry.first), HexStr(entry.second)); |
1169 | 289 | } |
1170 | 166 | result.pushKV("unknown", std::move(unknowns)); |
1171 | | |
1172 | | // inputs |
1173 | 166 | CAmount total_in = 0; |
1174 | 166 | bool have_all_utxos = true; |
1175 | 166 | UniValue inputs(UniValue::VARR); |
1176 | 278 | for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) { Branch (1176:30): [True: 112, False: 166]
|
1177 | 112 | const PSBTInput& input = psbtx.inputs[i]; |
1178 | 112 | UniValue in(UniValue::VOBJ); |
1179 | | // UTXOs |
1180 | 112 | bool have_a_utxo = false; |
1181 | 112 | CTxOut txout; |
1182 | 112 | if (!input.witness_utxo.IsNull()) { Branch (1182:13): [True: 6, False: 106]
|
1183 | 6 | txout = input.witness_utxo; |
1184 | | |
1185 | 6 | UniValue o(UniValue::VOBJ); |
1186 | 6 | ScriptToUniv(txout.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true); |
1187 | | |
1188 | 6 | UniValue out(UniValue::VOBJ); |
1189 | 6 | out.pushKV("amount", ValueFromAmount(txout.nValue)); |
1190 | 6 | out.pushKV("scriptPubKey", std::move(o)); |
1191 | | |
1192 | 6 | in.pushKV("witness_utxo", std::move(out)); |
1193 | | |
1194 | 6 | have_a_utxo = true; |
1195 | 6 | } |
1196 | 112 | if (input.non_witness_utxo) { Branch (1196:13): [True: 0, False: 112]
|
1197 | 0 | txout = input.non_witness_utxo->vout[input.prev_out]; |
1198 | |
|
1199 | 0 | UniValue non_wit(UniValue::VOBJ); |
1200 | 0 | TxToUniv(*input.non_witness_utxo, /*block_hash=*/uint256(), /*entry=*/non_wit, /*include_hex=*/false); |
1201 | 0 | in.pushKV("non_witness_utxo", std::move(non_wit)); |
1202 | |
|
1203 | 0 | have_a_utxo = true; |
1204 | 0 | } |
1205 | 112 | if (have_a_utxo) { Branch (1205:13): [True: 6, False: 106]
|
1206 | 6 | if (MoneyRange(txout.nValue) && MoneyRange(total_in + txout.nValue)) { Branch (1206:17): [True: 3, False: 3]
Branch (1206:17): [True: 3, False: 3]
Branch (1206:45): [True: 3, False: 0]
|
1207 | 3 | total_in += txout.nValue; |
1208 | 3 | } else { |
1209 | | // Hack to just not show fee later |
1210 | 3 | have_all_utxos = false; |
1211 | 3 | } |
1212 | 106 | } else { |
1213 | 106 | have_all_utxos = false; |
1214 | 106 | } |
1215 | | |
1216 | | // Partial sigs |
1217 | 112 | if (!input.partial_sigs.empty()) { Branch (1217:13): [True: 0, False: 112]
|
1218 | 0 | UniValue partial_sigs(UniValue::VOBJ); |
1219 | 0 | for (const auto& sig : input.partial_sigs) { Branch (1219:34): [True: 0, False: 0]
|
1220 | 0 | partial_sigs.pushKV(HexStr(sig.second.first), HexStr(sig.second.second)); |
1221 | 0 | } |
1222 | 0 | in.pushKV("partial_signatures", std::move(partial_sigs)); |
1223 | 0 | } |
1224 | | |
1225 | | // Sighash |
1226 | 112 | if (input.sighash_type != std::nullopt) { Branch (1226:13): [True: 5, False: 107]
|
1227 | 5 | in.pushKV("sighash", SighashToStr((unsigned char)*input.sighash_type)); |
1228 | 5 | } |
1229 | | |
1230 | | // Redeem script and witness script |
1231 | 112 | if (!input.redeem_script.empty()) { Branch (1231:13): [True: 17, False: 95]
|
1232 | 17 | UniValue r(UniValue::VOBJ); |
1233 | 17 | ScriptToUniv(input.redeem_script, /*out=*/r); |
1234 | 17 | in.pushKV("redeem_script", std::move(r)); |
1235 | 17 | } |
1236 | 112 | if (!input.witness_script.empty()) { Branch (1236:13): [True: 8, False: 104]
|
1237 | 8 | UniValue r(UniValue::VOBJ); |
1238 | 8 | ScriptToUniv(input.witness_script, /*out=*/r); |
1239 | 8 | in.pushKV("witness_script", std::move(r)); |
1240 | 8 | } |
1241 | | |
1242 | | // keypaths |
1243 | 112 | if (!input.hd_keypaths.empty()) { Branch (1243:13): [True: 5, False: 107]
|
1244 | 5 | UniValue keypaths(UniValue::VARR); |
1245 | 9 | for (auto entry : input.hd_keypaths) { Branch (1245:29): [True: 9, False: 5]
|
1246 | 9 | UniValue keypath(UniValue::VOBJ); |
1247 | 9 | keypath.pushKV("pubkey", HexStr(entry.first)); |
1248 | | |
1249 | 9 | keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint.data()))); |
1250 | 9 | keypath.pushKV("path", WriteHDKeypath(entry.second.path)); |
1251 | 9 | keypaths.push_back(std::move(keypath)); |
1252 | 9 | } |
1253 | 5 | in.pushKV("bip32_derivs", std::move(keypaths)); |
1254 | 5 | } |
1255 | | |
1256 | | // Final scriptSig and scriptwitness |
1257 | 112 | if (!input.final_script_sig.empty()) { Branch (1257:13): [True: 2, False: 110]
|
1258 | 2 | UniValue scriptsig(UniValue::VOBJ); |
1259 | 2 | scriptsig.pushKV("asm", ScriptToAsmStr(input.final_script_sig, true)); |
1260 | 2 | scriptsig.pushKV("hex", HexStr(input.final_script_sig)); |
1261 | 2 | in.pushKV("final_scriptSig", std::move(scriptsig)); |
1262 | 2 | } |
1263 | 112 | if (!input.final_script_witness.IsNull()) { Branch (1263:13): [True: 3, False: 109]
|
1264 | 3 | UniValue txinwitness(UniValue::VARR); |
1265 | 10 | for (const auto& item : input.final_script_witness.stack) { Branch (1265:35): [True: 10, False: 3]
|
1266 | 10 | txinwitness.push_back(HexStr(item)); |
1267 | 10 | } |
1268 | 3 | in.pushKV("final_scriptwitness", std::move(txinwitness)); |
1269 | 3 | } |
1270 | | |
1271 | | // Ripemd160 hash preimages |
1272 | 112 | if (!input.ripemd160_preimages.empty()) { Branch (1272:13): [True: 6, False: 106]
|
1273 | 6 | UniValue ripemd160_preimages(UniValue::VOBJ); |
1274 | 16 | for (const auto& [hash, preimage] : input.ripemd160_preimages) { Branch (1274:47): [True: 16, False: 6]
|
1275 | 16 | ripemd160_preimages.pushKV(HexStr(hash), HexStr(preimage)); |
1276 | 16 | } |
1277 | 6 | in.pushKV("ripemd160_preimages", std::move(ripemd160_preimages)); |
1278 | 6 | } |
1279 | | |
1280 | | // Sha256 hash preimages |
1281 | 112 | if (!input.sha256_preimages.empty()) { Branch (1281:13): [True: 6, False: 106]
|
1282 | 6 | UniValue sha256_preimages(UniValue::VOBJ); |
1283 | 20 | for (const auto& [hash, preimage] : input.sha256_preimages) { Branch (1283:47): [True: 20, False: 6]
|
1284 | 20 | sha256_preimages.pushKV(HexStr(hash), HexStr(preimage)); |
1285 | 20 | } |
1286 | 6 | in.pushKV("sha256_preimages", std::move(sha256_preimages)); |
1287 | 6 | } |
1288 | | |
1289 | | // Hash160 hash preimages |
1290 | 112 | if (!input.hash160_preimages.empty()) { Branch (1290:13): [True: 6, False: 106]
|
1291 | 6 | UniValue hash160_preimages(UniValue::VOBJ); |
1292 | 17 | for (const auto& [hash, preimage] : input.hash160_preimages) { Branch (1292:47): [True: 17, False: 6]
|
1293 | 17 | hash160_preimages.pushKV(HexStr(hash), HexStr(preimage)); |
1294 | 17 | } |
1295 | 6 | in.pushKV("hash160_preimages", std::move(hash160_preimages)); |
1296 | 6 | } |
1297 | | |
1298 | | // Hash256 hash preimages |
1299 | 112 | if (!input.hash256_preimages.empty()) { Branch (1299:13): [True: 10, False: 102]
|
1300 | 10 | UniValue hash256_preimages(UniValue::VOBJ); |
1301 | 36 | for (const auto& [hash, preimage] : input.hash256_preimages) { Branch (1301:47): [True: 36, False: 10]
|
1302 | 36 | hash256_preimages.pushKV(HexStr(hash), HexStr(preimage)); |
1303 | 36 | } |
1304 | 10 | in.pushKV("hash256_preimages", std::move(hash256_preimages)); |
1305 | 10 | } |
1306 | | |
1307 | | // PSBTv2 |
1308 | 112 | if (psbtx.GetVersion() >= 2) { Branch (1308:13): [True: 0, False: 112]
|
1309 | 0 | in.pushKV("previous_txid", input.prev_txid.GetHex()); |
1310 | 0 | in.pushKV("previous_vout", static_cast<uint64_t>(input.prev_out)); |
1311 | 0 | if (input.sequence.has_value()) { Branch (1311:17): [True: 0, False: 0]
|
1312 | 0 | in.pushKV("sequence", static_cast<uint64_t>(*input.sequence)); |
1313 | 0 | } |
1314 | 0 | if (input.time_locktime.has_value()) { Branch (1314:17): [True: 0, False: 0]
|
1315 | 0 | in.pushKV("time_locktime", static_cast<uint64_t>(*input.time_locktime)); |
1316 | 0 | } |
1317 | 0 | if (input.height_locktime.has_value()) { Branch (1317:17): [True: 0, False: 0]
|
1318 | 0 | in.pushKV("height_locktime", static_cast<uint64_t>(*input.height_locktime)); |
1319 | 0 | } |
1320 | 0 | } |
1321 | | |
1322 | | // Taproot key path signature |
1323 | 112 | if (!input.m_tap_key_sig.empty()) { Branch (1323:13): [True: 6, False: 106]
|
1324 | 6 | in.pushKV("taproot_key_path_sig", HexStr(input.m_tap_key_sig)); |
1325 | 6 | } |
1326 | | |
1327 | | // Taproot script path signatures |
1328 | 112 | if (!input.m_tap_script_sigs.empty()) { Branch (1328:13): [True: 8, False: 104]
|
1329 | 8 | UniValue script_sigs(UniValue::VARR); |
1330 | 33 | for (const auto& [pubkey_leaf, sig] : input.m_tap_script_sigs) { Branch (1330:49): [True: 33, False: 8]
|
1331 | 33 | const auto& [xonly, leaf_hash] = pubkey_leaf; |
1332 | 33 | UniValue sigobj(UniValue::VOBJ); |
1333 | 33 | sigobj.pushKV("pubkey", HexStr(xonly)); |
1334 | 33 | sigobj.pushKV("leaf_hash", HexStr(leaf_hash)); |
1335 | 33 | sigobj.pushKV("sig", HexStr(sig)); |
1336 | 33 | script_sigs.push_back(std::move(sigobj)); |
1337 | 33 | } |
1338 | 8 | in.pushKV("taproot_script_path_sigs", std::move(script_sigs)); |
1339 | 8 | } |
1340 | | |
1341 | | // Taproot leaf scripts |
1342 | 112 | if (!input.m_tap_scripts.empty()) { Branch (1342:13): [True: 14, False: 98]
|
1343 | 14 | UniValue tap_scripts(UniValue::VARR); |
1344 | 55 | for (const auto& [leaf, control_blocks] : input.m_tap_scripts) { Branch (1344:53): [True: 55, False: 14]
|
1345 | 55 | const auto& [script, leaf_ver] = leaf; |
1346 | 55 | UniValue script_info(UniValue::VOBJ); |
1347 | 55 | script_info.pushKV("script", HexStr(script)); |
1348 | 55 | script_info.pushKV("leaf_ver", leaf_ver); |
1349 | 55 | UniValue control_blocks_univ(UniValue::VARR); |
1350 | 70 | for (const auto& control_block : control_blocks) { Branch (1350:48): [True: 70, False: 55]
|
1351 | 70 | control_blocks_univ.push_back(HexStr(control_block)); |
1352 | 70 | } |
1353 | 55 | script_info.pushKV("control_blocks", std::move(control_blocks_univ)); |
1354 | 55 | tap_scripts.push_back(std::move(script_info)); |
1355 | 55 | } |
1356 | 14 | in.pushKV("taproot_scripts", std::move(tap_scripts)); |
1357 | 14 | } |
1358 | | |
1359 | | // Taproot bip32 keypaths |
1360 | 112 | if (!input.m_tap_bip32_paths.empty()) { Branch (1360:13): [True: 11, False: 101]
|
1361 | 11 | UniValue keypaths(UniValue::VARR); |
1362 | 22 | for (const auto& [xonly, leaf_origin] : input.m_tap_bip32_paths) { Branch (1362:51): [True: 22, False: 11]
|
1363 | 22 | const auto& [leaf_hashes, origin] = leaf_origin; |
1364 | 22 | UniValue path_obj(UniValue::VOBJ); |
1365 | 22 | path_obj.pushKV("pubkey", HexStr(xonly)); |
1366 | 22 | path_obj.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(origin.fingerprint.data()))); |
1367 | 22 | path_obj.pushKV("path", WriteHDKeypath(origin.path)); |
1368 | 22 | UniValue leaf_hashes_arr(UniValue::VARR); |
1369 | 29 | for (const auto& leaf_hash : leaf_hashes) { Branch (1369:44): [True: 29, False: 22]
|
1370 | 29 | leaf_hashes_arr.push_back(HexStr(leaf_hash)); |
1371 | 29 | } |
1372 | 22 | path_obj.pushKV("leaf_hashes", std::move(leaf_hashes_arr)); |
1373 | 22 | keypaths.push_back(std::move(path_obj)); |
1374 | 22 | } |
1375 | 11 | in.pushKV("taproot_bip32_derivs", std::move(keypaths)); |
1376 | 11 | } |
1377 | | |
1378 | | // Taproot internal key |
1379 | 112 | if (!input.m_tap_internal_key.IsNull()) { Branch (1379:13): [True: 1, False: 111]
|
1380 | 1 | in.pushKV("taproot_internal_key", HexStr(input.m_tap_internal_key)); |
1381 | 1 | } |
1382 | | |
1383 | | // Write taproot merkle root |
1384 | 112 | if (!input.m_tap_merkle_root.IsNull()) { Branch (1384:13): [True: 1, False: 111]
|
1385 | 1 | in.pushKV("taproot_merkle_root", HexStr(input.m_tap_merkle_root)); |
1386 | 1 | } |
1387 | | |
1388 | | // Write MuSig2 fields |
1389 | 112 | if (!input.m_musig2_participants.empty()) { Branch (1389:13): [True: 3, False: 109]
|
1390 | 3 | UniValue musig_pubkeys(UniValue::VARR); |
1391 | 3 | for (const auto& [agg, parts] : input.m_musig2_participants) { Branch (1391:43): [True: 3, False: 3]
|
1392 | 3 | UniValue musig_part(UniValue::VOBJ); |
1393 | 3 | musig_part.pushKV("aggregate_pubkey", HexStr(agg)); |
1394 | 3 | UniValue part_pubkeys(UniValue::VARR); |
1395 | 3 | for (const auto& pub : parts) { Branch (1395:38): [True: 3, False: 3]
|
1396 | 3 | part_pubkeys.push_back(HexStr(pub)); |
1397 | 3 | } |
1398 | 3 | musig_part.pushKV("participant_pubkeys", part_pubkeys); |
1399 | 3 | musig_pubkeys.push_back(musig_part); |
1400 | 3 | } |
1401 | 3 | in.pushKV("musig2_participant_pubkeys", musig_pubkeys); |
1402 | 3 | } |
1403 | 112 | if (!input.m_musig2_pubnonces.empty()) { Branch (1403:13): [True: 9, False: 103]
|
1404 | 9 | UniValue musig_pubnonces(UniValue::VARR); |
1405 | 20 | for (const auto& [agg_lh, part_pubnonce] : input.m_musig2_pubnonces) { Branch (1405:54): [True: 20, False: 9]
|
1406 | 20 | const auto& [agg, lh] = agg_lh; |
1407 | 21 | for (const auto& [part, pubnonce] : part_pubnonce) { Branch (1407:51): [True: 21, False: 20]
|
1408 | 21 | UniValue info(UniValue::VOBJ); |
1409 | 21 | info.pushKV("participant_pubkey", HexStr(part)); |
1410 | 21 | info.pushKV("aggregate_pubkey", HexStr(agg)); |
1411 | 21 | if (!lh.IsNull()) info.pushKV("leaf_hash", HexStr(lh)); Branch (1411:25): [True: 18, False: 3]
|
1412 | 21 | info.pushKV("pubnonce", HexStr(pubnonce)); |
1413 | 21 | musig_pubnonces.push_back(info); |
1414 | 21 | } |
1415 | 20 | } |
1416 | 9 | in.pushKV("musig2_pubnonces", musig_pubnonces); |
1417 | 9 | } |
1418 | 112 | if (!input.m_musig2_partial_sigs.empty()) { Branch (1418:13): [True: 8, False: 104]
|
1419 | 8 | UniValue musig_partial_sigs(UniValue::VARR); |
1420 | 16 | for (const auto& [agg_lh, part_psig] : input.m_musig2_partial_sigs) { Branch (1420:50): [True: 16, False: 8]
|
1421 | 16 | const auto& [agg, lh] = agg_lh; |
1422 | 17 | for (const auto& [part, psig] : part_psig) { Branch (1422:47): [True: 17, False: 16]
|
1423 | 17 | UniValue info(UniValue::VOBJ); |
1424 | 17 | info.pushKV("participant_pubkey", HexStr(part)); |
1425 | 17 | info.pushKV("aggregate_pubkey", HexStr(agg)); |
1426 | 17 | if (!lh.IsNull()) info.pushKV("leaf_hash", HexStr(lh)); Branch (1426:25): [True: 11, False: 6]
|
1427 | 17 | info.pushKV("partial_sig", HexStr(psig)); |
1428 | 17 | musig_partial_sigs.push_back(info); |
1429 | 17 | } |
1430 | 16 | } |
1431 | 8 | in.pushKV("musig2_partial_sigs", musig_partial_sigs); |
1432 | 8 | } |
1433 | | |
1434 | | // Proprietary |
1435 | 112 | if (!input.m_proprietary.empty()) { Branch (1435:13): [True: 7, False: 105]
|
1436 | 7 | UniValue proprietary(UniValue::VARR); |
1437 | 25 | for (const auto& entry : input.m_proprietary) { Branch (1437:36): [True: 25, False: 7]
|
1438 | 25 | UniValue this_prop(UniValue::VOBJ); |
1439 | 25 | this_prop.pushKV("identifier", HexStr(entry.identifier)); |
1440 | 25 | this_prop.pushKV("subtype", entry.subtype); |
1441 | 25 | this_prop.pushKV("key", HexStr(entry.key)); |
1442 | 25 | this_prop.pushKV("value", HexStr(entry.value)); |
1443 | 25 | proprietary.push_back(std::move(this_prop)); |
1444 | 25 | } |
1445 | 7 | in.pushKV("proprietary", std::move(proprietary)); |
1446 | 7 | } |
1447 | | |
1448 | | // Unknown data |
1449 | 112 | if (input.unknown.size() > 0) { Branch (1449:13): [True: 72, False: 40]
|
1450 | 72 | UniValue unknowns(UniValue::VOBJ); |
1451 | 553 | for (auto entry : input.unknown) { Branch (1451:29): [True: 553, False: 72]
|
1452 | 553 | unknowns.pushKV(HexStr(entry.first), HexStr(entry.second)); |
1453 | 553 | } |
1454 | 72 | in.pushKV("unknown", std::move(unknowns)); |
1455 | 72 | } |
1456 | | |
1457 | 112 | inputs.push_back(std::move(in)); |
1458 | 112 | } |
1459 | 166 | result.pushKV("inputs", std::move(inputs)); |
1460 | | |
1461 | | // outputs |
1462 | 166 | CAmount output_value = 0; |
1463 | 166 | UniValue outputs(UniValue::VARR); |
1464 | 268 | for (unsigned int i = 0; i < psbtx.outputs.size(); ++i) { Branch (1464:30): [True: 102, False: 166]
|
1465 | 102 | const PSBTOutput& output = psbtx.outputs[i]; |
1466 | 102 | UniValue out(UniValue::VOBJ); |
1467 | | // Redeem script and witness script |
1468 | 102 | if (!output.redeem_script.empty()) { Branch (1468:13): [True: 16, False: 86]
|
1469 | 16 | UniValue r(UniValue::VOBJ); |
1470 | 16 | ScriptToUniv(output.redeem_script, /*out=*/r); |
1471 | 16 | out.pushKV("redeem_script", std::move(r)); |
1472 | 16 | } |
1473 | 102 | if (!output.witness_script.empty()) { Branch (1473:13): [True: 20, False: 82]
|
1474 | 20 | UniValue r(UniValue::VOBJ); |
1475 | 20 | ScriptToUniv(output.witness_script, /*out=*/r); |
1476 | 20 | out.pushKV("witness_script", std::move(r)); |
1477 | 20 | } |
1478 | | |
1479 | | // keypaths |
1480 | 102 | if (!output.hd_keypaths.empty()) { Branch (1480:13): [True: 17, False: 85]
|
1481 | 17 | UniValue keypaths(UniValue::VARR); |
1482 | 46 | for (auto entry : output.hd_keypaths) { Branch (1482:29): [True: 46, False: 17]
|
1483 | 46 | UniValue keypath(UniValue::VOBJ); |
1484 | 46 | keypath.pushKV("pubkey", HexStr(entry.first)); |
1485 | 46 | keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint.data()))); |
1486 | 46 | keypath.pushKV("path", WriteHDKeypath(entry.second.path)); |
1487 | 46 | keypaths.push_back(std::move(keypath)); |
1488 | 46 | } |
1489 | 17 | out.pushKV("bip32_derivs", std::move(keypaths)); |
1490 | 17 | } |
1491 | | |
1492 | | // PSBTv2 stuff |
1493 | 102 | if (psbtx.GetVersion() >= 2) { Branch (1493:13): [True: 0, False: 102]
|
1494 | 0 | out.pushKV("amount", ValueFromAmount(output.amount)); |
1495 | 0 | UniValue spk(UniValue::VOBJ); |
1496 | 0 | ScriptToUniv(output.script, spk, /*include_hex=*/true, /*include_address=*/true); |
1497 | 0 | out.pushKV("script", spk); |
1498 | 0 | } |
1499 | | |
1500 | | // Taproot internal key |
1501 | 102 | if (!output.m_tap_internal_key.IsNull()) { Branch (1501:13): [True: 2, False: 100]
|
1502 | 2 | out.pushKV("taproot_internal_key", HexStr(output.m_tap_internal_key)); |
1503 | 2 | } |
1504 | | |
1505 | | // Taproot tree |
1506 | 102 | if (!output.m_tap_tree.empty()) { Branch (1506:13): [True: 6, False: 96]
|
1507 | 6 | UniValue tree(UniValue::VARR); |
1508 | 27 | for (const auto& [depth, leaf_ver, script] : output.m_tap_tree) { Branch (1508:56): [True: 27, False: 6]
|
1509 | 27 | UniValue elem(UniValue::VOBJ); |
1510 | 27 | elem.pushKV("depth", depth); |
1511 | 27 | elem.pushKV("leaf_ver", leaf_ver); |
1512 | 27 | elem.pushKV("script", HexStr(script)); |
1513 | 27 | tree.push_back(std::move(elem)); |
1514 | 27 | } |
1515 | 6 | out.pushKV("taproot_tree", std::move(tree)); |
1516 | 6 | } |
1517 | | |
1518 | | // Taproot bip32 keypaths |
1519 | 102 | if (!output.m_tap_bip32_paths.empty()) { Branch (1519:13): [True: 9, False: 93]
|
1520 | 9 | UniValue keypaths(UniValue::VARR); |
1521 | 19 | for (const auto& [xonly, leaf_origin] : output.m_tap_bip32_paths) { Branch (1521:51): [True: 19, False: 9]
|
1522 | 19 | const auto& [leaf_hashes, origin] = leaf_origin; |
1523 | 19 | UniValue path_obj(UniValue::VOBJ); |
1524 | 19 | path_obj.pushKV("pubkey", HexStr(xonly)); |
1525 | 19 | path_obj.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(origin.fingerprint.data()))); |
1526 | 19 | path_obj.pushKV("path", WriteHDKeypath(origin.path)); |
1527 | 19 | UniValue leaf_hashes_arr(UniValue::VARR); |
1528 | 28 | for (const auto& leaf_hash : leaf_hashes) { Branch (1528:44): [True: 28, False: 19]
|
1529 | 28 | leaf_hashes_arr.push_back(HexStr(leaf_hash)); |
1530 | 28 | } |
1531 | 19 | path_obj.pushKV("leaf_hashes", std::move(leaf_hashes_arr)); |
1532 | 19 | keypaths.push_back(std::move(path_obj)); |
1533 | 19 | } |
1534 | 9 | out.pushKV("taproot_bip32_derivs", std::move(keypaths)); |
1535 | 9 | } |
1536 | | |
1537 | | // Write MuSig2 fields |
1538 | 102 | if (!output.m_musig2_participants.empty()) { Branch (1538:13): [True: 7, False: 95]
|
1539 | 7 | UniValue musig_pubkeys(UniValue::VARR); |
1540 | 17 | for (const auto& [agg, parts] : output.m_musig2_participants) { Branch (1540:43): [True: 17, False: 7]
|
1541 | 17 | UniValue musig_part(UniValue::VOBJ); |
1542 | 17 | musig_part.pushKV("aggregate_pubkey", HexStr(agg)); |
1543 | 17 | UniValue part_pubkeys(UniValue::VARR); |
1544 | 17 | for (const auto& pub : parts) { Branch (1544:38): [True: 12, False: 17]
|
1545 | 12 | part_pubkeys.push_back(HexStr(pub)); |
1546 | 12 | } |
1547 | 17 | musig_part.pushKV("participant_pubkeys", part_pubkeys); |
1548 | 17 | musig_pubkeys.push_back(musig_part); |
1549 | 17 | } |
1550 | 7 | out.pushKV("musig2_participant_pubkeys", musig_pubkeys); |
1551 | 7 | } |
1552 | | |
1553 | | // Proprietary |
1554 | 102 | if (!output.m_proprietary.empty()) { Branch (1554:13): [True: 9, False: 93]
|
1555 | 9 | UniValue proprietary(UniValue::VARR); |
1556 | 32 | for (const auto& entry : output.m_proprietary) { Branch (1556:36): [True: 32, False: 9]
|
1557 | 32 | UniValue this_prop(UniValue::VOBJ); |
1558 | 32 | this_prop.pushKV("identifier", HexStr(entry.identifier)); |
1559 | 32 | this_prop.pushKV("subtype", entry.subtype); |
1560 | 32 | this_prop.pushKV("key", HexStr(entry.key)); |
1561 | 32 | this_prop.pushKV("value", HexStr(entry.value)); |
1562 | 32 | proprietary.push_back(std::move(this_prop)); |
1563 | 32 | } |
1564 | 9 | out.pushKV("proprietary", std::move(proprietary)); |
1565 | 9 | } |
1566 | | |
1567 | | // Unknown data |
1568 | 102 | if (output.unknown.size() > 0) { Branch (1568:13): [True: 43, False: 59]
|
1569 | 43 | UniValue unknowns(UniValue::VOBJ); |
1570 | 564 | for (auto entry : output.unknown) { Branch (1570:29): [True: 564, False: 43]
|
1571 | 564 | unknowns.pushKV(HexStr(entry.first), HexStr(entry.second)); |
1572 | 564 | } |
1573 | 43 | out.pushKV("unknown", std::move(unknowns)); |
1574 | 43 | } |
1575 | | |
1576 | 102 | outputs.push_back(std::move(out)); |
1577 | | |
1578 | | // Fee calculation |
1579 | 102 | if (MoneyRange(output.amount) && MoneyRange(output_value + output.amount)) { Branch (1579:13): [True: 30, False: 72]
Branch (1579:13): [True: 29, False: 73]
Branch (1579:42): [True: 29, False: 1]
|
1580 | 29 | output_value += output.amount; |
1581 | 73 | } else { |
1582 | | // Hack to just not show fee later |
1583 | 73 | have_all_utxos = false; |
1584 | 73 | } |
1585 | 102 | } |
1586 | 166 | result.pushKV("outputs", std::move(outputs)); |
1587 | 166 | if (have_all_utxos) { Branch (1587:9): [True: 6, False: 160]
|
1588 | 6 | result.pushKV("fee", ValueFromAmount(total_in - output_value)); |
1589 | 6 | } |
1590 | | |
1591 | 166 | return result; |
1592 | 176 | }, |
1593 | 530 | }; |
1594 | 530 | } |
1595 | | |
1596 | | static RPCMethod combinepsbt() |
1597 | 1.19k | { |
1598 | 1.19k | return RPCMethod{ |
1599 | 1.19k | "combinepsbt", |
1600 | 1.19k | "Combine multiple partially signed Bitcoin transactions into one transaction.\n" |
1601 | 1.19k | "Implements the Combiner role.\n", |
1602 | 1.19k | { |
1603 | 1.19k | {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions", |
1604 | 1.19k | { |
1605 | 1.19k | {"psbt", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A base64 string of a PSBT"}, |
1606 | 1.19k | }, |
1607 | 1.19k | }, |
1608 | 1.19k | }, |
1609 | 1.19k | RPCResult{ |
1610 | 1.19k | RPCResult::Type::STR, "", "The base64-encoded partially signed transaction" |
1611 | 1.19k | }, |
1612 | 1.19k | RPCExamples{ |
1613 | 1.19k | HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')") |
1614 | 1.19k | }, |
1615 | 1.19k | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1616 | 1.19k | { |
1617 | | // Unserialize the transactions |
1618 | 561 | std::vector<PartiallySignedTransaction> psbtxs; |
1619 | 561 | UniValue txs = request.params[0].get_array(); |
1620 | 561 | if (txs.empty()) { Branch (1620:9): [True: 0, False: 561]
|
1621 | 0 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter 'txs' cannot be empty"); |
1622 | 0 | } |
1623 | 11.1k | for (unsigned int i = 0; i < txs.size(); ++i) { Branch (1623:30): [True: 10.7k, False: 467]
|
1624 | 10.7k | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(txs[i].get_str()); |
1625 | 10.7k | if (!psbt_res) { Branch (1625:13): [True: 94, False: 10.6k]
|
1626 | 94 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
1627 | 94 | } |
1628 | 10.6k | psbtxs.push_back(*psbt_res); |
1629 | 10.6k | } |
1630 | | |
1631 | 467 | std::optional<PartiallySignedTransaction> merged_psbt = CombinePSBTs(psbtxs); |
1632 | 467 | if (!merged_psbt) { Branch (1632:9): [True: 63, False: 404]
|
1633 | 63 | throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs not compatible (different transactions)"); |
1634 | 63 | } |
1635 | | |
1636 | 404 | DataStream ssTx{}; |
1637 | 404 | ssTx << *merged_psbt; |
1638 | 404 | return EncodeBase64(ssTx); |
1639 | 467 | }, |
1640 | 1.19k | }; |
1641 | 1.19k | } |
1642 | | |
1643 | | static RPCMethod finalizepsbt() |
1644 | 582 | { |
1645 | 582 | return RPCMethod{"finalizepsbt", |
1646 | 582 | "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" |
1647 | 582 | "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" |
1648 | 582 | "created which has the final_scriptSig and final_scriptwitness fields filled for inputs that are complete.\n" |
1649 | 582 | "Implements the Finalizer and Extractor roles.\n", |
1650 | 582 | { |
1651 | 582 | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, |
1652 | 582 | {"extract", RPCArg::Type::BOOL, RPCArg::Default{true}, "If true and the transaction is complete,\n" |
1653 | 582 | " extract and return the complete transaction in normal network serialization instead of the PSBT."}, |
1654 | 582 | }, |
1655 | 582 | RPCResult{ |
1656 | 582 | RPCResult::Type::OBJ, "", "", |
1657 | 582 | { |
1658 | 582 | {RPCResult::Type::STR, "psbt", /*optional=*/true, "The base64-encoded partially signed transaction if not extracted"}, |
1659 | 582 | {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The hex-encoded network transaction if extracted"}, |
1660 | 582 | {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"}, |
1661 | 582 | } |
1662 | 582 | }, |
1663 | 582 | RPCExamples{ |
1664 | 582 | HelpExampleCli("finalizepsbt", "\"psbt\"") |
1665 | 582 | }, |
1666 | 582 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1667 | 582 | { |
1668 | | // Unserialize the transactions |
1669 | 293 | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(request.params[0].get_str()); |
1670 | 293 | if (!psbt_res) { Branch (1670:9): [True: 41, False: 252]
|
1671 | 41 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
1672 | 41 | } |
1673 | 252 | PartiallySignedTransaction psbtx = *psbt_res; |
1674 | | |
1675 | 252 | bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool()); Branch (1675:20): [True: 247, False: 5]
Branch (1675:51): [True: 5, False: 0]
Branch (1675:82): [True: 0, False: 5]
|
1676 | | |
1677 | 252 | CMutableTransaction mtx; |
1678 | 252 | bool complete = FinalizeAndExtractPSBT(psbtx, mtx); |
1679 | | |
1680 | 252 | UniValue result(UniValue::VOBJ); |
1681 | 252 | DataStream ssTx{}; |
1682 | 252 | std::string result_str; |
1683 | | |
1684 | 252 | if (complete && extract) { Branch (1684:9): [True: 10, False: 242]
Branch (1684:21): [True: 9, False: 1]
|
1685 | 9 | ssTx << TX_WITH_WITNESS(mtx); |
1686 | 9 | result_str = HexStr(ssTx); |
1687 | 9 | result.pushKV("hex", result_str); |
1688 | 243 | } else { |
1689 | 243 | ssTx << psbtx; |
1690 | 243 | result_str = EncodeBase64(ssTx.str()); |
1691 | 243 | result.pushKV("psbt", result_str); |
1692 | 243 | } |
1693 | 252 | result.pushKV("complete", complete); |
1694 | | |
1695 | 252 | return result; |
1696 | 293 | }, |
1697 | 582 | }; |
1698 | 582 | } |
1699 | | |
1700 | | static RPCMethod createpsbt() |
1701 | 235 | { |
1702 | 235 | return RPCMethod{ |
1703 | 235 | "createpsbt", |
1704 | 235 | "Creates a transaction in the Partially Signed Transaction format.\n" |
1705 | 235 | "Implements the Creator role.\n" |
1706 | 235 | "Note that the transaction's inputs are not signed, and\n" |
1707 | 235 | "it is not stored in the wallet or transmitted to the network.\n", |
1708 | 235 | Cat<std::vector<RPCArg>>( |
1709 | 235 | CreateTxDoc(), |
1710 | 235 | { |
1711 | 235 | {"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use."}, |
1712 | 235 | } |
1713 | 235 | ), |
1714 | 235 | RPCResult{ |
1715 | 235 | RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)" |
1716 | 235 | }, |
1717 | 235 | RPCExamples{ |
1718 | 235 | HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"") |
1719 | 235 | }, |
1720 | 235 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1721 | 235 | { |
1722 | 129 | std::optional<bool> rbf; |
1723 | 129 | if (!request.params[3].isNull()) { Branch (1723:9): [True: 8, False: 121]
|
1724 | 8 | rbf = request.params[3].get_bool(); |
1725 | 8 | } |
1726 | 129 | CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf, self.Arg<uint32_t>("version")); |
1727 | | |
1728 | | // Make a blank psbt |
1729 | 129 | uint32_t psbt_version = 2; |
1730 | 129 | if (!request.params[5].isNull()) { Branch (1730:9): [True: 0, False: 129]
|
1731 | 0 | psbt_version = request.params[5].getInt<uint32_t>(); |
1732 | 0 | } |
1733 | 129 | if (psbt_version != 2 && psbt_version != 0) { Branch (1733:9): [True: 0, False: 129]
Branch (1733:30): [True: 0, False: 0]
|
1734 | 0 | throw JSONRPCError(RPC_INVALID_PARAMETER, "The PSBT version can only be 2 or 0"); |
1735 | 0 | } |
1736 | 129 | PartiallySignedTransaction psbtx(rawTx, psbt_version); |
1737 | | |
1738 | | // Serialize the PSBT |
1739 | 129 | DataStream ssTx{}; |
1740 | 129 | ssTx << psbtx; |
1741 | | |
1742 | 129 | return EncodeBase64(ssTx); |
1743 | 129 | }, |
1744 | 235 | }; |
1745 | 235 | } |
1746 | | |
1747 | | static RPCMethod converttopsbt() |
1748 | 189 | { |
1749 | 189 | return RPCMethod{ |
1750 | 189 | "converttopsbt", |
1751 | 189 | "Converts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" |
1752 | 189 | "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", |
1753 | 189 | { |
1754 | 189 | {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of a raw transaction"}, |
1755 | 189 | {"permitsigdata", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, any signatures in the input will be discarded and conversion\n" |
1756 | 189 | " will continue. If false, RPC will fail if any signatures are present."}, |
1757 | 189 | {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n" |
1758 | 189 | "If iswitness is not present, heuristic tests will be used in decoding.\n" |
1759 | 189 | "If true, only witness deserialization will be tried.\n" |
1760 | 189 | "If false, only non-witness deserialization will be tried.\n" |
1761 | 189 | "This boolean should reflect whether the transaction has inputs\n" |
1762 | 189 | "(e.g. fully valid, or on-chain transactions), if known by the caller." |
1763 | 189 | }, |
1764 | 189 | {"psbt_version", RPCArg::Type::NUM, RPCArg::Default{2}, "The PSBT version number to use."}, |
1765 | 189 | }, |
1766 | 189 | RPCResult{ |
1767 | 189 | RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)" |
1768 | 189 | }, |
1769 | 189 | RPCExamples{ |
1770 | 189 | "\nCreate a transaction\n" |
1771 | 189 | + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") + |
1772 | 189 | "\nConvert the transaction to a PSBT\n" |
1773 | 189 | + HelpExampleCli("converttopsbt", "\"rawtransaction\"") |
1774 | 189 | }, |
1775 | 189 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1776 | 189 | { |
1777 | | // parse hex string from parameter |
1778 | 93 | CMutableTransaction tx; |
1779 | 93 | bool permitsigdata = request.params[1].isNull() ? false : request.params[1].get_bool(); Branch (1779:26): [True: 40, False: 53]
|
1780 | 93 | bool witness_specified = !request.params[2].isNull(); |
1781 | 93 | bool iswitness = witness_specified ? request.params[2].get_bool() : false; Branch (1781:22): [True: 34, False: 59]
|
1782 | 93 | const bool try_witness = witness_specified ? iswitness : true; Branch (1782:30): [True: 34, False: 59]
|
1783 | 93 | const bool try_no_witness = witness_specified ? !iswitness : true; Branch (1783:33): [True: 34, False: 59]
|
1784 | 93 | if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) { Branch (1784:9): [True: 21, False: 72]
|
1785 | 21 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
1786 | 21 | } |
1787 | | |
1788 | | // Remove all scriptSigs and scriptWitnesses from inputs |
1789 | 1.11k | for (CTxIn& input : tx.vin) { Branch (1789:23): [True: 1.11k, False: 65]
|
1790 | 1.11k | if ((!input.scriptSig.empty() || !input.scriptWitness.IsNull()) && !permitsigdata) { Branch (1790:14): [True: 707, False: 409]
Branch (1790:42): [True: 74, False: 335]
Branch (1790:76): [True: 7, False: 774]
|
1791 | 7 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Inputs must not have scriptSigs and scriptWitnesses"); |
1792 | 7 | } |
1793 | 1.10k | input.scriptSig.clear(); |
1794 | 1.10k | input.scriptWitness.SetNull(); |
1795 | 1.10k | } |
1796 | | |
1797 | | // Make a blank psbt |
1798 | 65 | uint32_t psbt_version = 2; |
1799 | 65 | if (!request.params[3].isNull()) { Branch (1799:9): [True: 33, False: 32]
|
1800 | 33 | psbt_version = request.params[3].getInt<uint32_t>(); |
1801 | 33 | } |
1802 | 65 | if (psbt_version != 2 && psbt_version != 0) { Branch (1802:9): [True: 32, False: 33]
Branch (1802:30): [True: 1, False: 31]
|
1803 | 1 | throw JSONRPCError(RPC_INVALID_PARAMETER, "The PSBT version can only be 2 or 0"); |
1804 | 1 | } |
1805 | 64 | PartiallySignedTransaction psbtx(tx, psbt_version); |
1806 | | |
1807 | | // Serialize the PSBT |
1808 | 64 | DataStream ssTx{}; |
1809 | 64 | ssTx << psbtx; |
1810 | | |
1811 | 64 | return EncodeBase64(ssTx); |
1812 | 65 | }, |
1813 | 189 | }; |
1814 | 189 | } |
1815 | | |
1816 | | static RPCMethod utxoupdatepsbt() |
1817 | 857 | { |
1818 | 857 | return RPCMethod{ |
1819 | 857 | "utxoupdatepsbt", |
1820 | 857 | "Updates all segwit inputs and outputs in a PSBT with data from output descriptors, the UTXO set, txindex, or the mempool.\n", |
1821 | 857 | { |
1822 | 857 | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, |
1823 | 857 | {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "An array of either strings or objects", { |
1824 | 857 | {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"}, |
1825 | 857 | {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", { |
1826 | 857 | {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, |
1827 | 857 | {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"}, |
1828 | 857 | }}, |
1829 | 857 | }}, |
1830 | 857 | }, |
1831 | 857 | RPCResult { |
1832 | 857 | RPCResult::Type::STR, "", "The base64-encoded partially signed transaction with inputs updated" |
1833 | 857 | }, |
1834 | 857 | RPCExamples { |
1835 | 857 | HelpExampleCli("utxoupdatepsbt", "\"psbt\"") |
1836 | 857 | }, |
1837 | 857 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1838 | 857 | { |
1839 | | // Parse descriptors, if any. |
1840 | 511 | FlatSigningProvider provider; |
1841 | 511 | if (!request.params[1].isNull()) { Branch (1841:9): [True: 54, False: 457]
|
1842 | 54 | auto descs = request.params[1].get_array(); |
1843 | 107 | for (size_t i = 0; i < descs.size(); ++i) { Branch (1843:28): [True: 53, False: 54]
|
1844 | 53 | EvalDescriptorStringOrObject(descs[i], provider); |
1845 | 53 | } |
1846 | 54 | } |
1847 | | |
1848 | | // We don't actually need private keys further on; hide them as a precaution. |
1849 | 511 | const PartiallySignedTransaction& psbtx = ProcessPSBT( |
1850 | 511 | request.params[0].get_str(), |
1851 | 511 | request.context, |
1852 | 511 | HidingSigningProvider(&provider, /*hide_secret=*/true, /*hide_origin=*/false), |
1853 | 511 | /*sighash_type=*/std::nullopt, |
1854 | 511 | /*finalize=*/false); |
1855 | | |
1856 | 511 | DataStream ssTx{}; |
1857 | 511 | ssTx << psbtx; |
1858 | 511 | return EncodeBase64(ssTx); |
1859 | 511 | }, |
1860 | 857 | }; |
1861 | 857 | } |
1862 | | |
1863 | | static RPCMethod joinpsbts() |
1864 | 384 | { |
1865 | 384 | return RPCMethod{ |
1866 | 384 | "joinpsbts", |
1867 | 384 | "Joins multiple distinct version 0 PSBTs with different inputs and outputs into one version 0 PSBT with inputs and outputs from all of the PSBTs\n" |
1868 | 384 | "No input in any of the PSBTs can be in more than one of the PSBTs.\n", |
1869 | 384 | { |
1870 | 384 | {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions", |
1871 | 384 | { |
1872 | 384 | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} |
1873 | 384 | }} |
1874 | 384 | }, |
1875 | 384 | RPCResult { |
1876 | 384 | RPCResult::Type::STR, "", "The base64-encoded partially signed transaction" |
1877 | 384 | }, |
1878 | 384 | RPCExamples { |
1879 | 384 | HelpExampleCli("joinpsbts", "\"psbt\"") |
1880 | 384 | }, |
1881 | 384 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1882 | 384 | { |
1883 | | // Unserialize the transactions |
1884 | 26 | std::vector<PartiallySignedTransaction> psbtxs; |
1885 | 26 | UniValue txs = request.params[0].get_array(); |
1886 | | |
1887 | 26 | if (txs.size() <= 1) { Branch (1887:9): [True: 14, False: 12]
|
1888 | 14 | throw JSONRPCError(RPC_INVALID_PARAMETER, "At least two PSBTs are required to join PSBTs."); |
1889 | 14 | } |
1890 | | |
1891 | 12 | uint32_t best_version = 1; |
1892 | 12 | uint32_t best_locktime = 0xffffffff; |
1893 | 25 | for (unsigned int i = 0; i < txs.size(); ++i) { Branch (1893:30): [True: 18, False: 7]
|
1894 | 18 | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(txs[i].get_str()); |
1895 | 18 | if (!psbt_res) { Branch (1895:13): [True: 5, False: 13]
|
1896 | 5 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
1897 | 5 | } |
1898 | 13 | psbtxs.push_back(*psbt_res); |
1899 | 13 | const PartiallySignedTransaction& psbtx = psbtxs.back(); |
1900 | 13 | if (psbtx.GetVersion() != 0) { Branch (1900:13): [True: 0, False: 13]
|
1901 | 0 | throw JSONRPCError(RPC_INVALID_PARAMETER, "joinpsbts only operates on version 0 PSBTs"); |
1902 | 0 | } |
1903 | | // Choose the highest version number |
1904 | 13 | if (psbtx.tx_version > best_version) { Branch (1904:13): [True: 8, False: 5]
|
1905 | 8 | best_version = psbtx.tx_version; |
1906 | 8 | } |
1907 | | // Choose the lowest lock time |
1908 | 13 | uint32_t psbt_locktime = psbtx.fallback_locktime.value_or(0); |
1909 | 13 | if (psbt_locktime < best_locktime) { Branch (1909:13): [True: 7, False: 6]
|
1910 | 7 | best_locktime = psbt_locktime; |
1911 | 7 | } |
1912 | 13 | } |
1913 | | |
1914 | | // Create a blank psbt where everything will be added |
1915 | 7 | CMutableTransaction tx; |
1916 | 7 | tx.version = best_version; |
1917 | 7 | tx.nLockTime = best_locktime; |
1918 | 7 | PartiallySignedTransaction merged_psbt(tx, psbtxs.at(0).GetVersion()); |
1919 | | |
1920 | | // Merge |
1921 | 7 | for (auto& psbt : psbtxs) { Branch (1921:21): [True: 6, False: 7]
|
1922 | 6 | for (const PSBTInput& input : psbt.inputs) { Branch (1922:37): [True: 0, False: 6]
|
1923 | 0 | if (!merged_psbt.AddInput(input)) { Branch (1923:17): [True: 0, False: 0]
|
1924 | 0 | throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input %s:%d exists in multiple PSBTs", input.prev_txid.ToString(), input.prev_out)); |
1925 | 0 | } |
1926 | 0 | } |
1927 | 7 | for (const PSBTOutput& output : psbt.outputs) { Branch (1927:39): [True: 7, False: 6]
|
1928 | 7 | merged_psbt.AddOutput(output); |
1929 | 7 | } |
1930 | 6 | merged_psbt.MergeGlobalXPubs(psbt); |
1931 | 6 | merged_psbt.m_proprietary.insert(psbt.m_proprietary.begin(), psbt.m_proprietary.end()); |
1932 | 6 | merged_psbt.unknown.insert(psbt.unknown.begin(), psbt.unknown.end()); |
1933 | 6 | } |
1934 | | |
1935 | | // Shuffle the inputs and outputs for privacy |
1936 | 7 | std::shuffle(merged_psbt.inputs.begin(), merged_psbt.inputs.end(), FastRandomContext()); |
1937 | 7 | std::shuffle(merged_psbt.outputs.begin(), merged_psbt.outputs.end(), FastRandomContext()); |
1938 | | |
1939 | 7 | DataStream ssTx{}; |
1940 | 7 | ssTx << merged_psbt; |
1941 | 7 | return EncodeBase64(ssTx); |
1942 | 7 | }, |
1943 | 384 | }; |
1944 | 384 | } |
1945 | | |
1946 | | static RPCMethod analyzepsbt() |
1947 | 1.29k | { |
1948 | 1.29k | return RPCMethod{ |
1949 | 1.29k | "analyzepsbt", |
1950 | 1.29k | "Analyzes and provides information about the current status of a PSBT and its inputs\n", |
1951 | 1.29k | { |
1952 | 1.29k | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} |
1953 | 1.29k | }, |
1954 | 1.29k | RPCResult { |
1955 | 1.29k | RPCResult::Type::OBJ, "", "", |
1956 | 1.29k | { |
1957 | 1.29k | {RPCResult::Type::ARR, "inputs", /*optional=*/true, "", |
1958 | 1.29k | { |
1959 | 1.29k | {RPCResult::Type::OBJ, "", "", |
1960 | 1.29k | { |
1961 | 1.29k | {RPCResult::Type::BOOL, "has_utxo", "Whether a UTXO is provided"}, |
1962 | 1.29k | {RPCResult::Type::BOOL, "is_final", "Whether the input is finalized"}, |
1963 | 1.29k | {RPCResult::Type::OBJ, "missing", /*optional=*/true, "Things that are missing that are required to complete this input", |
1964 | 1.29k | { |
1965 | 1.29k | {RPCResult::Type::ARR, "pubkeys", /*optional=*/true, "", |
1966 | 1.29k | { |
1967 | 1.29k | {RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose BIP 32 derivation path is missing"}, |
1968 | 1.29k | }}, |
1969 | 1.29k | {RPCResult::Type::ARR, "signatures", /*optional=*/true, "", |
1970 | 1.29k | { |
1971 | 1.29k | {RPCResult::Type::STR_HEX, "keyid", "Public key ID, hash160 of the public key, of a public key whose signature is missing"}, |
1972 | 1.29k | }}, |
1973 | 1.29k | {RPCResult::Type::STR_HEX, "redeemscript", /*optional=*/true, "Hash160 of the redeem script that is missing"}, |
1974 | 1.29k | {RPCResult::Type::STR_HEX, "witnessscript", /*optional=*/true, "SHA256 of the witness script that is missing"}, |
1975 | 1.29k | }}, |
1976 | 1.29k | {RPCResult::Type::STR, "next", /*optional=*/true, "Role of the next person that this input needs to go to"}, |
1977 | 1.29k | }}, |
1978 | 1.29k | }}, |
1979 | 1.29k | {RPCResult::Type::NUM, "estimated_vsize", /*optional=*/true, "Estimated vsize of the final signed transaction"}, |
1980 | 1.29k | {RPCResult::Type::STR_AMOUNT, "estimated_feerate", /*optional=*/true, "Estimated feerate of the final signed transaction in " + CURRENCY_UNIT + "/kvB. Shown only if all UTXO slots in the PSBT have been filled"}, |
1981 | 1.29k | {RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true, "The transaction fee paid. Shown only if all UTXO slots in the PSBT have been filled"}, |
1982 | 1.29k | {RPCResult::Type::STR, "next", "Role of the next person that this psbt needs to go to"}, |
1983 | 1.29k | {RPCResult::Type::STR, "error", /*optional=*/true, "Error message (if there is one)"}, |
1984 | 1.29k | } |
1985 | 1.29k | }, |
1986 | 1.29k | RPCExamples { |
1987 | 1.29k | HelpExampleCli("analyzepsbt", "\"psbt\"") |
1988 | 1.29k | }, |
1989 | 1.29k | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
1990 | 1.29k | { |
1991 | | // Unserialize the transaction |
1992 | 296 | util::Result<PartiallySignedTransaction> psbt_res = DecodeBase64PSBT(request.params[0].get_str()); |
1993 | 296 | if (!psbt_res) { Branch (1993:9): [True: 182, False: 114]
|
1994 | 182 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", util::ErrorString(psbt_res).original)); |
1995 | 182 | } |
1996 | 114 | const PartiallySignedTransaction& psbtx = *psbt_res; |
1997 | | |
1998 | 114 | PSBTAnalysis psbta = AnalyzePSBT(psbtx); |
1999 | | |
2000 | 114 | UniValue result(UniValue::VOBJ); |
2001 | 114 | UniValue inputs_result(UniValue::VARR); |
2002 | 114 | for (const auto& input : psbta.inputs) { Branch (2002:28): [True: 66, False: 114]
|
2003 | 66 | UniValue input_univ(UniValue::VOBJ); |
2004 | 66 | UniValue missing(UniValue::VOBJ); |
2005 | | |
2006 | 66 | input_univ.pushKV("has_utxo", input.has_utxo); |
2007 | 66 | input_univ.pushKV("is_final", input.is_final); |
2008 | 66 | input_univ.pushKV("next", PSBTRoleName(input.next)); |
2009 | | |
2010 | 66 | if (!input.missing_pubkeys.empty()) { Branch (2010:13): [True: 0, False: 66]
|
2011 | 0 | UniValue missing_pubkeys_univ(UniValue::VARR); |
2012 | 0 | for (const CKeyID& pubkey : input.missing_pubkeys) { Branch (2012:39): [True: 0, False: 0]
|
2013 | 0 | missing_pubkeys_univ.push_back(HexStr(pubkey)); |
2014 | 0 | } |
2015 | 0 | missing.pushKV("pubkeys", std::move(missing_pubkeys_univ)); |
2016 | 0 | } |
2017 | 66 | if (!input.missing_redeem_script.IsNull()) { Branch (2017:13): [True: 0, False: 66]
|
2018 | 0 | missing.pushKV("redeemscript", HexStr(input.missing_redeem_script)); |
2019 | 0 | } |
2020 | 66 | if (!input.missing_witness_script.IsNull()) { Branch (2020:13): [True: 0, False: 66]
|
2021 | 0 | missing.pushKV("witnessscript", HexStr(input.missing_witness_script)); |
2022 | 0 | } |
2023 | 66 | if (!input.missing_sigs.empty()) { Branch (2023:13): [True: 0, False: 66]
|
2024 | 0 | UniValue missing_sigs_univ(UniValue::VARR); |
2025 | 0 | for (const CKeyID& pubkey : input.missing_sigs) { Branch (2025:39): [True: 0, False: 0]
|
2026 | 0 | missing_sigs_univ.push_back(HexStr(pubkey)); |
2027 | 0 | } |
2028 | 0 | missing.pushKV("signatures", std::move(missing_sigs_univ)); |
2029 | 0 | } |
2030 | 66 | if (!missing.getKeys().empty()) { Branch (2030:13): [True: 0, False: 66]
|
2031 | 0 | input_univ.pushKV("missing", std::move(missing)); |
2032 | 0 | } |
2033 | 66 | inputs_result.push_back(std::move(input_univ)); |
2034 | 66 | } |
2035 | 114 | if (!inputs_result.empty()) result.pushKV("inputs", std::move(inputs_result)); Branch (2035:9): [True: 66, False: 48]
|
2036 | | |
2037 | 114 | if (psbta.estimated_vsize != std::nullopt) { Branch (2037:9): [True: 46, False: 68]
|
2038 | 46 | result.pushKV("estimated_vsize", *psbta.estimated_vsize); |
2039 | 46 | } |
2040 | 114 | if (psbta.estimated_feerate != std::nullopt) { Branch (2040:9): [True: 46, False: 68]
|
2041 | 46 | result.pushKV("estimated_feerate", ValueFromAmount(psbta.estimated_feerate->GetFeePerK())); |
2042 | 46 | } |
2043 | 114 | if (psbta.fee != std::nullopt) { Branch (2043:9): [True: 101, False: 13]
|
2044 | 101 | result.pushKV("fee", ValueFromAmount(*psbta.fee)); |
2045 | 101 | } |
2046 | 114 | result.pushKV("next", PSBTRoleName(psbta.next)); |
2047 | 114 | if (!psbta.error.empty()) { Branch (2047:9): [True: 8, False: 106]
|
2048 | 8 | result.pushKV("error", psbta.error); |
2049 | 8 | } |
2050 | | |
2051 | 114 | return result; |
2052 | 296 | }, |
2053 | 1.29k | }; |
2054 | 1.29k | } |
2055 | | |
2056 | | RPCMethod descriptorprocesspsbt() |
2057 | 205 | { |
2058 | 205 | return RPCMethod{ |
2059 | 205 | "descriptorprocesspsbt", |
2060 | 205 | "Update all segwit inputs in a PSBT with information from output descriptors, the UTXO set or the mempool. \n" |
2061 | 205 | "Then, sign the inputs we are able to with information from the output descriptors. ", |
2062 | 205 | { |
2063 | 205 | {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"}, |
2064 | 205 | {"descriptors", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of either strings or objects", { |
2065 | 205 | {"", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"}, |
2066 | 205 | {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with an output descriptor and extra information", { |
2067 | 205 | {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"}, |
2068 | 205 | {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "Up to what index HD chains should be explored (either end or [begin,end])"}, |
2069 | 205 | }}, |
2070 | 205 | }}, |
2071 | 205 | {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT for Taproot, ALL otherwise"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n" |
2072 | 205 | " \"DEFAULT\"\n" |
2073 | 205 | " \"ALL\"\n" |
2074 | 205 | " \"NONE\"\n" |
2075 | 205 | " \"SINGLE\"\n" |
2076 | 205 | " \"ALL|ANYONECANPAY\"\n" |
2077 | 205 | " \"NONE|ANYONECANPAY\"\n" |
2078 | 205 | " \"SINGLE|ANYONECANPAY\""}, |
2079 | 205 | {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"}, |
2080 | 205 | {"finalize", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also finalize inputs if possible"}, |
2081 | 205 | }, |
2082 | 205 | RPCResult{ |
2083 | 205 | RPCResult::Type::OBJ, "", "", |
2084 | 205 | { |
2085 | 205 | {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"}, |
2086 | 205 | {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"}, |
2087 | 205 | {RPCResult::Type::STR_HEX, "hex", /*optional=*/true, "The hex-encoded network transaction if complete"}, |
2088 | 205 | } |
2089 | 205 | }, |
2090 | 205 | RPCExamples{ |
2091 | 205 | HelpExampleCli("descriptorprocesspsbt", "\"psbt\" \"[\\\"descriptor1\\\", \\\"descriptor2\\\"]\"") + |
2092 | 205 | HelpExampleCli("descriptorprocesspsbt", "\"psbt\" \"[{\\\"desc\\\":\\\"mydescriptor\\\", \\\"range\\\":21}]\"") |
2093 | 205 | }, |
2094 | 205 | [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue |
2095 | 205 | { |
2096 | | // Add descriptor information to a signing provider |
2097 | 54 | FlatSigningProvider provider; |
2098 | | |
2099 | 54 | auto descs = request.params[1].get_array(); |
2100 | 89 | for (size_t i = 0; i < descs.size(); ++i) { Branch (2100:24): [True: 35, False: 54]
|
2101 | 35 | EvalDescriptorStringOrObject(descs[i], provider, /*expand_priv=*/true); |
2102 | 35 | } |
2103 | | |
2104 | 54 | std::optional<int> sighash_type = ParseSighashString(request.params[2]); |
2105 | 54 | bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool(); Branch (2105:24): [True: 16, False: 38]
|
2106 | 54 | bool finalize = request.params[4].isNull() ? true : request.params[4].get_bool(); Branch (2106:21): [True: 16, False: 38]
|
2107 | | |
2108 | 54 | const PartiallySignedTransaction& psbtx = ProcessPSBT( |
2109 | 54 | request.params[0].get_str(), |
2110 | 54 | request.context, |
2111 | 54 | HidingSigningProvider(&provider, /*hide_secret=*/false, !bip32derivs), |
2112 | 54 | sighash_type, |
2113 | 54 | finalize); |
2114 | | |
2115 | | // Check whether or not all of the inputs are now correctly signed |
2116 | 54 | bool complete = true; |
2117 | 54 | const std::optional<PrecomputedTransactionData> txdata_opt{PrecomputePSBTData(psbtx)}; |
2118 | 54 | const PrecomputedTransactionData txdata{*CHECK_NONFATAL(txdata_opt)}; |
2119 | 55 | for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) { Branch (2119:30): [True: 1, False: 54]
|
2120 | 1 | complete = complete && PSBTInputSignedAndVerified(psbtx, i, &txdata); Branch (2120:20): [True: 1, False: 0]
Branch (2120:32): [True: 0, False: 1]
|
2121 | 1 | } |
2122 | | |
2123 | 54 | DataStream ssTx{}; |
2124 | 54 | ssTx << psbtx; |
2125 | | |
2126 | 54 | UniValue result(UniValue::VOBJ); |
2127 | | |
2128 | 54 | result.pushKV("psbt", EncodeBase64(ssTx)); |
2129 | 54 | result.pushKV("complete", complete); |
2130 | 54 | if (complete) { Branch (2130:9): [True: 9, False: 45]
|
2131 | 9 | CMutableTransaction mtx; |
2132 | 9 | PartiallySignedTransaction psbtx_copy = psbtx; |
2133 | 9 | CHECK_NONFATAL(FinalizeAndExtractPSBT(psbtx_copy, mtx)); |
2134 | 9 | DataStream ssTx_final; |
2135 | 9 | ssTx_final << TX_WITH_WITNESS(mtx); |
2136 | 9 | result.pushKV("hex", HexStr(ssTx_final)); |
2137 | 9 | } |
2138 | 54 | return result; |
2139 | 54 | }, |
2140 | 205 | }; |
2141 | 205 | } |
2142 | | |
2143 | | void RegisterRawTransactionRPCCommands(CRPCTable& t) |
2144 | 0 | { |
2145 | 0 | static const CRPCCommand commands[]{ |
2146 | 0 | {"rawtransactions", &getrawtransaction}, |
2147 | 0 | {"rawtransactions", &createrawtransaction}, |
2148 | 0 | {"rawtransactions", &decoderawtransaction}, |
2149 | 0 | {"rawtransactions", &decodescript}, |
2150 | 0 | {"rawtransactions", &combinerawtransaction}, |
2151 | 0 | {"rawtransactions", &signrawtransactionwithkey}, |
2152 | 0 | {"rawtransactions", &decodepsbt}, |
2153 | 0 | {"rawtransactions", &combinepsbt}, |
2154 | 0 | {"rawtransactions", &finalizepsbt}, |
2155 | 0 | {"rawtransactions", &createpsbt}, |
2156 | 0 | {"rawtransactions", &converttopsbt}, |
2157 | 0 | {"rawtransactions", &utxoupdatepsbt}, |
2158 | 0 | {"rawtransactions", &descriptorprocesspsbt}, |
2159 | 0 | {"rawtransactions", &joinpsbts}, |
2160 | 0 | {"rawtransactions", &analyzepsbt}, |
2161 | 0 | }; |
2162 | 0 | for (const auto& c : commands) { Branch (2162:24): [True: 0, False: 0]
|
2163 | 0 | t.appendCommand(c.name, &c); |
2164 | 0 | } |
2165 | 0 | } |