Skip to content

Commit 9a15459

Browse files
committed
Merge #900: Redesign PSET
f8553c5 Disable joinpsbts (Andrew Chow) 864f625 Fix display of outputs in PSBT ops dialog (Andrew Chow) 5425da4 Enable converttopsbt for PSET (Andrew Chow) 4940cee Use a constant for maximum surjection targets (Andrew Chow) 4a44ff2 Check elements blinding field constraints during deser (Andrew Chow) 9fe6401 Allow specifying SIGHASH_RANGEPROOF (Andrew Chow) 7533503 Initialize optionals with nullopt (Andrew Chow) 64b30bf Enable analyzepsbt (Andrew Chow) b65a00f Add PSBTOutput::GetTxOut() (Andrew Chow) 80ff739 Default to adding bip32 derivs (Andrew Chow) 1889554 Remove unnecessary psbt blinding test (Andrew Chow) afd7950 Update rpc_psbt.py for PSET (Andrew Chow) 46ccf61 Only allow psbt_version 2 (Andrew Chow) b1ebc81 Remove walletsignpsbt, blindpsbt, walletblindpsbt, and walletfillpsbtdata (Andrew Chow) d8fa5c1 Use createtx array outputs (Andrew Chow) 0e2f1ff Make m_peg_in_witness during SignPSBTInput (Andrew Chow) bd97836 Update FinalizeAndExtract for PSEt (Andrew Chow) c0cb623 Allow value commitments instead of explicit value (Andrew Chow) 2c0cee5 Update GetUnsignedTx for PSET (Andrew Chow) 25df8aa Fixes to FillPSBT (Andrew Chow) e9bfff2 Allow empty scriptPubKeys (Andrew Chow) eeb6cf7 Mark PSET as being implemented (Andrew Chow) 3db2622 Only sign blinded PSBTs in walletprocesspsbt (Andrew Chow) a8a6f4c Add IsBlinded and IsFullyBlinded helpers for PSBT (Andrew Chow) 124efa2 Return better errors for BlindingStatus (Andrew Chow) f686e0f Remove walletfillpsbtdata RPC (Andrew Chow) 5391095 Output PSBTOutputs with aux info from ConstructTransaction (Andrew Chow) ea2c3df Remove output_assets and have asset field in outputs (Andrew Chow) e6cc0fd Have walletprocesspsbt blind before signing (Andrew Chow) bad1876 Re-enable and fix PSBT signing (Andrew Chow) 9a450ec Set blinder_index to self in walletcreatefundedpsbt (Andrew Chow) 3f6c8bf Add walletblindpsbt rpc (Andrew Chow) e7dd046 Implement BlindPSBT (Andrew Chow) 1dbc3b2 Implement updatepsbtpegin RPC (Andrew Chow) bdfcb43 Add calculateasset RPC (Andrew Chow) 79c4a99 pset: add issuance things (Andrew Chow) 6890461 Implement blinded combiner stuff (Andrew Chow) 2220d84 Return peg-in UTXO with GetUTXO (Andrew Chow) 33c694f Helper functions to determine whether a PSBTOutput is blinded (Andrew Chow) ee28be3 Extract elements fields for tx into psbt (Andrew Chow) f84a927 Add DecomposePeginWitness (Andrew Chow) e374397 Implement and enable decodepsbt for PSET (Andrew Chow) b372430 Implement PSET fields and their de/ser (Andrew Chow) ecaf5ea Use GetUnsignedTx when serializing in PSBTv0 (Andrew Chow) e860cd0 Add a PSBT constructor for providing the version (Andrew Chow) 0ca0b7e Update rpc_psbt.py to test PSBTv0 explicitly in some places (Andrew Chow) f4bca18 Restrict joinpsbts to PSBTv0 only (Andrew Chow) ebc49e3 Allow createpsbt and walletcreatefundedpsbt to take psbt version (Andrew Chow) 2c1fe58 Allow and create PSBTv2 in RPCs (Andrew Chow) e467ec6 Update PSBT::UpdatePSBTOutput to use GetUnsignedTx (Andrew Chow) a34474e Allow specifying PSBT version in constructor (Andrew Chow) bedc1e0 Implement PSBTv2 in decodepsbt (Andrew Chow) 139ac36 Implement PSBTv2 AddInput and AddOutput (Andrew Chow) 16395c1 Update wallet for PSBTv2 (Andrew Chow) 9c83300 Update RPCs for PSBTv2 (Andrew Chow) c9c23ca Update PSBT Operations Dialog for v2 (Andrew Chow) 500554a Update AnalyzePSBT for PSBTv2 (Andrew Chow) f269d11 Update FinalizeAndExtract for v2 (Andrew Chow) 23f6442 Update SignPSBTInput for PSBTv2 (Andrew Chow) d8dba33 Add PSBTInput::GetOutPoint (Andrew Chow) 4ff2593 Implement PSBTv2 field merging (Andrew Chow) cd5515a Change PSBT::AddOutput to take just PSBTOutput (Andrew Chow) 90cd7ec Change PSBT::AddInput to take just PSBTInput (Andrew Chow) bd1a57b Add PSBT::GetUniqueID (Andrew Chow) 32bdf2d Add PSBT::GetUnsignedTx (Andrew Chow) 10bf247 Add PSBT::ComputeLockTime() (Andrew Chow) 3c647b7 Replace PSBT::GetInputUTXO with PSBTInput::GetUTXO (Andrew Chow) 4b805fd Convert PSBTv0 unsigned tx to PSBTv2 fields (Andrew Chow) 32234df Call CacheUnsignedTxPieces in PSBT constructor (Andrew Chow) c32950e Add PSBT::CacheUnsignedTxPieces (Andrew Chow) 457b6bd Enforce PSBT version constraints (Andrew Chow) 2042765 Have PSBTInput and PSBTOutput know the PSBT's version (Andrew Chow) 8c62443 Change PSBT unknown fields test to use higher numbers (Andrew Chow) dd792ce Implement PSBTv2 fields de/ser (Andrew Chow) ec03f83 Define psbtv2 field numbers (Andrew Chow) 20e8dff Merge global xpubs in joinpsbts and combinepsbts (Andrew Chow) bc2651d Add global xpub test vectors from BIP (Andrew Chow) 7fd50b2 Add global_xpubs to decodepsbt (Andrew Chow) 2c54175 Implement serializations for PSBT_GLOBAL_XPUB (Andrew Chow) 5b5c5ef Implement operator< for KeyOriginInfo and CExtPubKey (Andrew Chow) 4eabba9 Separate individual HD Keypath serialization into separate functions (Andrew Chow) cb9c553 Store version bytes and be able to serialize them in CExtPubKey (Andrew Chow) fad29ba moveonly: Move (Un)Serialize(To/From)Vector, (De)SerializeHDKeypaths to psbt module (Andrew Chow) 31a7e0a Test for proprietary field (Andrew Chow) 5bb930e Output proprietary type info in decodepsbt (Andrew Chow) 575fec0 Implement PSBT proprietary type (Andrew Chow) 25c13ad Output psbt version in decodepsbt (Andrew Chow) ad2b2d7 Add GetVersion helper to PSBT (Andrew Chow) 50c281f Implement PSBT versions (Andrew Chow) e882a3a Types are compact size uints (Andrew Chow) fdf71de Remove PSET and disable PSBT/PSET things for now (Andrew Chow) Pull request description: The original PSET had some issues with leaking private information and there were issues with the design of the various roles. This PR replaces it with a new PSET design that should be able to provide all of the things that people expect PSETs to do while preserving privacy. Additionally, an actual specification for this new design has been written up. It describes all of the new fields, their serialization, and how roles should handle the PSET data. This is still a work in progress as not everything with the blinder role has been worked out yet. Top commit has no ACKs. Tree-SHA512: 69f6f74dd252e4fba14e201f8f1d9b017b3b62ddf375e6536e71a3f327435e7c1ef8a12b2914cbed3e46f70bcbc8caadc07342ee323ece45a47dd1d77d81b3e8
2 parents 0355e30 + f8553c5 commit 9a15459

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3736
-1682
lines changed

