psbt.cpp raw
1 // Copyright (c) 2009-2022 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <psbt.h>
6
7 #include <node/types.h>
8 #include <policy/policy.h>
9 #include <script/signingprovider.h>
10 #include <util/check.h>
11 #include <util/strencodings.h>
12
13 PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
14 {
15 inputs.resize(tx.vin.size());
16 outputs.resize(tx.vout.size());
17 }
18
19 bool PartiallySignedTransaction::IsNull() const
20 {
21 return !tx && inputs.empty() && outputs.empty() && unknown.empty();
22 }
23
24 bool PartiallySignedTransaction::Merge(const PartiallySignedTransaction& psbt)
25 {
26 // Prohibited to merge two PSBTs over different transactions
27 if (tx->GetHash() != psbt.tx->GetHash()) {
28 return false;
29 }
30
31 for (unsigned int i = 0; i < inputs.size(); ++i) {
32 inputs[i].Merge(psbt.inputs[i]);
33 }
34 for (unsigned int i = 0; i < outputs.size(); ++i) {
35 outputs[i].Merge(psbt.outputs[i]);
36 }
37 for (auto& xpub_pair : psbt.m_xpubs) {
38 if (m_xpubs.count(xpub_pair.first) == 0) {
39 m_xpubs[xpub_pair.first] = xpub_pair.second;
40 } else {
41 m_xpubs[xpub_pair.first].insert(xpub_pair.second.begin(), xpub_pair.second.end());
42 }
43 }
44 m_proprietary.insert(psbt.m_proprietary.begin(), psbt.m_proprietary.end());
45 unknown.insert(psbt.unknown.begin(), psbt.unknown.end());
46
47 return true;
48 }
49
50 bool PartiallySignedTransaction::AddInput(const CTxIn& txin, PSBTInput& psbtin)
51 {
52 if (std::find(tx->vin.begin(), tx->vin.end(), txin) != tx->vin.end()) {
53 return false;
54 }
55 tx->vin.push_back(txin);
56 psbtin.partial_sigs.clear();
57 psbtin.final_script_sig.clear();
58 psbtin.final_script_witness.SetNull();
59 inputs.push_back(psbtin);
60 return true;
61 }
62
63 bool PartiallySignedTransaction::AddOutput(const CTxOut& txout, const PSBTOutput& psbtout)
64 {
65 tx->vout.push_back(txout);
66 outputs.push_back(psbtout);
67 return true;
68 }
69
70 bool PartiallySignedTransaction::GetInputUTXO(CTxOut& utxo, int input_index) const
71 {
72 const PSBTInput& input = inputs[input_index];
73 uint32_t prevout_index = tx->vin[input_index].prevout.n;
74 if (input.non_witness_utxo) {
75 if (prevout_index >= input.non_witness_utxo->vout.size()) {
76 return false;
77 }
78 if (input.non_witness_utxo->GetHash() != tx->vin[input_index].prevout.hash) {
79 return false;
80 }
81 utxo = input.non_witness_utxo->vout[prevout_index];
82 } else if (!input.witness_utxo.IsNull()) {
83 utxo = input.witness_utxo;
84 } else {
85 return false;
86 }
87 return true;
88 }
89
90 bool PSBTInput::IsNull() const
91 {
92 return !non_witness_utxo && witness_utxo.IsNull() && partial_sigs.empty() && unknown.empty() && hd_keypaths.empty() && redeem_script.empty() && witness_script.empty();
93 }
94
95 void PSBTInput::FillSignatureData(SignatureData& sigdata) const
96 {
97 if (!final_script_sig.empty()) {
98 sigdata.scriptSig = final_script_sig;
99 sigdata.complete = true;
100 }
101 if (!final_script_witness.IsNull()) {
102 sigdata.scriptWitness = final_script_witness;
103 sigdata.complete = true;
104 }
105 if (sigdata.complete) {
106 return;
107 }
108
109 sigdata.signatures.insert(partial_sigs.begin(), partial_sigs.end());
110 if (!redeem_script.empty()) {
111 sigdata.redeem_script = redeem_script;
112 }
113 if (!witness_script.empty()) {
114 sigdata.witness_script = witness_script;
115 }
116 for (const auto& key_pair : hd_keypaths) {
117 sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
118 }
119 if (!m_tap_key_sig.empty()) {
120 sigdata.taproot_key_path_sig = m_tap_key_sig;
121 }
122 for (const auto& [pubkey_leaf, sig] : m_tap_script_sigs) {
123 sigdata.taproot_script_sigs.emplace(pubkey_leaf, sig);
124 }
125 if (!m_tap_internal_key.IsNull()) {
126 sigdata.tr_spenddata.internal_key = m_tap_internal_key;
127 }
128 if (!m_tap_merkle_root.IsNull()) {
129 sigdata.tr_spenddata.merkle_root = m_tap_merkle_root;
130 }
131 for (const auto& [leaf_script, control_block] : m_tap_scripts) {
132 sigdata.tr_spenddata.scripts.emplace(leaf_script, control_block);
133 }
134 for (const auto& [pubkey, leaf_origin] : m_tap_bip32_paths) {
135 sigdata.taproot_misc_pubkeys.emplace(pubkey, leaf_origin);
136 sigdata.tap_pubkeys.emplace(Hash160(pubkey), pubkey);
137 }
138 for (const auto& [hash, preimage] : ripemd160_preimages) {
139 sigdata.ripemd160_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
140 }
141 for (const auto& [hash, preimage] : sha256_preimages) {
142 sigdata.sha256_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
143 }
144 for (const auto& [hash, preimage] : hash160_preimages) {
145 sigdata.hash160_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
146 }
147 for (const auto& [hash, preimage] : hash256_preimages) {
148 sigdata.hash256_preimages.emplace(std::vector<unsigned char>(hash.begin(), hash.end()), preimage);
149 }
150 }
151
152 void PSBTInput::FromSignatureData(const SignatureData& sigdata)
153 {
154 if (sigdata.complete) {
155 partial_sigs.clear();
156 hd_keypaths.clear();
157 redeem_script.clear();
158 witness_script.clear();
159
160 if (!sigdata.scriptSig.empty()) {
161 final_script_sig = sigdata.scriptSig;
162 }
163 if (!sigdata.scriptWitness.IsNull()) {
164 final_script_witness = sigdata.scriptWitness;
165 }
166 return;
167 }
168
169 partial_sigs.insert(sigdata.signatures.begin(), sigdata.signatures.end());
170 if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
171 redeem_script = sigdata.redeem_script;
172 }
173 if (witness_script.empty() && !sigdata.witness_script.empty()) {
174 witness_script = sigdata.witness_script;
175 }
176 for (const auto& entry : sigdata.misc_pubkeys) {
177 hd_keypaths.emplace(entry.second);
178 }
179 if (!sigdata.taproot_key_path_sig.empty()) {
180 m_tap_key_sig = sigdata.taproot_key_path_sig;
181 }
182 for (const auto& [pubkey_leaf, sig] : sigdata.taproot_script_sigs) {
183 m_tap_script_sigs.emplace(pubkey_leaf, sig);
184 }
185 if (!sigdata.tr_spenddata.internal_key.IsNull()) {
186 m_tap_internal_key = sigdata.tr_spenddata.internal_key;
187 }
188 if (!sigdata.tr_spenddata.merkle_root.IsNull()) {
189 m_tap_merkle_root = sigdata.tr_spenddata.merkle_root;
190 }
191 for (const auto& [leaf_script, control_block] : sigdata.tr_spenddata.scripts) {
192 m_tap_scripts.emplace(leaf_script, control_block);
193 }
194 for (const auto& [pubkey, leaf_origin] : sigdata.taproot_misc_pubkeys) {
195 m_tap_bip32_paths.emplace(pubkey, leaf_origin);
196 }
197 }
198
199 void PSBTInput::Merge(const PSBTInput& input)
200 {
201 if (!non_witness_utxo && input.non_witness_utxo) non_witness_utxo = input.non_witness_utxo;
202 if (witness_utxo.IsNull() && !input.witness_utxo.IsNull()) {
203 witness_utxo = input.witness_utxo;
204 }
205
206 partial_sigs.insert(input.partial_sigs.begin(), input.partial_sigs.end());
207 ripemd160_preimages.insert(input.ripemd160_preimages.begin(), input.ripemd160_preimages.end());
208 sha256_preimages.insert(input.sha256_preimages.begin(), input.sha256_preimages.end());
209 hash160_preimages.insert(input.hash160_preimages.begin(), input.hash160_preimages.end());
210 hash256_preimages.insert(input.hash256_preimages.begin(), input.hash256_preimages.end());
211 hd_keypaths.insert(input.hd_keypaths.begin(), input.hd_keypaths.end());
212 m_proprietary.insert(input.m_proprietary.begin(), input.m_proprietary.end());
213 unknown.insert(input.unknown.begin(), input.unknown.end());
214 m_tap_script_sigs.insert(input.m_tap_script_sigs.begin(), input.m_tap_script_sigs.end());
215 m_tap_scripts.insert(input.m_tap_scripts.begin(), input.m_tap_scripts.end());
216 m_tap_bip32_paths.insert(input.m_tap_bip32_paths.begin(), input.m_tap_bip32_paths.end());
217
218 if (redeem_script.empty() && !input.redeem_script.empty()) redeem_script = input.redeem_script;
219 if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script;
220 if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
221 if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness;
222 if (m_tap_key_sig.empty() && !input.m_tap_key_sig.empty()) m_tap_key_sig = input.m_tap_key_sig;
223 if (m_tap_internal_key.IsNull() && !input.m_tap_internal_key.IsNull()) m_tap_internal_key = input.m_tap_internal_key;
224 if (m_tap_merkle_root.IsNull() && !input.m_tap_merkle_root.IsNull()) m_tap_merkle_root = input.m_tap_merkle_root;
225 }
226
227 void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
228 {
229 if (!redeem_script.empty()) {
230 sigdata.redeem_script = redeem_script;
231 }
232 if (!witness_script.empty()) {
233 sigdata.witness_script = witness_script;
234 }
235 for (const auto& key_pair : hd_keypaths) {
236 sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
237 }
238 if (!m_tap_tree.empty() && m_tap_internal_key.IsFullyValid()) {
239 TaprootBuilder builder;
240 for (const auto& [depth, leaf_ver, script] : m_tap_tree) {
241 builder.Add((int)depth, script, (int)leaf_ver, /*track=*/true);
242 }
243 assert(builder.IsComplete());
244 builder.Finalize(m_tap_internal_key);
245 TaprootSpendData spenddata = builder.GetSpendData();
246
247 sigdata.tr_spenddata.internal_key = m_tap_internal_key;
248 sigdata.tr_spenddata.Merge(spenddata);
249 }
250 for (const auto& [pubkey, leaf_origin] : m_tap_bip32_paths) {
251 sigdata.taproot_misc_pubkeys.emplace(pubkey, leaf_origin);
252 sigdata.tap_pubkeys.emplace(Hash160(pubkey), pubkey);
253 }
254 }
255
256 void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
257 {
258 if (redeem_script.empty() && !sigdata.redeem_script.empty()) {
259 redeem_script = sigdata.redeem_script;
260 }
261 if (witness_script.empty() && !sigdata.witness_script.empty()) {
262 witness_script = sigdata.witness_script;
263 }
264 for (const auto& entry : sigdata.misc_pubkeys) {
265 hd_keypaths.emplace(entry.second);
266 }
267 if (!sigdata.tr_spenddata.internal_key.IsNull()) {
268 m_tap_internal_key = sigdata.tr_spenddata.internal_key;
269 }
270 if (sigdata.tr_builder.has_value() && sigdata.tr_builder->HasScripts()) {
271 m_tap_tree = sigdata.tr_builder->GetTreeTuples();
272 }
273 for (const auto& [pubkey, leaf_origin] : sigdata.taproot_misc_pubkeys) {
274 m_tap_bip32_paths.emplace(pubkey, leaf_origin);
275 }
276 }
277
278 bool PSBTOutput::IsNull() const
279 {
280 return redeem_script.empty() && witness_script.empty() && hd_keypaths.empty() && unknown.empty();
281 }
282
283 void PSBTOutput::Merge(const PSBTOutput& output)
284 {
285 hd_keypaths.insert(output.hd_keypaths.begin(), output.hd_keypaths.end());
286 m_proprietary.insert(output.m_proprietary.begin(), output.m_proprietary.end());
287 unknown.insert(output.unknown.begin(), output.unknown.end());
288 m_tap_bip32_paths.insert(output.m_tap_bip32_paths.begin(), output.m_tap_bip32_paths.end());
289
290 if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
291 if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
292 if (m_tap_internal_key.IsNull() && !output.m_tap_internal_key.IsNull()) m_tap_internal_key = output.m_tap_internal_key;
293 if (m_tap_tree.empty() && !output.m_tap_tree.empty()) m_tap_tree = output.m_tap_tree;
294 }
295
296 bool PSBTInputSigned(const PSBTInput& input)
297 {
298 return !input.final_script_sig.empty() || !input.final_script_witness.IsNull();
299 }
300
301 bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned int input_index, const PrecomputedTransactionData* txdata)
302 {
303 CTxOut utxo;
304 assert(input_index < psbt.inputs.size());
305 const PSBTInput& input = psbt.inputs[input_index];
306
307 if (input.non_witness_utxo) {
308 // If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
309 COutPoint prevout = psbt.tx->vin[input_index].prevout;
310 if (prevout.n >= input.non_witness_utxo->vout.size()) {
311 return false;
312 }
313 if (input.non_witness_utxo->GetHash() != prevout.hash) {
314 return false;
315 }
316 utxo = input.non_witness_utxo->vout[prevout.n];
317 } else if (!input.witness_utxo.IsNull()) {
318 utxo = input.witness_utxo;
319 } else {
320 return false;
321 }
322
323 if (txdata) {
324 return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, *txdata, MissingDataBehavior::FAIL});
325 } else {
326 return VerifyScript(input.final_script_sig, utxo.scriptPubKey, &input.final_script_witness, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker{&(*psbt.tx), input_index, utxo.nValue, MissingDataBehavior::FAIL});
327 }
328 }
329
330 size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
331 size_t count = 0;
332 for (const auto& input : psbt.inputs) {
333 if (!PSBTInputSigned(input)) {
334 count++;
335 }
336 }
337
338 return count;
339 }
340
341 void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
342 {
343 CMutableTransaction& tx = *Assert(psbt.tx);
344 const CTxOut& out = tx.vout.at(index);
345 PSBTOutput& psbt_out = psbt.outputs.at(index);
346
347 // Fill a SignatureData with output info
348 SignatureData sigdata;
349 psbt_out.FillSignatureData(sigdata);
350
351 // Construct a would-be spend of this output, to update sigdata with.
352 // Note that ProduceSignature is used to fill in metadata (not actual signatures),
353 // so provider does not need to provide any private keys (it can be a HidingSigningProvider).
354 MutableTransactionSignatureCreator creator(tx, /*input_idx=*/0, out.nValue, SIGHASH_ALL);
355 ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
356
357 // Put redeem_script, witness_script, key paths, into PSBTOutput.
358 psbt_out.FromSignatureData(sigdata);
359 }
360
361 PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction& psbt)
362 {
363 const CMutableTransaction& tx = *psbt.tx;
364 bool have_all_spent_outputs = true;
365 std::vector<CTxOut> utxos(tx.vin.size());
366 for (size_t idx = 0; idx < tx.vin.size(); ++idx) {
367 if (!psbt.GetInputUTXO(utxos[idx], idx)) have_all_spent_outputs = false;
368 }
369 PrecomputedTransactionData txdata;
370 if (have_all_spent_outputs) {
371 txdata.Init(tx, std::move(utxos), true);
372 } else {
373 txdata.Init(tx, {}, true);
374 }
375 return txdata;
376 }
377
378 bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
379 {
380 PSBTInput& input = psbt.inputs.at(index);
381 const CMutableTransaction& tx = *psbt.tx;
382
383 if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
384 return true;
385 }
386
387 // Fill SignatureData with input info
388 SignatureData sigdata;
389 input.FillSignatureData(sigdata);
390
391 // Get UTXO
392 bool require_witness_sig = false;
393 CTxOut utxo;
394
395 if (input.non_witness_utxo) {
396 // If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
397 COutPoint prevout = tx.vin[index].prevout;
398 if (prevout.n >= input.non_witness_utxo->vout.size()) {
399 return false;
400 }
401 if (input.non_witness_utxo->GetHash() != prevout.hash) {
402 return false;
403 }
404 utxo = input.non_witness_utxo->vout[prevout.n];
405 } else if (!input.witness_utxo.IsNull()) {
406 utxo = input.witness_utxo;
407 // When we're taking our information from a witness UTXO, we can't verify it is actually data from
408 // the output being spent. This is safe in case a witness signature is produced (which includes this
409 // information directly in the hash), but not for non-witness signatures. Remember that we require
410 // a witness signature in this situation.
411 require_witness_sig = true;
412 } else {
413 return false;
414 }
415
416 sigdata.witness = false;
417 bool sig_complete;
418 if (txdata == nullptr) {
419 sig_complete = ProduceSignature(provider, DUMMY_SIGNATURE_CREATOR, utxo.scriptPubKey, sigdata);
420 } else {
421 MutableTransactionSignatureCreator creator(tx, index, utxo.nValue, txdata, sighash);
422 sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
423 }
424 // Verify that a witness signature was produced in case one was required.
425 if (require_witness_sig && !sigdata.witness) return false;
426
427 // If we are not finalizing, set sigdata.complete to false to not set the scriptWitness.
428 // P2SPKH inputs must keep the witness since there is no intermediate partial-signature
429 // mechanism (unlike the taproot key path signature field).
430 TxoutType which_type;
431 std::vector<std::vector<unsigned char>> solutions;
432 which_type = Solver(utxo.scriptPubKey, solutions);
433 bool is_p2spkh = (which_type == TxoutType::WITNESS_V3_SPKHASH);
434 if (!finalize && sigdata.complete && !is_p2spkh) sigdata.complete = false;
435
436 input.FromSignatureData(sigdata);
437
438 // If we have a witness signature, put a witness UTXO.
439 if (sigdata.witness) {
440 input.witness_utxo = utxo;
441 // We can remove the non_witness_utxo if and only if there are no non-segwit or segwit v0
442 // inputs in this transaction. Since this requires inspecting the entire transaction, this
443 // is something for the caller to deal with (i.e. FillPSBT).
444 }
445
446 // Fill in the missing info
447 if (out_sigdata) {
448 out_sigdata->missing_pubkeys = sigdata.missing_pubkeys;
449 out_sigdata->missing_sigs = sigdata.missing_sigs;
450 out_sigdata->missing_redeem_script = sigdata.missing_redeem_script;
451 out_sigdata->missing_witness_script = sigdata.missing_witness_script;
452 }
453
454 return sig_complete;
455 }
456
457 void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type)
458 {
459 // Only drop non_witness_utxos if sighash_type != SIGHASH_ANYONECANPAY
460 if ((sighash_type & 0x80) != SIGHASH_ANYONECANPAY) {
461 // Figure out if any non_witness_utxos should be dropped
462 std::vector<unsigned int> to_drop;
463 for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
464 const auto& input = psbtx.inputs.at(i);
465 int wit_ver;
466 std::vector<unsigned char> wit_prog;
467 if (input.witness_utxo.IsNull() || !input.witness_utxo.scriptPubKey.IsWitnessProgram(wit_ver, wit_prog)) {
468 // There's a non-segwit input or Segwit v0, so we cannot drop any witness_utxos
469 to_drop.clear();
470 break;
471 }
472 if (wit_ver == 0) {
473 // Segwit v0, so we cannot drop any non_witness_utxos
474 to_drop.clear();
475 break;
476 }
477 if (input.non_witness_utxo) {
478 to_drop.push_back(i);
479 }
480 }
481
482 // Drop the non_witness_utxos that we can drop
483 for (unsigned int i : to_drop) {
484 psbtx.inputs.at(i).non_witness_utxo = nullptr;
485 }
486 }
487 }
488
489 bool FinalizePSBT(PartiallySignedTransaction& psbtx)
490 {
491 // Finalize input signatures -- in case we have partial signatures that add up to a complete
492 // signature, but have not combined them yet (e.g. because the combiner that created this
493 // PartiallySignedTransaction did not understand them), this will combine them into a final
494 // script.
495 bool complete = true;
496 const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
497 for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
498 complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
499 }
500
501 return complete;
502 }
503
504 bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransaction& result)
505 {
506 // It's not safe to extract a PSBT that isn't finalized, and there's no easy way to check
507 // whether a PSBT is finalized without finalizing it, so we just do this.
508 if (!FinalizePSBT(psbtx)) {
509 return false;
510 }
511
512 result = *psbtx.tx;
513 for (unsigned int i = 0; i < result.vin.size(); ++i) {
514 result.vin[i].scriptSig = psbtx.inputs[i].final_script_sig;
515 result.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness;
516 }
517 return true;
518 }
519
520 bool CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs)
521 {
522 out = psbtxs[0]; // Copy the first one
523
524 // Merge
525 for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) {
526 if (!out.Merge(*it)) {
527 return false;
528 }
529 }
530 return true;
531 }
532
533 std::string PSBTRoleName(PSBTRole role) {
534 switch (role) {
535 case PSBTRole::CREATOR: return "creator";
536 case PSBTRole::UPDATER: return "updater";
537 case PSBTRole::SIGNER: return "signer";
538 case PSBTRole::FINALIZER: return "finalizer";
539 case PSBTRole::EXTRACTOR: return "extractor";
540 // no default case, so the compiler can warn about missing cases
541 }
542 assert(false);
543 }
544
545 bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
546 {
547 auto tx_data = DecodeBase64(base64_tx);
548 if (!tx_data) {
549 error = "invalid base64";
550 return false;
551 }
552 return DecodeRawPSBT(psbt, MakeByteSpan(*tx_data), error);
553 }
554
555 bool DecodeRawPSBT(PartiallySignedTransaction& psbt, Span<const std::byte> tx_data, std::string& error)
556 {
557 DataStream ss_data{tx_data};
558 try {
559 ss_data >> psbt;
560 if (!ss_data.empty()) {
561 error = "extra data after PSBT";
562 return false;
563 }
564 } catch (const std::exception& e) {
565 error = e.what();
566 return false;
567 }
568 return true;
569 }
570
571 uint32_t PartiallySignedTransaction::GetVersion() const
572 {
573 if (m_version != std::nullopt) {
574 return *m_version;
575 }
576 return 0;
577 }
578