aboutsummaryrefslogtreecommitdiff
path: root/src/psbt.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/psbt.h')
-rw-r--r--src/psbt.h57
1 files changed, 44 insertions, 13 deletions
diff --git a/src/psbt.h b/src/psbt.h
index 99a56b3b3d..bcff66f7a1 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -7,9 +7,12 @@
#include <attributes.h>
#include <node/transaction.h>
+#include <optional.h>
+#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <pubkey.h>
#include <script/sign.h>
+#include <script/signingprovider.h>
// Magic bytes
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
@@ -123,6 +126,9 @@ struct PSBTInput
template <typename Stream>
inline void Unserialize(Stream& s) {
+ // Used for duplicate key detection
+ std::set<std::vector<unsigned char>> key_lookup;
+
// Read loop
bool found_sep = false;
while(!s.empty()) {
@@ -144,7 +150,7 @@ struct PSBTInput
switch(type) {
case PSBT_IN_NON_WITNESS_UTXO:
{
- if (non_witness_utxo) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Non-witness utxo key is more than one byte type");
@@ -155,7 +161,7 @@ struct PSBTInput
break;
}
case PSBT_IN_WITNESS_UTXO:
- if (!witness_utxo.IsNull()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input witness utxo already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Witness utxo key is more than one byte type");
@@ -186,7 +192,7 @@ struct PSBTInput
break;
}
case PSBT_IN_SIGHASH:
- if (sighash_type > 0) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input sighash type already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Sighash type key is more than one byte type");
@@ -195,7 +201,7 @@ struct PSBTInput
break;
case PSBT_IN_REDEEMSCRIPT:
{
- if (!redeem_script.empty()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input redeemScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input redeemScript key is more than one byte type");
@@ -205,7 +211,7 @@ struct PSBTInput
}
case PSBT_IN_WITNESSSCRIPT:
{
- if (!witness_script.empty()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input witnessScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input witnessScript key is more than one byte type");
@@ -220,7 +226,7 @@ struct PSBTInput
}
case PSBT_IN_SCRIPTSIG:
{
- if (!final_script_sig.empty()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Final scriptSig key is more than one byte type");
@@ -230,7 +236,7 @@ struct PSBTInput
}
case PSBT_IN_SCRIPTWITNESS:
{
- if (!final_script_witness.IsNull()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Final scriptWitness key is more than one byte type");
@@ -306,6 +312,9 @@ struct PSBTOutput
template <typename Stream>
inline void Unserialize(Stream& s) {
+ // Used for duplicate key detection
+ std::set<std::vector<unsigned char>> key_lookup;
+
// Read loop
bool found_sep = false;
while(!s.empty()) {
@@ -327,7 +336,7 @@ struct PSBTOutput
switch(type) {
case PSBT_OUT_REDEEMSCRIPT:
{
- if (!redeem_script.empty()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output redeemScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output redeemScript key is more than one byte type");
@@ -337,7 +346,7 @@ struct PSBTOutput
}
case PSBT_OUT_WITNESSSCRIPT:
{
- if (!witness_script.empty()) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output witnessScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output witnessScript key is more than one byte type");
@@ -378,7 +387,7 @@ struct PSBTOutput
/** A version of CTransaction with the PSBT format*/
struct PartiallySignedTransaction
{
- boost::optional<CMutableTransaction> tx;
+ Optional<CMutableTransaction> tx;
std::vector<PSBTInput> inputs;
std::vector<PSBTOutput> outputs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
@@ -392,7 +401,6 @@ struct PartiallySignedTransaction
bool AddInput(const CTxIn& txin, PSBTInput& psbtin);
bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout);
PartiallySignedTransaction() {}
- PartiallySignedTransaction(const PartiallySignedTransaction& psbt_in) : tx(psbt_in.tx), inputs(psbt_in.inputs), outputs(psbt_in.outputs), unknown(psbt_in.unknown) {}
explicit PartiallySignedTransaction(const CMutableTransaction& tx);
/**
* Finds the UTXO for a given input index
@@ -445,6 +453,9 @@ struct PartiallySignedTransaction
throw std::ios_base::failure("Invalid PSBT magic bytes");
}
+ // Used for duplicate key detection
+ std::set<std::vector<unsigned char>> key_lookup;
+
// Read global data
bool found_sep = false;
while(!s.empty()) {
@@ -466,7 +477,7 @@ struct PartiallySignedTransaction
switch(type) {
case PSBT_GLOBAL_UNSIGNED_TX:
{
- if (tx) {
+ if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, unsigned tx already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Global unsigned tx key is more than one byte type");
@@ -548,12 +559,27 @@ struct PartiallySignedTransaction
}
};
+enum class PSBTRole {
+ UPDATER,
+ SIGNER,
+ FINALIZER,
+ EXTRACTOR
+};
+
+std::string PSBTRoleName(PSBTRole role);
+
/** Checks whether a PSBTInput is already signed. */
-bool PSBTInputSigned(PSBTInput& input);
+bool PSBTInputSigned(const PSBTInput& input);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool use_dummy = false);
+/** Updates a PSBTOutput with information from provider.
+ *
+ * This fills in the redeem_script, witness_script, and hd_keypaths where possible.
+ */
+void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index);
+
/**
* Finalizes a PSBT if possible, combining partial signatures.
*
@@ -580,4 +606,9 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
*/
NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
+//! 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
+NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
+
#endif // BITCOIN_PSBT_H