Remove PSET and disable PSBT/PSET things for now

Reset back to Bitcoin PSBT and disable PSBT/PSET handling in wallet and
rpc.

This is just a reset to allow for PSBTv2 change and then a new and
improved PSET.
This commit is contained in:
Andrew Chow 2021-03-03 17:00:15 -05:00
parent eda3fbe212
commit fdf71def4c
5 changed files with 35 additions and 503 deletions

View file

@ -2,11 +2,10 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <blind.h>
#include <pegins.h>
#include <psbt.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <confidential_validation.h>
PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
@ -151,16 +150,6 @@ void PSBTInput::Merge(const PSBTInput& input)
if (witness_script.empty() && !input.witness_script.empty()) witness_script = input.witness_script;
if (final_script_sig.empty() && !input.final_script_sig.empty()) final_script_sig = input.final_script_sig;
if (final_script_witness.IsNull() && !input.final_script_witness.IsNull()) final_script_witness = input.final_script_witness;
if (!value && input.value) value = input.value;
if (value_blinding_factor.IsNull() && !input.value_blinding_factor.IsNull()) value_blinding_factor = input.value_blinding_factor;
if (asset.IsNull() && !input.asset.IsNull()) asset = input.asset;
if (asset_blinding_factor.IsNull() && !input.asset_blinding_factor.IsNull()) asset_blinding_factor = input.asset_blinding_factor;
if (peg_in_tx.which() == 0 && peg_in_tx.which() > 0) peg_in_tx = input.peg_in_tx;
if (txout_proof.which() == 0 && peg_in_tx.which() > 0) txout_proof = input.txout_proof;
if (claim_script.empty() && !input.claim_script.empty()) claim_script = input.claim_script;
if (genesis_hash.IsNull() && !input.genesis_hash.IsNull()) genesis_hash = input.genesis_hash;
}
void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
@ -201,15 +190,6 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (redeem_script.empty() && !output.redeem_script.empty()) redeem_script = output.redeem_script;
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
if (!blinding_pubkey.IsValid() && output.blinding_pubkey.IsValid()) blinding_pubkey = output.blinding_pubkey;
if (value_commitment.IsNull() && !output.value_commitment.IsNull()) value_commitment = output.value_commitment;
if (value_blinding_factor.IsNull() && !output.value_blinding_factor.IsNull()) value_blinding_factor = output.value_blinding_factor;
if (asset_commitment.IsNull() && !output.asset_commitment.IsNull()) asset_commitment = output.asset_commitment;
if (asset_blinding_factor.IsNull() && !output.asset_blinding_factor.IsNull()) asset_blinding_factor = output.asset_blinding_factor;
if (nonce_commitment.IsNull() && !output.nonce_commitment.IsNull()) nonce_commitment = output.nonce_commitment;
if (range_proof.empty() && !output.range_proof.empty()) range_proof = output.range_proof;
if (surjection_proof.empty() && !output.surjection_proof.empty()) surjection_proof = output.surjection_proof;
}
bool PSBTInputSigned(const PSBTInput& input)
{
@ -229,7 +209,8 @@ size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt) {
void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index)
{
const CTxOut& out = psbt.tx->vout.at(index);
CMutableTransaction& tx = *Assert(psbt.tx);
const CTxOut& out = tx.vout.at(index);
PSBTOutput& psbt_out = psbt.outputs.at(index);
// Fill a SignatureData with output info
@ -239,7 +220,7 @@ void UpdatePSBTOutput(const SigningProvider& provider, PartiallySignedTransactio
// Construct a would-be spend of this output, to update sigdata with.
// Note that ProduceSignature is used to fill in metadata (not actual signatures),
// so provider does not need to provide any private keys (it can be a HidingSigningProvider).
MutableTransactionSignatureCreator creator(psbt.tx.get_ptr(), /* index */ 0, out.nValue, SIGHASH_ALL);
MutableTransactionSignatureCreator creator(&tx, /* index */ 0, out.nValue, SIGHASH_ALL);
ProduceSignature(provider, creator, out.scriptPubKey, sigdata);
// Put redeem_script, witness_script, key paths, into PSBTOutput.
@ -259,7 +240,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
SignatureData sigdata;
input.FillSignatureData(sigdata);
// Get UTXO for this input
// Get UTXO
bool require_witness_sig = false;
CTxOut utxo;
@ -337,51 +318,10 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
}
result = *psbtx.tx;
result.witness.vtxinwit.resize(result.vin.size());
for (unsigned int i = 0; i < result.vin.size(); ++i) {
result.vin[i].scriptSig = psbtx.inputs[i].final_script_sig;
result.witness.vtxinwit[i].scriptWitness = psbtx.inputs[i].final_script_witness;
PSBTInput& input = psbtx.inputs[i];
if (input.value && input.peg_in_tx.which() != 0 && input.txout_proof.which() != 0 && !input.claim_script.empty() && !input.genesis_hash.IsNull()) {
CScriptWitness pegin_witness;
if (Params().GetConsensus().ParentChainHasPow()) {
const Sidechain::Bitcoin::CTransactionRef& btc_peg_in_tx = boost::get<Sidechain::Bitcoin::CTransactionRef>(input.peg_in_tx);
const Sidechain::Bitcoin::CMerkleBlock& btc_txout_proof = boost::get<Sidechain::Bitcoin::CMerkleBlock>(input.txout_proof);
pegin_witness = CreatePeginWitness(*input.value, input.asset, input.genesis_hash, input.claim_script, btc_peg_in_tx, btc_txout_proof);
} else {
const CTransactionRef& elem_peg_in_tx = boost::get<CTransactionRef>(input.peg_in_tx);
const CMerkleBlock& elem_txout_proof = boost::get<CMerkleBlock>(input.txout_proof);
pegin_witness = CreatePeginWitness(*input.value, input.asset, input.genesis_hash, input.claim_script, elem_peg_in_tx, elem_txout_proof);
}
result.vin[i].m_is_pegin = true;
result.witness.vtxinwit[i].m_pegin_witness = pegin_witness;
}
}
result.witness.vtxoutwit.resize(result.vout.size());
for (unsigned int i = 0; i < result.vout.size(); ++i) {
PSBTOutput& output = psbtx.outputs.at(i);
CTxOut& out = result.vout[i];
CTxOutWitness& outwit = result.witness.vtxoutwit[i];
if (!output.value_commitment.IsNull()) {
out.nValue = output.value_commitment;
}
if (!output.asset_commitment.IsNull()) {
out.nAsset = output.asset_commitment;
}
if (!output.nonce_commitment.IsNull()) {
out.nNonce = output.nonce_commitment;
}
if (!output.range_proof.empty()) {
outwit.vchRangeproof = output.range_proof;
}
if (!output.surjection_proof.empty()) {
outwit.vchSurjectionproof = output.surjection_proof;
}
}
return true;
}
@ -417,7 +357,6 @@ std::string EncodePSBT(const PartiallySignedTransaction& psbt)
return EncodeBase64(MakeUCharSpan(ssTx));
}
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
{
bool invalid;
@ -444,43 +383,3 @@ bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data,
}
return true;
}
bool CheckPSBTBlinding(const PartiallySignedTransaction& psbtx, std::string& error) {
// Plausibly, we may want a way to let the user continue anyway. However, we
// want to fail by default, to make it as hard as possible to do something
// really dangerous. And since this way of handling blinded PSBTs is going
// away "real soon now" in favor of a better one, no sense in trying too
// hard about it.
for (size_t i = 0; i < psbtx.outputs.size(); ++i) {
const PSBTOutput& output = psbtx.outputs[i];
const CTxOut& txo = psbtx.tx->vout[i];
if (txo.nValue.IsCommitment() || txo.nAsset.IsCommitment()) {
error = "PSBT's 'tx' field may not have pre-blinded outputs.";
return false;
}
if (!output.value_commitment.IsCommitment() &&
!output.asset_commitment.IsCommitment() &&
output.value_blinding_factor.IsNull() &&
output.asset_blinding_factor.IsNull()) {
// Nothing blinded, nothing to check.
continue;
} else if (!output.value_commitment.IsCommitment() ||
!output.asset_commitment.IsCommitment() ||
output.value_blinding_factor.IsNull() ||
output.asset_blinding_factor.IsNull()) {
// Something blinded, but not everything? That's not expected.
error = "PSBT has a partially-blinded output. Blinded outputs must be fully blinded.";
return false;
}
if (!VerifyConfidentialPair(output.value_commitment, output.asset_commitment, txo.nValue.GetAmount(), txo.nAsset.GetAsset(), output.value_blinding_factor, output.asset_blinding_factor)) {
error = "PSBT's 'tx' field output values do not match blinded output values (or are invalid in some way)! Either there is a bug, or the blinder is attacking you.";
return false;
}
}
return true;
}

