mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-17 13:07:54 +02:00
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:
parent
eda3fbe212
commit
fdf71def4c
5 changed files with 35 additions and 503 deletions
113
src/psbt.cpp
113
src/psbt.cpp
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
403
src/psbt.h
403
src/psbt.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue