aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/node/psbt.cpp134
-rw-r--r--src/node/psbt.h43
-rw-r--r--src/psbt.cpp123
-rw-r--r--src/psbt.h33
-rw-r--r--src/rpc/rawtransaction.cpp1
6 files changed, 180 insertions, 156 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 17e72a7906..cb0604391e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -156,6 +156,7 @@ BITCOIN_CORE_H = \
netbase.h \
netmessagemaker.h \
node/coin.h \
+ node/psbt.h \
node/transaction.h \
noui.h \
optional.h \
@@ -272,6 +273,7 @@ libbitcoin_server_a_SOURCES = \
net.cpp \
net_processing.cpp \
node/coin.cpp \
+ node/psbt.cpp \
node/transaction.cpp \
noui.cpp \
policy/fees.cpp \
diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp
new file mode 100644
index 0000000000..12559c5a5f
--- /dev/null
+++ b/src/node/psbt.cpp
@@ -0,0 +1,134 @@
+// Copyright (c) 2009-2018 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <coins.h>
+#include <consensus/tx_verify.h>
+#include <node/psbt.h>
+#include <policy/policy.h>
+#include <policy/settings.h>
+
+#include <numeric>
+
+PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
+{
+ // Go through each input and build status
+ PSBTAnalysis result;
+
+ bool calc_fee = true;
+ bool all_final = true;
+ bool only_missing_sigs = true;
+ bool only_missing_final = false;
+ CAmount in_amt = 0;
+
+ result.inputs.resize(psbtx.tx->vin.size());
+
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs[i];
+ PSBTInputAnalysis& input_analysis = result.inputs[i];
+
+ // Check for a UTXO
+ CTxOut utxo;
+ if (psbtx.GetInputUTXO(utxo, i)) {
+ in_amt += utxo.nValue;
+ input_analysis.has_utxo = true;
+ } else {
+ input_analysis.has_utxo = false;
+ input_analysis.is_final = false;
+ input_analysis.next = PSBTRole::UPDATER;
+ calc_fee = false;
+ }
+
+ // Check if it is final
+ if (!utxo.IsNull() && !PSBTInputSigned(input)) {
+ input_analysis.is_final = false;
+ all_final = false;
+
+ // Figure out what is missing
+ SignatureData outdata;
+ bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
+
+ // Things are missing
+ if (!complete) {
+ input_analysis.missing_pubkeys = outdata.missing_pubkeys;
+ input_analysis.missing_redeem_script = outdata.missing_redeem_script;
+ input_analysis.missing_witness_script = outdata.missing_witness_script;
+ input_analysis.missing_sigs = outdata.missing_sigs;
+
+ // If we are only missing signatures and nothing else, then next is signer
+ if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
+ input_analysis.next = PSBTRole::SIGNER;
+ } else {
+ only_missing_sigs = false;
+ input_analysis.next = PSBTRole::UPDATER;
+ }
+ } else {
+ only_missing_final = true;
+ input_analysis.next = PSBTRole::FINALIZER;
+ }
+ } else if (!utxo.IsNull()){
+ input_analysis.is_final = true;
+ }
+ }
+
+ if (all_final) {
+ only_missing_sigs = false;
+ result.next = PSBTRole::EXTRACTOR;
+ }
+ if (calc_fee) {
+ // Get the output amount
+ CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmount(0),
+ [](CAmount a, const CTxOut& b) {
+ return a += b.nValue;
+ }
+ );
+
+ // Get the fee
+ CAmount fee = in_amt - out_amt;
+ result.fee = fee;
+
+ // Estimate the size
+ CMutableTransaction mtx(*psbtx.tx);
+ CCoinsView view_dummy;
+ CCoinsViewCache view(&view_dummy);
+ bool success = true;
+
+ for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
+ PSBTInput& input = psbtx.inputs[i];
+ Coin newcoin;
+
+ if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
+ success = false;
+ break;
+ } else {
+ mtx.vin[i].scriptSig = input.final_script_sig;
+ mtx.vin[i].scriptWitness = input.final_script_witness;
+ newcoin.nHeight = 1;
+ view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
+ }
+ }
+
+ if (success) {
+ CTransaction ctx = CTransaction(mtx);
+ size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
+ result.estimated_vsize = size;
+ // Estimate fee rate
+ CFeeRate feerate(fee, size);
+ result.estimated_feerate = feerate;
+ }
+
+ if (only_missing_sigs) {
+ result.next = PSBTRole::SIGNER;
+ } else if (only_missing_final) {
+ result.next = PSBTRole::FINALIZER;
+ } else if (all_final) {
+ result.next = PSBTRole::EXTRACTOR;
+ } else {
+ result.next = PSBTRole::UPDATER;
+ }
+ } else {
+ result.next = PSBTRole::UPDATER;
+ }
+
+ return result;
+}
diff --git a/src/node/psbt.h b/src/node/psbt.h
new file mode 100644
index 0000000000..e04366a20f
--- /dev/null
+++ b/src/node/psbt.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2009-2019 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_NODE_PSBT_H
+#define BITCOIN_NODE_PSBT_H
+
+#include <psbt.h>
+
+/**
+ * Holds an analysis of one input from a PSBT
+ */
+struct PSBTInputAnalysis {
+ bool has_utxo; //!< Whether we have UTXO information for this input
+ bool is_final; //!< Whether the input has all required information including signatures
+ PSBTRole next; //!< Which of the BIP 174 roles needs to handle this input next
+
+ std::vector<CKeyID> missing_pubkeys; //!< Pubkeys whose BIP32 derivation path is missing
+ std::vector<CKeyID> missing_sigs; //!< Pubkeys whose signatures are missing
+ uint160 missing_redeem_script; //!< Hash160 of redeem script, if missing
+ uint256 missing_witness_script; //!< SHA256 of witness script, if missing
+};
+
+/**
+ * Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
+ */
+struct PSBTAnalysis {
+ Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
+ Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
+ Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
+ std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
+ PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
+};
+
+/**
+ * Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
+ *
+ * @param[in] psbtx the PSBT to analyze
+ * @return A PSBTAnalysis with information about the provided PSBT.
+ */
+PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx);
+
+#endif // BITCOIN_NODE_PSBT_H
diff --git a/src/psbt.cpp b/src/psbt.cpp
index 184129e330..f31f2af0d1 100644
--- a/src/psbt.cpp
+++ b/src/psbt.cpp
@@ -340,129 +340,6 @@ std::string PSBTRoleName(PSBTRole role) {
}
}
-PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
-{
- // Go through each input and build status
- PSBTAnalysis result;
-
- bool calc_fee = true;
- bool all_final = true;
- bool only_missing_sigs = true;
- bool only_missing_final = false;
- CAmount in_amt = 0;
-
- result.inputs.resize(psbtx.tx->vin.size());
-
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs[i];
- PSBTInputAnalysis& input_analysis = result.inputs[i];
-
- // Check for a UTXO
- CTxOut utxo;
- if (psbtx.GetInputUTXO(utxo, i)) {
- in_amt += utxo.nValue;
- input_analysis.has_utxo = true;
- } else {
- input_analysis.has_utxo = false;
- input_analysis.is_final = false;
- input_analysis.next = PSBTRole::UPDATER;
- calc_fee = false;
- }
-
- // Check if it is final
- if (!utxo.IsNull() && !PSBTInputSigned(input)) {
- input_analysis.is_final = false;
- all_final = false;
-
- // Figure out what is missing
- SignatureData outdata;
- bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, &outdata);
-
- // Things are missing
- if (!complete) {
- input_analysis.missing_pubkeys = outdata.missing_pubkeys;
- input_analysis.missing_redeem_script = outdata.missing_redeem_script;
- input_analysis.missing_witness_script = outdata.missing_witness_script;
- input_analysis.missing_sigs = outdata.missing_sigs;
-
- // If we are only missing signatures and nothing else, then next is signer
- if (outdata.missing_pubkeys.empty() && outdata.missing_redeem_script.IsNull() && outdata.missing_witness_script.IsNull() && !outdata.missing_sigs.empty()) {
- input_analysis.next = PSBTRole::SIGNER;
- } else {
- only_missing_sigs = false;
- input_analysis.next = PSBTRole::UPDATER;
- }
- } else {
- only_missing_final = true;
- input_analysis.next = PSBTRole::FINALIZER;
- }
- } else if (!utxo.IsNull()){
- input_analysis.is_final = true;
- }
- }
-
- if (all_final) {
- only_missing_sigs = false;
- result.next = PSBTRole::EXTRACTOR;
- }
- if (calc_fee) {
- // Get the output amount
- CAmount out_amt = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmount(0),
- [](CAmount a, const CTxOut& b) {
- return a += b.nValue;
- }
- );
-
- // Get the fee
- CAmount fee = in_amt - out_amt;
- result.fee = fee;
-
- // Estimate the size
- CMutableTransaction mtx(*psbtx.tx);
- CCoinsView view_dummy;
- CCoinsViewCache view(&view_dummy);
- bool success = true;
-
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- PSBTInput& input = psbtx.inputs[i];
- Coin newcoin;
-
- if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
- success = false;
- break;
- } else {
- mtx.vin[i].scriptSig = input.final_script_sig;
- mtx.vin[i].scriptWitness = input.final_script_witness;
- newcoin.nHeight = 1;
- view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
- }
- }
-
- if (success) {
- CTransaction ctx = CTransaction(mtx);
- size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
- result.estimated_vsize = size;
- // Estimate fee rate
- CFeeRate feerate(fee, size);
- result.estimated_feerate = feerate;
- }
-
- if (only_missing_sigs) {
- result.next = PSBTRole::SIGNER;
- } else if (only_missing_final) {
- result.next = PSBTRole::FINALIZER;
- } else if (all_final) {
- result.next = PSBTRole::EXTRACTOR;
- } else {
- result.next = PSBTRole::UPDATER;
- }
- } else {
- result.next = PSBTRole::UPDATER;
- }
-
- return result;
-}
-
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
{
bool invalid;
diff --git a/src/psbt.h b/src/psbt.h
index fcb3337a53..1bc1e91a84 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -557,31 +557,6 @@ enum class PSBTRole {
EXTRACTOR
};
-/**
- * Holds an analysis of one input from a PSBT
- */
-struct PSBTInputAnalysis {
- bool has_utxo; //!< Whether we have UTXO information for this input
- bool is_final; //!< Whether the input has all required information including signatures
- PSBTRole next; //!< Which of the BIP 174 roles needs to handle this input next
-
- std::vector<CKeyID> missing_pubkeys; //!< Pubkeys whose BIP32 derivation path is missing
- std::vector<CKeyID> missing_sigs; //!< Pubkeys whose signatures are missing
- uint160 missing_redeem_script; //!< Hash160 of redeem script, if missing
- uint256 missing_witness_script; //!< SHA256 of witness script, if missing
-};
-
-/**
- * Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
- */
-struct PSBTAnalysis {
- Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
- Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
- Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
- std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
- PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
-};
-
std::string PSBTRoleName(PSBTRole role);
/** Checks whether a PSBTInput is already signed. */
@@ -616,14 +591,6 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
*/
NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
-/**
- * Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
- *
- * @param[in] psbtx the PSBT to analyze
- * @return A PSBTAnalysis with information about the provided PSBT.
- */
-PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx);
-
//! Decode a base64ed PSBT into a PartiallySignedTransaction
NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 4da952060e..8d15ecc28e 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -15,6 +15,7 @@
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
+#include <node/psbt.h>
#include <node/transaction.h>
#include <policy/policy.h>
#include <policy/rbf.h>