Skip to content

Commit 4d074e8

Browse files
committed
[build] Move AnalyzePSBT from psbt.cpp to node/psbt.cpp
psbt.cpp definitions except for AnalyzePSBT are used by the wallet and need to be linked into the wallet binary. AnalyzePSBT is an exception in that it is not used by the wallet, and depends on node classes like CCoinsViewCache, and on node global variables like nBytesPerSigOp. So AnalyzePSBT is more at home in libbitcoin_server than libbitcoin_common, and in any case needs to be defined in a separate object file than other PSBT utilities, to avoid dragging link dependencies on node functions and global variables into the wallet.
1 parent fd509bd commit 4d074e8

File tree

6 files changed

+180
-156
lines changed

6 files changed

+180
-156
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ BITCOIN_CORE_H = \
156156
netbase.h \
157157
netmessagemaker.h \
158158
node/coin.h \
159+
node/psbt.h \
159160
node/transaction.h \
160161
noui.h \
161162
optional.h \
@@ -272,6 +273,7 @@ libbitcoin_server_a_SOURCES = \
272273
net.cpp \
273274
net_processing.cpp \
274275
node/coin.cpp \
276+
node/psbt.cpp \
275277
node/transaction.cpp \
276278
noui.cpp \
277279
policy/fees.cpp \

src/node/psbt.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2009-2018 The Bitcoin Core 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 <coins.h>
6+
#include <consensus/tx_verify.h>
7+
#include <node/psbt.h>
8+
#include <policy/policy.h>
9+
#include <policy/settings.h>
10+
11+
#include <numeric>
12+
13+
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
14+
{
15+
// Go through each input and build status
16+
PSBTAnalysis result;
17+
18+
bool calc_fee = true;
19+
bool all_final = true;
20+
bool only_missing_sigs = true;
21+
bool only_missing_final = false;
22+
CAmount in_amt = 0;
23+
24+
result.inputs.resize(psbtx.tx->vin.size());
25+
26+
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
27+
PSBTInput& input = psbtx.inputs[i];
28+
PSBTInputAnalysis& input_analysis = result.inputs[i];
29+
30+
// Check for a UTXO
31+
CTxOut utxo;
32+
if (psbtx.GetInputUTXO(utxo, i)) {
33+
in_amt += utxo.nValue;
34+
input_analysis.has_utxo = true;
35+
} else {
36+
input_analysis.has_utxo = false;
37+
input_analysis.is_final = false;
38+
input_analysis.next = PSBTRole::UPDATER;
39+
calc_fee = false;
40+
}
41+
42+
// Check if it is final
43+
if (!utxo.IsNull() && !PSBTInputSigned(input)) {
44+
input_analysis.is_final = false;
45+
all_final = false;
46+
47+
// Figure out what is missing
48+
SignatureData outdata;
49+
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
50+
51+
// Things are missing
52+
if (!complete) {
53+
input_analysis.missing_pubkeys = outdata.missing_pubkeys;
54+
input_analysis.missing_redeem_script = outdata.missing_redeem_script;
55+
input_analysis.missing_witness_script = outdata.missing_witness_script;
56+
input_analysis.missing_sigs = outdata.missing_sigs;
57+
58+
// If we are only missing signatures and nothing else, then next is signer
59+
if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
60+
input_analysis.next = PSBTRole::SIGNER;
61+
} else {
62+
only_missing_sigs = false;
63+
input_analysis.next = PSBTRole::UPDATER;
64+
}
65+
} else {
66+
only_missing_final = true;
67+
input_analysis.next = PSBTRole::FINALIZER;
68+
}
69+
} else if (!utxo.IsNull()){
70+
input_analysis.is_final = true;
71+
}
72+
}
73+
74+
if (all_final) {
75+
only_missing_sigs = false;
76+
result.next = PSBTRole::EXTRACTOR;
77+
}
78+
if (calc_fee) {
79+
// Get the output amount
80+
CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmount(0),
81+
[](CAmount a, const CTxOut& b) {
82+
return a += b.nValue;
83+
}
84+
);
85+
86+
// Get the fee
87+
CAmount fee = in_amt - out_amt;
88+
result.fee = fee;
89+
90+
// Estimate the size
91+
CMutableTransaction mtx(*psbtx.tx);
92+
CCoinsView view_dummy;
93+
CCoinsViewCache view(&view_dummy);
94+
bool success = true;
95+
96+
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
97+
PSBTInput& input = psbtx.inputs[i];
98+
Coin newcoin;
99+
100+
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
101+
success = false;
102+
break;
103+
} else {
104+
mtx.vin[i].scriptSig = input.final_script_sig;
105+
mtx.vin[i].scriptWitness = input.final_script_witness;
106+
newcoin.nHeight = 1;
107+
view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
108+
}
109+
}
110+
111+
if (success) {
112+
CTransaction ctx = CTransaction(mtx);
113+
size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
114+
result.estimated_vsize = size;
115+
// Estimate fee rate
116+
CFeeRate feerate(fee, size);
117+
result.estimated_feerate = feerate;
118+
}
119+
120+
if (only_missing_sigs) {
121+
result.next = PSBTRole::SIGNER;
122+
} else if (only_missing_final) {
123+
result.next = PSBTRole::FINALIZER;
124+
} else if (all_final) {
125+
result.next = PSBTRole::EXTRACTOR;
126+
} else {
127+
result.next = PSBTRole::UPDATER;
128+
}
129+
} else {
130+
result.next = PSBTRole::UPDATER;
131+
}
132+
133+
return result;
134+
}

src/node/psbt.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2009-2019 The Bitcoin Core 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+
#ifndef BITCOIN_NODE_PSBT_H
6+
#define BITCOIN_NODE_PSBT_H
7+
8+
#include <psbt.h>
9+
10+
/**
11+
* Holds an analysis of one input from a PSBT
12+
*/
13+
struct PSBTInputAnalysis {
14+
bool has_utxo; //!< Whether we have UTXO information for this input
15+
bool is_final; //!< Whether the input has all required information including signatures
16+
PSBTRole next; //!< Which of the BIP 174 roles needs to handle this input next
17+
18+
std::vector<CKeyID> missing_pubkeys; //!< Pubkeys whose BIP32 derivation path is missing
19+
std::vector<CKeyID> missing_sigs; //!< Pubkeys whose signatures are missing
20+
uint160 missing_redeem_script; //!< Hash160 of redeem script, if missing
21+
uint256 missing_witness_script; //!< SHA256 of witness script, if missing
22+
};
23+
24+
/**
25+
* Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
26+
*/
27+
struct PSBTAnalysis {
28+
Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
29+
Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
30+
Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
31+
std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
32+
PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
33+
};
34+
35+
/**
36+
* Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
37+
*
38+
* @param[in] psbtx the PSBT to analyze
39+
* @return A PSBTAnalysis with information about the provided PSBT.
40+
*/
41+
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx);
42+
43+
#endif // BITCOIN_NODE_PSBT_H

src/psbt.cpp

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -340,129 +340,6 @@ std::string PSBTRoleName(PSBTRole role) {
340340
}
341341
}
342342