View file

@ -6,27 +6,19 @@
#define BITCOIN_PSBT_H
#include <attributes.h>
#include <chainparams.h>
#include <node/transaction.h>
#include <optional.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <primitives/bitcoin/transaction.h>
#include <primitives/bitcoin/merkleblock.h>
#include <merkleblock.h>
#include <pubkey.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <boost/variant.hpp>
// Magic bytes
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
static constexpr uint8_t PSBT_ELEMENTS_MAGIC_BYTES[5] = {'p', 's', 'e', 't', 0xff};
// Global types
static constexpr uint8_t PSBT_GLOBAL_UNSIGNED_TX = 0x00;
static constexpr uint8_t PSBT_GLOBAL_PROPRIETARY = 0xFC;
// Input types
static constexpr uint8_t PSBT_IN_NON_WITNESS_UTXO = 0x00;
@ -38,35 +30,11 @@ static constexpr uint8_t PSBT_IN_WITNESSSCRIPT = 0x05;
static constexpr uint8_t PSBT_IN_BIP32_DERIVATION = 0x06;
static constexpr uint8_t PSBT_IN_SCRIPTSIG = 0x07;
static constexpr uint8_t PSBT_IN_SCRIPTWITNESS = 0x08;
static constexpr uint8_t PSBT_IN_PROPRIETARY = 0xFC;
// Confidential Assets stuff (private use area)
static constexpr uint8_t PSBT_IN_VALUE = 0x00;
static constexpr uint8_t PSBT_IN_VALUE_BLINDER = 0x01;
static constexpr uint8_t PSBT_IN_ASSET = 0x02;
static constexpr uint8_t PSBT_IN_ASSET_BLINDER = 0x03;
// Peg-in stuff
static constexpr uint8_t PSBT_IN_PEG_IN_TX = 0x04;
static constexpr uint8_t PSBT_IN_TXOUT_PROOF = 0x05;
static constexpr uint8_t PSBT_IN_GENESIS_HASH = 0x06;
static constexpr uint8_t PSBT_IN_CLAIM_SCRIPT = 0x07;
// Output types
static constexpr uint8_t PSBT_OUT_REDEEMSCRIPT = 0x00;
static constexpr uint8_t PSBT_OUT_WITNESSSCRIPT = 0x01;
static constexpr uint8_t PSBT_OUT_BIP32_DERIVATION = 0x02;
static constexpr uint8_t PSBT_OUT_PROPRIETARY = 0xFC;
// Confidential Assets stuff (private use area)
static constexpr uint8_t PSBT_OUT_VALUE_COMMITMENT = 0x00;
static constexpr uint8_t PSBT_OUT_VALUE_BLINDER = 0x01;
static constexpr uint8_t PSBT_OUT_ASSET_COMMITMENT = 0x02;
static constexpr uint8_t PSBT_OUT_ASSET_BLINDER = 0x03;
static constexpr uint8_t PSBT_OUT_RANGE_PROOF = 0x04;
static constexpr uint8_t PSBT_OUT_SURJECTION_PROOF = 0x05;
static constexpr uint8_t PSBT_OUT_BLINDING_PUBKEY = 0x06;
static constexpr uint8_t PSBT_OUT_NONCE_COMMITMENT = 0x07;
// Proprietary type identifer string
static const std::string PSBT_ELEMENTS_ID("elements");
// The separator is 0x00. Reading this in means that the unserializer can interpret it
// as a 0 length key which indicates that this is the separator. The separator has no value.
@ -90,16 +58,6 @@ struct PSBTInput
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
int sighash_type = 0;
boost::optional<CAmount> value;
uint256 value_blinding_factor;
CAsset asset;
uint256 asset_blinding_factor;
boost::variant<boost::blank, CTransactionRef, Sidechain::Bitcoin::CTransactionRef> peg_in_tx;
boost::variant<boost::blank, CMerkleBlock, Sidechain::Bitcoin::CMerkleBlock> txout_proof;
CScript claim_script;
uint256 genesis_hash;
bool IsNull() const;
void FillSignatureData(SignatureData& sigdata) const;
void FromSignatureData(const SignatureData& sigdata);
@ -148,27 +106,6 @@ struct PSBTInput
SerializeHDKeypaths(s, hd_keypaths, PSBT_IN_BIP32_DERIVATION);
}
// Write the Confidential Assets blinding data
if (value) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_VALUE);
SerializeToVector(s, *value);
}
if (!value_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_VALUE_BLINDER);
SerializeToVector(s, value_blinding_factor);
}
if (!asset.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_ASSET);
SerializeToVector(s, asset);
}
if (!asset_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_ASSET_BLINDER);
SerializeToVector(s, asset_blinding_factor);
}
// Write script sig
if (!final_script_sig.empty()) {
SerializeToVector(s, PSBT_IN_SCRIPTSIG);
@ -180,49 +117,6 @@ struct PSBTInput
SerializeToVector(s, final_script_witness.stack);
}
// Write peg-in data
if (Params().GetConsensus().ParentChainHasPow()) {
if (peg_in_tx.which() > 0) {
const Sidechain::Bitcoin::CTransactionRef& btc_peg_in_tx = boost::get<Sidechain::Bitcoin::CTransactionRef>(peg_in_tx);
if (btc_peg_in_tx) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_PEG_IN_TX);
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS);
SerializeToVector(os, btc_peg_in_tx);
}
}
if (txout_proof.which() > 0) {
const Sidechain::Bitcoin::CMerkleBlock& btc_txout_proof = boost::get<Sidechain::Bitcoin::CMerkleBlock>(txout_proof);
if (!btc_txout_proof.header.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_TXOUT_PROOF);
SerializeToVector(s, btc_txout_proof);
}
}
} else {
if (peg_in_tx.which() > 0) {
const CTransactionRef& elem_peg_in_tx = boost::get<CTransactionRef>(peg_in_tx);
if (elem_peg_in_tx) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_PEG_IN_TX);
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion() | SERIALIZE_TRANSACTION_NO_WITNESS);
SerializeToVector(os, elem_peg_in_tx);
}
}
if (txout_proof.which() > 0) {
const CMerkleBlock& elem_txout_proof = boost::get<CMerkleBlock>(txout_proof);
if (!elem_txout_proof.header.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_TXOUT_PROOF);
SerializeToVector(s, elem_txout_proof);
}
}
}
if (!claim_script.empty()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_CLAIM_SCRIPT);
s << claim_script;
}
if (!genesis_hash.IsNull()) {
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_GENESIS_HASH);
SerializeToVector(s, genesis_hash);
}
// Write unknown things
for (auto& entry : unknown) {
s << entry.first;
@ -353,124 +247,6 @@ struct PSBTInput
UnserializeFromVector(s, final_script_witness.stack);
break;
}
case PSBT_IN_PROPRIETARY:
{
VectorReader skey(s.GetType(), s.GetVersion(), key, 1);
std::string identifier;
skey >> identifier;
if (identifier != PSBT_ELEMENTS_ID) {
// This is not our proprietary type, skip it
continue;
}
size_t subkey_len = skey.size();
uint64_t subtype = ReadCompactSize(skey);
switch(subtype) {
case PSBT_IN_VALUE:
{
if (value != boost::none) {
throw std::ios_base::failure("Duplicate Key, input value already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Final value key is more than one byte type");
}
CAmount amt;
UnserializeFromVector(s, amt);
value = amt;
break;
}
case PSBT_IN_VALUE_BLINDER:
{
if (!value_blinding_factor.IsNull()) {
throw std::ios_base::failure("Duplicate Key, input value_blinding_factor already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Final value_blinding_factor key is more than one byte type");
}
UnserializeFromVector(s, value_blinding_factor);
break;
}
case PSBT_IN_ASSET:
{
if (!asset.IsNull()) {
throw std::ios_base::failure("Duplicate Key, input asset already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Final asset key is more than one byte type");
}
UnserializeFromVector(s, asset);
break;
}
case PSBT_IN_ASSET_BLINDER:
{
if (!asset_blinding_factor.IsNull()) {
throw std::ios_base::failure("Duplicate Key, input asset_blinding_factor already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Final asset_blinding_factor key is more than one byte type");
}
UnserializeFromVector(s, asset_blinding_factor);
break;
}
case PSBT_IN_PEG_IN_TX:
{
if (peg_in_tx.which() != 0) {
throw std::ios_base::failure("Duplicate Key, peg-in tx already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Peg-in tx key is more than one byte type");
}
if (Params().GetConsensus().ParentChainHasPow()) {
Sidechain::Bitcoin::CTransactionRef tx_btc;
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion());
UnserializeFromVector(os, tx_btc);
peg_in_tx = tx_btc;
} else {
CTransactionRef tx_btc;
OverrideStream<Stream> os(&s, s.GetType(), s.GetVersion());
UnserializeFromVector(os, tx_btc);
peg_in_tx = tx_btc;
}
break;
}
case PSBT_IN_TXOUT_PROOF:
{
if (txout_proof.which() != 0) {
throw std::ios_base::failure("Duplicate Key, peg-in txout proof already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Peg-in txout proof key is more than one byte type");
}
if (Params().GetConsensus().ParentChainHasPow()) {
Sidechain::Bitcoin::CMerkleBlock tx_proof;
UnserializeFromVector(s, tx_proof);
txout_proof = tx_proof;
} else {
CMerkleBlock tx_proof;
UnserializeFromVector(s, tx_proof);
txout_proof = tx_proof;
}
break;
}
case PSBT_IN_CLAIM_SCRIPT:
{
if (!claim_script.empty()) {
throw std::ios_base::failure("Duplicate Key, peg-in claim script already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Peg-in claim script key is more than one byte type");
}
s >> claim_script;
break;
}
case PSBT_IN_GENESIS_HASH:
{
if (!genesis_hash.IsNull()) {
throw std::ios_base::failure("Duplicate Key, peg-in genesis hash already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Peg-in genesis hash is more than one byte type");
}
UnserializeFromVector(s, genesis_hash);
break;
}
}
break;
}
// Unknown stuff
default:
if (unknown.count(key) > 0) {
@ -501,16 +277,6 @@ struct PSBTOutput
CScript redeem_script;
CScript witness_script;
std::map<CPubKey, KeyOriginInfo> hd_keypaths;
CPubKey blinding_pubkey;
CConfidentialValue value_commitment;
uint256 value_blinding_factor;
CConfidentialAsset asset_commitment;
uint256 asset_blinding_factor;
CConfidentialNonce nonce_commitment;
std::vector<unsigned char> range_proof;
std::vector<unsigned char> surjection_proof;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
bool IsNull() const;
@ -536,49 +302,6 @@ struct PSBTOutput
// Write any hd keypaths
SerializeHDKeypaths(s, hd_keypaths, PSBT_OUT_BIP32_DERIVATION);
if (g_con_elementsmode) {
// Write the Confidential Assets blinding data
if (!value_commitment.IsNull()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_VALUE_COMMITMENT);
SerializeToVector(s, value_commitment);
}
if (!value_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_VALUE_BLINDER);
SerializeToVector(s, value_blinding_factor);
}
if (!asset_commitment.IsNull()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_ASSET_COMMITMENT);
SerializeToVector(s, asset_commitment);
}
if (!asset_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_ASSET_BLINDER);
SerializeToVector(s, asset_blinding_factor);
}
if (!nonce_commitment.IsNull()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_NONCE_COMMITMENT);
SerializeToVector(s, nonce_commitment);
}
if (!range_proof.empty()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_RANGE_PROOF);
s << range_proof;
}
if (!surjection_proof.empty()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_SURJECTION_PROOF);
s << surjection_proof;
}
if (blinding_pubkey.IsValid()) {
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_BLINDING_PUBKEY);
s << blinding_pubkey;
}
}
// Write unknown things
for (auto& entry : unknown) {
s << entry.first;
@ -638,104 +361,6 @@ struct PSBTOutput
DeserializeHDKeypaths(s, key, hd_keypaths);
break;
}
case PSBT_OUT_PROPRIETARY:
{
VectorReader skey(s.GetType(), s.GetVersion(), key, 1);
std::string identifier;
skey >> identifier;
if (identifier != PSBT_ELEMENTS_ID) {
// This is not our proprietary type, skip it
continue;
}
size_t subkey_len = skey.size();
uint64_t subtype = ReadCompactSize(skey);
switch(subtype) {
case PSBT_OUT_VALUE_COMMITMENT:
{
if (!value_commitment.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output value_commitment already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output value_commitment key is more than one byte type");
}
UnserializeFromVector(s, value_commitment);
break;
}
case PSBT_OUT_VALUE_BLINDER:
{
if (!value_blinding_factor.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output value_blinding_factor already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output value_blinding_factor key is more than one byte type");
}
UnserializeFromVector(s, value_blinding_factor);
break;
}
case PSBT_OUT_ASSET_COMMITMENT:
{
if (!asset_commitment.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output asset_commitment already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output asset_commitment key is more than one byte type");
}
UnserializeFromVector(s, asset_commitment);
break;
}
case PSBT_OUT_ASSET_BLINDER:
{
if (!asset_blinding_factor.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output asset_blinding_factor already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output asset_blinding_factor key is more than one byte type");
}
UnserializeFromVector(s, asset_blinding_factor);
break;
}
case PSBT_OUT_NONCE_COMMITMENT:
{
if (!nonce_commitment.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output nonce_commitment already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output nonce_commitment key is more than one byte type");
}
UnserializeFromVector(s, nonce_commitment);
break;
}
case PSBT_OUT_RANGE_PROOF:
{
if (!range_proof.empty()) {
throw std::ios_base::failure("Duplicate Key, output range_proof already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output range_proof key is more than one byte type");
}
s >> range_proof;
break;
}
case PSBT_OUT_SURJECTION_PROOF:
{
if (!surjection_proof.empty()) {
throw std::ios_base::failure("Duplicate Key, output surjection_proof already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output surjection_proof key is more than one byte type");
}
s >> surjection_proof;
break;
}
case PSBT_OUT_BLINDING_PUBKEY:
{
if (blinding_pubkey.IsValid()) {
throw std::ios_base::failure("Duplicate Key, output blinding_pubkey already provided");
} else if (subkey_len != 1) {
throw std::ios_base::failure("Output blinding_pubkey key is more than one byte type");
}
s >> blinding_pubkey;
break;
}
}
break;
}
// Unknown stuff
default: {
if (unknown.count(key) > 0) {
@ -773,7 +398,7 @@ struct PartiallySignedTransaction
/** Merge psbt into this. The two psbts must have the same underlying CTransaction (i.e. the
* same actual Bitcoin transaction.) Returns true if the merge succeeded, false otherwise. */
NODISCARD bool Merge(const PartiallySignedTransaction& psbt);
[[nodiscard]] bool Merge(const PartiallySignedTransaction& psbt);
bool AddInput(const CTxIn& txin, PSBTInput& psbtin);
bool AddOutput(const CTxOut& txout, const PSBTOutput& psbtout);
PartiallySignedTransaction() {}
@ -791,11 +416,7 @@ struct PartiallySignedTransaction
inline void Serialize(Stream& s) const {
// magic bytes
if (g_con_elementsmode) {
s << PSBT_ELEMENTS_MAGIC_BYTES;
} else {
s << PSBT_MAGIC_BYTES;
}
s << PSBT_MAGIC_BYTES;
// unsigned tx flag
SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX);
@ -829,14 +450,8 @@ struct PartiallySignedTransaction
// Read the magic bytes
uint8_t magic[5];
s >> magic;
if (g_con_elementsmode) {
if (!std::equal(magic, magic + 5, PSBT_ELEMENTS_MAGIC_BYTES)) {
throw std::ios_base::failure("Invalid PSBT magic bytes");
}
} else {
if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) {
throw std::ios_base::failure("Invalid PSBT magic bytes");
}
if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) {
throw std::ios_base::failure("Invalid PSBT magic bytes");
}
// Used for duplicate key detection
@ -874,7 +489,6 @@ struct PartiallySignedTransaction
UnserializeFromVector(os, mtx);
tx = std::move(mtx);
// Make sure that all scriptSigs and scriptWitnesses are empty
tx->witness.vtxinwit.resize(tx->vin.size());
for (unsigned int i = 0; i < tx->vin.size(); i++) {
const CTxIn& txin = tx->vin[i];
if (!txin.scriptSig.empty() || !tx->witness.vtxinwit[i].scriptWitness.IsNull()) {
@ -992,16 +606,13 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
* @param[in] psbtxs the PSBTs to combine
* @return error (OK if we successfully combined the transactions, other error if they were not compatible)
*/
NODISCARD TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
[[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);
[[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);
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
std::string EncodePSBT(const PartiallySignedTransaction& psbt);
/** Check that the blinder did not tamper with the values in a blinded PSBT. */
bool CheckPSBTBlinding(const PartiallySignedTransaction& psbtx, std::string& error);
#endif // BITCOIN_PSBT_H

View file

@ -1059,6 +1059,8 @@ static RPCHelpMan blindpsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
throw std::runtime_error("RPC disabled");
/*
if (!g_con_elementsmode)
throw std::runtime_error("PSBT operations are disabled when not in elementsmode.\n");
@ -1160,6 +1162,7 @@ static RPCHelpMan blindpsbt()
}
return EncodePSBT(psbtx);
*/
},
};
}
@ -1295,6 +1298,8 @@ static RPCHelpMan decodepsbt()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
throw std::runtime_error("RPC disabled");
/*
if (!g_con_elementsmode)
throw std::runtime_error("PSBT operations are disabled when not in elementsmode.\n");
@ -1569,6 +1574,7 @@ static RPCHelpMan decodepsbt()
result.pushKV("outputs", outputs);
return result;
*/
},
};
}
@ -1760,6 +1766,7 @@ static RPCHelpMan createpsbt()
// Make a blank psbt
PartiallySignedTransaction psbtx(rawTx);
/*
for (unsigned int i = 0; i < rawTx.vout.size(); ++i) {
psbtx.outputs[i].blinding_pubkey = output_pubkeys[i];
}
@ -1799,6 +1806,7 @@ static RPCHelpMan createpsbt()
psbtx.tx->vin[i].m_is_pegin = false;
}
}
*/
return EncodePSBT(psbtx);
},
@ -1870,11 +1878,13 @@ static RPCHelpMan converttopsbt()
}
for (unsigned int i = 0; i < tx.vout.size(); ++i) {
psbtx.outputs.push_back(PSBTOutput());
/*
// At this point, if the nonce field is present it should be a smuggled
// pubkey, and not a real nonce. Convert it back to a pubkey and strip
// it out.
psbtx.outputs[i].blinding_pubkey = CPubKey(tx.vout[i].nNonce.vchCommitment);
tx.vout[i].nNonce.SetNull();
*/
}
psbtx.tx = tx;

