2021-12-30 19:36:57 +02:00
|
|
|
// Copyright (c) 2009-2021 The Bitcoin Core developers
|
2019-04-08 16:33:05 -04:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
|
|
#include <coins.h>
|
2021-09-11 10:29:00 +08:00
|
|
|
#include <consensus/amount.h>
|
2019-04-08 16:33:05 -04:00
|
|
|
#include <consensus/tx_verify.h>
|
|
|
|
|
#include <node/psbt.h>
|
|
|
|
|
#include <policy/policy.h>
|
|
|
|
|
#include <policy/settings.h>
|
2019-11-19 14:54:13 -05:00
|
|
|
#include <tinyformat.h>
|
2019-04-08 16:33:05 -04:00
|
|
|
|
|
|
|
|
#include <numeric>
|
|
|
|
|
|
2021-11-12 10:06:00 -05:00
|
|
|
namespace node {
|
2019-04-08 16:33:05 -04:00
|
|
|
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
|
|
|
|
|
{
|
|
|
|
|
// Go through each input and build status
|
|
|
|
|
PSBTAnalysis result;
|
|
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
// Elements things
|
|
|
|
|
bool needs_blinded_outputs = false;
|
|
|
|
|
bool has_blinded_outputs = false;
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-01-11 17:21:34 -05:00
|
|
|
result.inputs.resize(psbtx.inputs.size());
|
2021-09-14 15:48:35 +00:00
|
|
|
result.next = PSBTRole::EXTRACTOR;
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-03-03 16:47:44 -08:00
|
|
|
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
|
|
|
|
|
|
2021-01-11 17:21:34 -05:00
|
|
|
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
|
2019-04-08 16:33:05 -04:00
|
|
|
PSBTInput& input = psbtx.inputs[i];
|
|
|
|
|
PSBTInputAnalysis& input_analysis = result.inputs[i];
|
|
|
|
|
|
2020-02-28 11:27:13 -05:00
|
|
|
// We set next role here and ratchet backwards as required
|
|
|
|
|
input_analysis.next = PSBTRole::EXTRACTOR;
|
|
|
|
|
|
2019-04-08 16:33:05 -04:00
|
|
|
// Check for a UTXO
|
|
|
|
|
CTxOut utxo;
|
2021-01-11 15:50:27 -05:00
|
|
|
if (input.GetUTXO(utxo)) {
|
2021-05-12 18:53:00 -04:00
|
|
|
if (utxo.nValue.IsExplicit()) {
|
|
|
|
|
if (!MoneyRange(utxo.nValue.GetAmount())) {
|
|
|
|
|
result.SetInvalid(strprintf("PSBT is not valid. Input %u has invalid value", i));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
needs_blinded_outputs = true;
|
2019-10-15 17:15:22 -04:00
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
input_analysis.has_utxo = true;
|
|
|
|
|
} else {
|
2021-05-12 18:53:00 -04:00
|
|
|
if (input.non_witness_utxo && *input.prev_out >= input.non_witness_utxo->vout.size()) {
|
2019-10-15 17:26:46 -04:00
|
|
|
result.SetInvalid(strprintf("PSBT is not valid. Input %u specifies invalid prevout", i));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
input_analysis.has_utxo = false;
|
|
|
|
|
input_analysis.is_final = false;
|
|
|
|
|
input_analysis.next = PSBTRole::UPDATER;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-19 14:54:13 -05:00
|
|
|
if (!utxo.IsNull() && utxo.scriptPubKey.IsUnspendable()) {
|
|
|
|
|
result.SetInvalid(strprintf("PSBT is not valid. Input %u spends unspendable output", i));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-08 16:33:05 -04:00
|
|
|
// Check if it is final
|
|
|
|
|
if (!utxo.IsNull() && !PSBTInputSigned(input)) {
|
|
|
|
|
input_analysis.is_final = false;
|
|
|
|
|
|
|
|
|
|
// Figure out what is missing
|
|
|
|
|
SignatureData outdata;
|
2021-03-03 16:47:44 -08:00
|
|
|
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, 1, &outdata);
|
2019-04-08 16:33:05 -04:00
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
|
input_analysis.next = PSBTRole::UPDATER;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
input_analysis.next = PSBTRole::FINALIZER;
|
|
|
|
|
}
|
|
|
|
|
} else if (!utxo.IsNull()){
|
|
|
|
|
input_analysis.is_final = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 16:35:37 +00:00
|
|
|
result.outputs.resize(psbtx.outputs.size());
|
|
|
|
|
for (unsigned int i = 0; i < psbtx.outputs.size(); ++i) {
|
|
|
|
|
const PSBTOutput& output = psbtx.outputs[i];
|
|
|
|
|
PSBTOutputAnalysis& output_analysis = result.outputs[i];
|
2021-05-12 18:53:00 -04:00
|
|
|
CTxOut txout = output.GetTxOut();
|
2021-09-21 16:35:37 +00:00
|
|
|
|
|
|
|
|
output_analysis.is_blind = output.IsBlinded();
|
|
|
|
|
output_analysis.proof_result = VerifyBlindProofs(output);
|
|
|
|
|
if (output_analysis.is_blind) {
|
2021-05-12 18:53:00 -04:00
|
|
|
has_blinded_outputs = true;
|
|
|
|
|
if (!output.IsFullyBlinded()) {
|
|
|
|
|
result.next = PSBTRole::BLINDER;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Find the fee output
|
|
|
|
|
if (txout.IsFee()) {
|
2021-09-04 15:19:42 +00:00
|
|
|
if (result.fee != std::nullopt) {
|
2021-05-12 18:53:00 -04:00
|
|
|
result.SetInvalid("There is more than one fee output");
|
|
|
|
|
return result;
|
2019-10-15 17:15:22 -04:00
|
|
|
}
|
2021-05-12 18:53:00 -04:00
|
|
|
result.fee = output.amount;
|
2019-04-08 16:33:05 -04:00
|
|
|
}
|
2021-05-12 18:53:00 -04:00
|
|
|
}
|
|
|
|
|
if (txout.nValue.IsExplicit() && !MoneyRange(txout.nValue.GetAmount())) {
|
|
|
|
|
result.SetInvalid("PSBT is not valid. Output amount invalid");
|
2019-10-15 17:15:22 -04:00
|
|
|
return result;
|
|
|
|
|
}
|
2021-05-12 18:53:00 -04:00
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-09-04 15:19:42 +00:00
|
|
|
if (result.fee == std::nullopt) {
|
2021-05-12 18:53:00 -04:00
|
|
|
result.SetInvalid("PSBT missing required fee output");
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
if (needs_blinded_outputs && !has_blinded_outputs) {
|
|
|
|
|
result.SetInvalid("PSBT has blinded inputs but no blinded outputs. Must have at least one blinded output to balance with the inputs");
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
// Estimate the size
|
|
|
|
|
CMutableTransaction mtx(psbtx.GetUnsignedTx());
|
|
|
|
|
CCoinsView view_dummy;
|
|
|
|
|
CCoinsViewCache view(&view_dummy);
|
|
|
|
|
bool success = true;
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
|
|
|
|
|
PSBTInput& input = psbtx.inputs[i];
|
|
|
|
|
Coin newcoin;
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-09-04 15:19:42 +00:00
|
|
|
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, 1) || !input.GetUTXO(newcoin.out)) {
|
2021-05-12 18:53:00 -04:00
|
|
|
success = false;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
mtx.vin[i].scriptSig = input.final_script_sig;
|
|
|
|
|
mtx.witness.vtxinwit[i].scriptWitness = input.final_script_witness;
|
|
|
|
|
newcoin.nHeight = 1;
|
|
|
|
|
view.AddCoin(input.GetOutPoint(), std::move(newcoin), true);
|
2019-04-08 16:33:05 -04:00
|
|
|
}
|
2021-05-12 18:53:00 -04:00
|
|
|
}
|
2019-04-08 16:33:05 -04:00
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
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(*result.fee, size);
|
|
|
|
|
result.estimated_feerate = feerate;
|
2019-04-08 16:33:05 -04:00
|
|
|
}
|
|
|
|
|
|
2021-05-12 18:53:00 -04:00
|
|
|
// Calculate next role for PSBT by grabbing "minimum" PSBTInput next role
|
|
|
|
|
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
|
|
|
|
|
PSBTInputAnalysis& input_analysis = result.inputs[i];
|
|
|
|
|
result.next = std::min(result.next, input_analysis.next);
|
|
|
|
|
}
|
|
|
|
|
assert(result.next > PSBTRole::CREATOR);
|
|
|
|
|
|
2019-04-08 16:33:05 -04:00
|
|
|
return result;
|
|
|
|
|
}
|
2021-11-12 10:06:00 -05:00
|
|
|
} // namespace node
|