343-
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
344-
{
345-
// Go through each input and build status
346-
PSBTAnalysis result;
347-
348-
bool calc_fee = true;
349-
bool all_final = true;
350-
bool only_missing_sigs = true;
351-
bool only_missing_final = false;
352-
CAmount in_amt = 0;
353-
354-
result.inputs.resize(psbtx.tx->vin.size());
355-
356-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
357-
PSBTInput& input = psbtx.inputs[i];
358-
PSBTInputAnalysis& input_analysis = result.inputs[i];
359-
360-
// Check for a UTXO
361-
CTxOut utxo;
362-
if (psbtx.GetInputUTXO(utxo, i)) {
363-
in_amt += utxo.nValue;
364-
input_analysis.has_utxo = true;
365-
} else {
366-
input_analysis.has_utxo = false;
367-
input_analysis.is_final = false;
368-
input_analysis.next = PSBTRole::UPDATER;
369-
calc_fee = false;
370-
}
371-
372-
// Check if it is final
373-
if (!utxo.IsNull() && !PSBTInputSigned(input)) {
374-
input_analysis.is_final = false;
375-
all_final = false;
376-
377-
// Figure out what is missing
378-
SignatureData outdata;
379-
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
380-
381-
// Things are missing
382-
if (!complete) {
383-
input_analysis.missing_pubkeys = outdata.missing_pubkeys;
384-
input_analysis.missing_redeem_script = outdata.missing_redeem_script;
385-
input_analysis.missing_witness_script = outdata.missing_witness_script;
386-
input_analysis.missing_sigs = outdata.missing_sigs;
387-
388-
// If we are only missing signatures and nothing else, then next is signer
389-
if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
390-
input_analysis.next = PSBTRole::SIGNER;
391-
} else {
392-
only_missing_sigs = false;
393-
input_analysis.next = PSBTRole::UPDATER;
394-
}
395-
} else {
396-
only_missing_final = true;
397-
input_analysis.next = PSBTRole::FINALIZER;
398-
}
399-
} else if (!utxo.IsNull()){
400-
input_analysis.is_final = true;
401-
}
402-
}
403-
404-
if (all_final) {
405-
only_missing_sigs = false;
406-
result.next = PSBTRole::EXTRACTOR;
407-
}
408-
if (calc_fee) {
409-
// Get the output amount
410-
CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmount(0),
411-
[](CAmount a, const CTxOut& b) {
412-
return a += b.nValue;
413-
}
414-
);
415-
416-
// Get the fee
417-
CAmount fee = in_amt - out_amt;
418-
result.fee = fee;
419-
420-
// Estimate the size
421-
CMutableTransaction mtx(*psbtx.tx);
422-
CCoinsView view_dummy;
423-
CCoinsViewCache view(&view_dummy);
424-
bool success = true;
425-
426-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
427-
PSBTInput& input = psbtx.inputs[i];
428-
Coin newcoin;
429-
430-
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
431-
success = false;
432-
break;
433-
} else {
434-
mtx.vin[i].scriptSig = input.final_script_sig;
435-
mtx.vin[i].scriptWitness = input.final_script_witness;
436-
newcoin.nHeight = 1;
437-
view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
438-
}
439-
}
440-
441-
if (success) {
442-
CTransaction ctx = CTransaction(mtx);
443-
size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
444-
result.estimated_vsize = size;
445-
// Estimate fee rate
446-
CFeeRate feerate(fee, size);
447-
result.estimated_feerate = feerate;
448-
}
449-
450-
if (only_missing_sigs) {
451-
result.next = PSBTRole::SIGNER;
452-
} else if (only_missing_final) {
453-
result.next = PSBTRole::FINALIZER;
454-
} else if (all_final) {
455-
result.next = PSBTRole::EXTRACTOR;
456-
} else {
457-
result.next = PSBTRole::UPDATER;
458-
}
459-
} else {
460-
result.next = PSBTRole::UPDATER;
461-
}
462-
463-
return result;
464-
}
465-
466343
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
467344
{
468345
bool invalid;

src/psbt.h

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -557,31 +557,6 @@ enum class PSBTRole {
557557
EXTRACTOR
558558
};
559559

560-
/**
561-
* Holds an analysis of one input from a PSBT
562-
*/
563-
struct PSBTInputAnalysis {
564-
bool has_utxo; //!< Whether we have UTXO information for this input
565-
bool is_final; //!< Whether the input has all required information including signatures
566-
PSBTRole next; //!< Which of the BIP 174 roles needs to handle this input next
567-
568-
std::vector<CKeyID> missing_pubkeys; //!< Pubkeys whose BIP32 derivation path is missing
569-
std::vector<CKeyID> missing_sigs; //!< Pubkeys whose signatures are missing
570-
uint160 missing_redeem_script; //!< Hash160 of redeem script, if missing
571-
uint256 missing_witness_script; //!< SHA256 of witness script, if missing
572-
};
573-
574-
/**
575-
* Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
576-
*/
577-
struct PSBTAnalysis {
578-
Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
579-
Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
580-
Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
581-
std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
582-
PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
583-
};
584-
585560
std::string PSBTRoleName(PSBTRole role);
586561

587562
/** Checks whether a PSBTInput is already signed. */
@@ -616,14 +591,6 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
616591
*/
617592
NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
618593

619-
/**
620-
* Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
621-
*
622-
* @param[in] psbtx the PSBT to analyze
623-
* @return A PSBTAnalysis with information about the provided PSBT.
624-
*/
625-
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx);
626-
627594
//! Decode a base64ed PSBT into a PartiallySignedTransaction
628595
NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
629596
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction

src/rpc/rawtransaction.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <key_io.h>
1616
#include <keystore.h>
1717
#include <merkleblock.h>
18+
#include <node/psbt.h>
1819
#include <node/transaction.h>
1920
#include <policy/policy.h>
2021
#include <policy/rbf.h>

0 commit comments

Comments
 (0)