View file

@ -4769,9 +4769,11 @@ static RPCHelpMan walletsignpsbt()
if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
/*
if (!CheckPSBTBlinding(psbtx, error)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, error);
}
*/
// Get the sighash type
int nHashType = ParseSighashString(request.params[1]);
@ -5002,6 +5004,7 @@ static RPCHelpMan walletcreatefundedpsbt()
// Make a blank psbt
PartiallySignedTransaction psbtx(rawTx);
/*
for (unsigned int i = 0; i < rawTx.vout.size(); ++i) {
if (!psbtx.tx->vout[i].nNonce.IsNull()) {
// Extract blinding key and clear the nonce
@ -5009,6 +5012,7 @@ static RPCHelpMan walletcreatefundedpsbt()
psbtx.tx->vout[i].nNonce.SetNull();
}
}
*/
// Fill transaction with out data but don't sign
bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
@ -5018,6 +5022,7 @@ static RPCHelpMan walletcreatefundedpsbt()
throw JSONRPCTransactionError(err);
}
/*
// Add peg-in stuff if it's there
for (unsigned int i = 0; i < rawTx.vin.size(); ++i) {
if (psbtx.tx->vin[i].m_is_pegin) {
@ -5053,6 +5058,7 @@ static RPCHelpMan walletcreatefundedpsbt()
psbtx.tx->vin[i].m_is_pegin = false;
}
}
*/
// Serialize the PSBT
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);

View file

@ -2732,12 +2732,14 @@ TransactionError CWallet::FillPSBTData(PartiallySignedTransaction& psbtx, bool b
// The signing code will switch to the smaller witness_utxo if this is ok.
input.non_witness_utxo = wtx.tx;
/*
// ELEMENTS: Grab the CA data
CAmount val_tmp;
wtx.GetNonIssuanceBlindingData(txin.prevout.n, nullptr, &val_tmp, &input.value_blinding_factor, &input.asset, &input.asset_blinding_factor);
if (val_tmp != -1) {
input.value = val_tmp;
}
*/
}
}
}
@ -2798,6 +2800,7 @@ TransactionError CWallet::FillPSBTData(PartiallySignedTransaction& psbtx, bool b
TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& complete, int sighash_type, bool sign, bool imbalance_ok, bool bip32derivs, size_t* n_signed) const
{
/*
// If we're signing, check that the transaction is not still in need of blinding
if (sign) {
for (const PSBTOutput& o : psbtx.outputs) {
@ -2806,6 +2809,7 @@ TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& comp
}
}
}
*/
if (n_signed) {
*n_signed = 0;
@ -2818,6 +2822,7 @@ TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& comp
CMutableTransaction& tx = *psbtx.tx;
tx.witness.vtxoutwit.resize(tx.vout.size());
/*
// Stuff in auxiliary CA blinding data, if we have it
for (unsigned int i = 0; i < tx.vout.size(); ++i) {
PSBTOutput& output = psbtx.outputs.at(i);
@ -2891,6 +2896,7 @@ TransactionError CWallet::SignPSBT(PartiallySignedTransaction& psbtx, bool& comp
return TransactionError::VALUE_IMBALANCE;
}
}
*/
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
int n_signed_this_spkm = 0;