doc/pset.mediawiki

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
Note that this format is not yet implemented by Elements.
2-
31
<pre>
42
BIP: PSET
53
Layer: Applications

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ BITCOIN_CORE_H = \
115115
bech32.h \
116116
blech32.h \
117117
blind.h \
118+
blindpsbt.h \
118119
blockencodings.h \
119120
blockfilter.h \
120121
block_proof.h \
@@ -523,6 +524,7 @@ libbitcoin_common_a_SOURCES = \
523524
bech32.cpp \
524525
blech32.cpp \
525526
blind.cpp \
527+
blindpsbt.cpp \
526528
block_proof.cpp \
527529
bloom.cpp \
528530
chainparams.cpp \

src/blind.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <random.h>
1212
#include <util/system.h>
1313

14-
static secp256k1_context* secp256k1_blind_context = NULL;
14+
secp256k1_context* secp256k1_blind_context = NULL;
1515

1616
class Blind_ECC_Init {
1717
public:
@@ -192,7 +192,7 @@ bool SurjectOutput(CTxOutWitness& txoutwit, const std::vector<secp256k1_fixed_as
192192
{
193193
int ret;
194194
// 1 to 3 targets
195-
size_t nInputsToSelect = std::min((size_t)3, surjection_targets.size());
195+
size_t nInputsToSelect = std::min(MAX_SURJECTION_TARGETS, surjection_targets.size());
196196
unsigned char randseed[32];
197197
GetStrongRandBytes(randseed, 32);
198198
size_t input_index;

src/blind.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ static const size_t MAX_RANGEPROOF_SIZE = 5126;
2323
static const size_t DEFAULT_SURJECTIONPROOF_SIZE = 135;
2424
// 32 bytes of asset type, 32 bytes of asset blinding factor in sidechannel
2525
static const size_t SIDECHANNEL_MSG_SIZE = 64;
26+
// Maximum number of inputs to select for surjection proof
27+
static const size_t MAX_SURJECTION_TARGETS = 3;
28+
29+
// Blinding context
30+
extern secp256k1_context* secp256k1_blind_context;
2631

2732
/*
2833
* Verify a pair of confidential asset and value, given the blinding factors for both.

src/blindpsbt.cpp

Lines changed: 426 additions & 0 deletions
Large diffs are not rendered by default.

src/blindpsbt.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2020 The Elements Core developers
2+
// // Distributed under the MIT software license, see the accompanying
3+
// // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_BLINDPSBT_H
6+
#define BITCOIN_BLINDPSBT_H
7+
8+
#include <blind.h>
9+
#include <key.h>
10+
#include <pubkey.h>
11+
#include <primitives/transaction.h>
12+
#include <primitives/confidential.h>
13+
14+
#include <secp256k1.h>
15+
#include <secp256k1_rangeproof.h>
16+
#include <secp256k1_surjectionproof.h>
17+
18+
struct PartiallySignedTransaction;
19+
20+
enum class BlindingStatus
21+
{
22+
OK, //!< No error
23+
NEEDS_UTXOS,
24+
INVALID_ASSET,
25+
INVALID_ASSET_COMMITMENT,
26+
SCALAR_UNABLE,
27+
INVALID_BLINDER,
28+
ASP_UNABLE,
29+
};
30+
31+
std::string GetBlindingStatusError(const BlindingStatus& status);
32+
33+
bool CreateAssetSurjectionProof(std::vector<unsigned char>& output_proof, const std::vector<secp256k1_fixed_asset_tag>& fixed_input_tags, const std::vector<secp256k1_generator>& ephemeral_input_tags, const std::vector<uint256>& input_asset_blinders, const uint256& output_asset_blinder, const secp256k1_generator& output_asset_tag, const CAsset& asset);
34+
uint256 GenerateRangeproofECDHKey(CPubKey& ephemeral_pubkey, const CPubKey blinding_pubkey);
35+
bool CreateValueRangeProof(std::vector<unsigned char>& rangeproof, const uint256& value_blinder, const uint256& nonce, const CAmount amount, const CScript& scriptPubKey, const secp256k1_pedersen_commitment& value_commit, const secp256k1_generator& gen, const CAsset& asset, const uint256& asset_blinder);
36+
void CreateAssetCommitment(CConfidentialAsset& conf_asset, secp256k1_generator& asset_gen, const CAsset& asset, const uint256& asset_blinder);
37+
void CreateValueCommitment(CConfidentialValue& conf_value, secp256k1_pedersen_commitment& value_commit, const uint256& value_blinder, const secp256k1_generator& asset_gen, const CAmount amount);
38+
BlindingStatus BlindPSBT(PartiallySignedTransaction& psbt, std::map<uint32_t, std::tuple<CAmount, CAsset, uint256, uint256>> our_input_data, std::map<uint32_t, std::pair<CKey, CKey>> our_issuances_to_blind);
39+
40+
#endif //BITCOIN_BLINDPSBT_H

src/core_read.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,16 @@ int ParseSighashString(const UniValue& sighash)
214214
static std::map<std::string, int> map_sighash_values = {
215215
{std::string("ALL"), int(SIGHASH_ALL)},
216216
{std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
217+
{std::string("ALL|RANGEPROOF"), int(SIGHASH_ALL|SIGHASH_RANGEPROOF)},
218+
{std::string("ALL|ANYONECANPAY|RANGEPROOF"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY|SIGHASH_RANGEPROOF)},
217219
{std::string("NONE"), int(SIGHASH_NONE)},
218220
{std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
221+
{std::string("NONE|RANGEPROOF"), int(SIGHASH_NONE|SIGHASH_RANGEPROOF)},
222+
{std::string("NONE|ANYONECANPAY|RANGEPROOF"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY|SIGHASH_RANGEPROOF)},
219223
{std::string("SINGLE"), int(SIGHASH_SINGLE)},
220224
{std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
225+
{std::string("SINGLE|RANGEPROOF"), int(SIGHASH_SINGLE|SIGHASH_RANGEPROOF)},
226+
{std::string("SINGLE|ANYONECANPAY|RANGEPROOF"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY|SIGHASH_RANGEPROOF)},
221227
};
222228
std::string strHashType = sighash.get_str();
223229
const auto& it = map_sighash_values.find(strHashType);

src/node/psbt.cpp

Lines changed: 72 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
1717
// Go through each input and build status
1818
PSBTAnalysis result;
1919

20-
bool calc_fee = true;
21-
CAmountMap in_amts;
20+
// Elements things
21+
bool needs_blinded_outputs = false;
22+
bool has_blinded_outputs = false;
2223

23-
result.inputs.resize(psbtx.tx->vin.size());
24+
result.inputs.resize(psbtx.inputs.size());
2425

25-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
26+
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
2627
PSBTInput& input = psbtx.inputs[i];
2728
PSBTInputAnalysis& input_analysis = result.inputs[i];
2829

@@ -31,23 +32,24 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
3132

3233
// Check for a UTXO
3334
CTxOut utxo;
34-
if (psbtx.GetInputUTXO(utxo, i)) {
35-
//TODO(gwillen) do PSBT inputs always have explicit assets & amounts?
36-
if (!MoneyRange(utxo.nValue.GetAmount()) || !MoneyRange(in_amts[utxo.nAsset.GetAsset()] + utxo.nValue.GetAmount())) {
37-
result.SetInvalid(strprintf("PSBT is not valid. Input %u has invalid value", i));
38-
return result;
35+
if (input.GetUTXO(utxo)) {
36+
if (utxo.nValue.IsExplicit()) {
37+
if (!MoneyRange(utxo.nValue.GetAmount())) {
38+
result.SetInvalid(strprintf("PSBT is not valid. Input %u has invalid value", i));
39+
return result;
40+
}
41+
} else {
42+
needs_blinded_outputs = true;
3943
}
40-
in_amts[utxo.nAsset.GetAsset()] += utxo.nValue.GetAmount();
4144
input_analysis.has_utxo = true;
4245
} else {
43-
if (input.non_witness_utxo && psbtx.tx->vin[i].prevout.n >= input.non_witness_utxo->vout.size()) {
46+
if (input.non_witness_utxo && *input.prev_out >= input.non_witness_utxo->vout.size()) {
4447
result.SetInvalid(strprintf("PSBT is not valid. Input %u specifies invalid prevout", i));
4548
return result;
4649
}
4750
input_analysis.has_utxo = false;
4851
input_analysis.is_final = false;
4952
input_analysis.next = PSBTRole::UPDATER;
50-
calc_fee = false;
5153
}
5254

5355
if (!utxo.IsNull() && utxo.scriptPubKey.IsUnspendable()) {
@@ -84,71 +86,77 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
8486
}
8587
}
8688

87-
// Calculate next role for PSBT by grabbing "minimum" PSBTInput next role
88-
result.next = PSBTRole::EXTRACTOR;
89-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
90-
PSBTInputAnalysis& input_analysis = result.inputs[i];
91-
result.next = std::min(result.next, input_analysis.next);
92-
}
93-
assert(result.next > PSBTRole::CREATOR);
94-
95-
if (calc_fee) {
96-
// Get the output amount
97-
CAmountMap out_amts = std::accumulate(psbtx.tx->vout.begin(), psbtx.tx->vout.end(), CAmountMap(),
98-
[](CAmountMap a, const CTxOut& b) {
99-
CAmount acc = a[b.nAsset.GetAsset()];
100-
CAmount add = b.nValue.GetAmount();
101-
102-
if (!MoneyRange(acc) || !MoneyRange(add) || !MoneyRange(acc + add)) {
103-
CAmountMap invalid;
104-
invalid[::policyAsset] = CAmount(-1);
105-
return invalid;
89+
for (const PSBTOutput& output : psbtx.outputs) {
90+
CTxOut txout = output.GetTxOut();
91+
if (output.IsBlinded()) {
92+
has_blinded_outputs = true;
93+
if (!output.IsFullyBlinded()) {
94+
result.next = PSBTRole::BLINDER;
95+
}
96+
} else {
97+
// Find the fee output
98+
if (txout.IsFee()) {
99+
if (result.fee != nullopt) {
100+
result.SetInvalid("There is more than one fee output");
101+
return result;
106102
}
107-
a[b.nAsset.GetAsset()] += add;
108-
return a;
103+
result.fee = output.amount;
109104
}
110-
);
111-
if (!MoneyRange(out_amts)) {
112-
result.SetInvalid(strprintf("PSBT is not valid. Output amount invalid"));
105+
}
106+
if (txout.nValue.IsExplicit() && !MoneyRange(txout.nValue.GetAmount())) {
107+
result.SetInvalid("PSBT is not valid. Output amount invalid");
113108
return result;
114109
}
110+
}
115111

116-
// Get the fee
117-
CAmountMap fee = in_amts - out_amts;
118-
result.fee = fee;
112+
if (result.fee == nullopt) {
113+
result.SetInvalid("PSBT missing required fee output");
114+
return result;
115+
}
119116

120-
// Estimate the size
121-
CMutableTransaction mtx(*psbtx.tx);
122-
CCoinsView view_dummy;
123-
CCoinsViewCache view(&view_dummy);
124-
bool success = true;
117+
if (needs_blinded_outputs && !has_blinded_outputs) {
118+
result.SetInvalid("PSBT has blinded inputs but no blinded outputs. Must have at least one blinded output to balance with the inputs");
119+
return result;
120+
}
125121

126-
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
127-
PSBTInput& input = psbtx.inputs[i];
128-
Coin newcoin;
122+
// Estimate the size
123+
CMutableTransaction mtx(psbtx.GetUnsignedTx());
124+
CCoinsView view_dummy;
125+
CCoinsViewCache view(&view_dummy);
126+
bool success = true;
129127

130-
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !psbtx.GetInputUTXO(newcoin.out, i)) {
131-
success = false;
132-
break;
133-
} else {
134-
mtx.vin[i].scriptSig = input.final_script_sig;
135-
mtx.witness.vtxinwit[i].scriptWitness = input.final_script_witness;
136-
newcoin.nHeight = 1;
137-
view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
138-
}
139-
}
128+
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
129+
PSBTInput& input = psbtx.inputs[i];
130+
Coin newcoin;
140131

141-
if (success) {
142-
CTransaction ctx = CTransaction(mtx);
143-
size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
144-
result.estimated_vsize = size;
145-
// Estimate fee rate
146-
CFeeRate feerate(fee[::policyAsset], size);
147-
result.estimated_feerate = feerate;
132+
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, 1, nullptr, true) || !input.GetUTXO(newcoin.out)) {
133+
success = false;
134+
break;
135+
} else {
136+
mtx.vin[i].scriptSig = input.final_script_sig;
137+
mtx.witness.vtxinwit[i].scriptWitness = input.final_script_witness;
138+
newcoin.nHeight = 1;
139+
view.AddCoin(input.GetOutPoint(), std::move(newcoin), true);
148140
}
141+
}
149142

143+
if (success) {
144+
CTransaction ctx = CTransaction(mtx);
145+
size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
146+
result.estimated_vsize = size;
147+
// Estimate fee rate
148+
CFeeRate feerate(*result.fee, size);
149+
result.estimated_feerate = feerate;
150150
}
151151

152+
// Calculate next role for PSBT by grabbing "minimum" PSBTInput next role
153+
result.next = PSBTRole::EXTRACTOR;
154+
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
155+
PSBTInputAnalysis& input_analysis = result.inputs[i];
156+
result.next = std::min(result.next, input_analysis.next);
157+
}
158+
assert(result.next > PSBTRole::CREATOR);
159+
152160
return result;
153161
}
154162

src/node/psbt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct PSBTInputAnalysis {
2727
struct PSBTAnalysis {
2828
Optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
2929
Optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
30-
Optional<CAmountMap> fee; //!< Amount of fee being paid by the transaction
30+
Optional<CAmount> fee; //!< Amount of fee being paid by the transaction
3131
std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
3232
PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
3333
std::string error; //!< Error message

src/pegins.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,3 +533,46 @@ CScriptWitness CreatePeginWitness(const CAmount& value, const CAsset& asset, con
533533
{
534534
return CreatePeginWitnessInner(value, asset, genesis_hash, claim_script, tx_ref, merkle_block);
535535
}
536+
537+
bool DecomposePeginWitness(const CScriptWitness& witness, CAmount& value, CAsset& asset, uint256& genesis_hash, CScript& claim_script, boost::variant<boost::blank, Sidechain::Bitcoin::CTransactionRef, CTransactionRef>& tx, boost::variant<boost::blank, Sidechain::Bitcoin::CMerkleBlock, CMerkleBlock>& merkle_block)
538+
{
539+
const auto& stack = witness.stack;
540+
541+
if (stack.size() < 5) return false;
542+
543+
CDataStream stream(stack[0], SER_NETWORK, PROTOCOL_VERSION);
544+
stream >> value;
545+
546+
CAsset tmp_asset(stack[1]);
547+
asset = tmp_asset;
548+
549+
uint256 gh(stack[2]);
550+
genesis_hash = gh;
551+
552+
CScript s(stack[3].begin(), stack[3].end());
553+
claim_script = s;
554+
555+
CDataStream ss_tx(stack[4], SER_NETWORK, PROTOCOL_VERSION);
556+
if (Params().GetConsensus().ParentChainHasPow()) {
557+
Sidechain::Bitcoin::CTransactionRef btc_tx;
558+
ss_tx >> btc_tx;
559+
tx = btc_tx;
560+
} else {
561+
CTransactionRef elem_tx;
562+
ss_tx >> elem_tx;
563+
tx = elem_tx;
564+
}
565+
566+
CDataStream ss_proof(stack[5], SER_NETWORK, PROTOCOL_VERSION);
567+
if (Params().GetConsensus().ParentChainHasPow()) {
568+
Sidechain::Bitcoin::CMerkleBlock tx_proof;
569+
ss_proof >> tx_proof;
570+
merkle_block = tx_proof;
571+
} else {
572+
CMerkleBlock tx_proof;
573+
ss_proof >> tx_proof;
574+
merkle_block = tx_proof;
575+
}
576+
577+
return true;
578+
}

0 commit comments

Comments
 (0)