mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-14 12:43:40 +02:00
Merge #751: Peg-in fields for PSBT
7cb5f6bb0Sign PSBTs with peg-in data (Andrew Chow)73711eb0bMerge psbt peg-in data (Andrew Chow)4ad849fedFinalize psbt peg-ins (Andrew Chow)b7e369505Test createpsbt and decodepsbt with peg-ins (Andrew Chow)8ece8e0a0Show peg-in info in decodepsbt (Andrew Chow)646e76f7dBe able to create peg-in PSBTs in createpegin (Andrew Chow)b5590b20cAdd peg-in PSBT fields (Andrew Chow) Pull request description: Adds peg-in fields for PSBT. `createpsbt` uses the new peg-in raw tx api to allow specifying the peg-in data and then adds it to the psbt. `decodepsbt`, `finalizepsbt` and `walletsignpsbt` are both updated to handle peg-in stuff too. Also tests. `walletcreatefundedpsbt` still does not handle peg-in data. It will require handling external inputs which the wallet does not do. I think it would be best to first implement external inputs in `FundTransaction` upstream before allowing `walletcreatefundedpsbt` to accept peg-ins. Tree-SHA512: 838c2cf0de78b6ad948aaec2932326e2e39b6645c98193c90eedaee7e5cd8ebe3e8ea00e3ba4a67d5f862948195f37aded0e6a08a7c3c20def325d4cabb78ee3
This commit is contained in:
commit
2949ea924f
6 changed files with 275 additions and 5 deletions
22
src/psbt.cpp
22
src/psbt.cpp
|
|
@ -2,6 +2,7 @@
|
|||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <pegins.h>
|
||||
#include <psbt.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <confidential_validation.h>
|
||||
|
|
@ -158,6 +159,11 @@ void PSBTInput::Merge(const PSBTInput& input)
|
|||
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;
|
||||
}
|
||||
|
||||
bool PSBTInput::IsSane() const
|
||||
|
|
@ -321,6 +327,22 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
|
|||
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());
|
||||
|
|
|
|||
117
src/psbt.h
117
src/psbt.h
|
|
@ -6,11 +6,17 @@
|
|||
#define BITCOIN_PSBT_H
|
||||
|
||||
#include <attributes.h>
|
||||
#include <chainparams.h>
|
||||
#include <node/transaction.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 <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};
|
||||
|
|
@ -35,6 +41,11 @@ 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;
|
||||
|
|
@ -77,6 +88,11 @@ struct PSBTInput
|
|||
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);
|
||||
|
|
@ -158,6 +174,49 @@ 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;
|
||||
|
|
@ -342,6 +401,64 @@ struct PSBTInput
|
|||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1660,6 +1660,10 @@ UniValue decodepsbt(const JSONRPCRequest& request)
|
|||
" \"value_blinding_factor\": \"hex\" , (string) The value blinding factor from the output being spent\n"
|
||||
" \"asset\": \"hex\" , (string) The (unblinded) asset id of the input\n"
|
||||
" \"asset_blinding_factor\": \"hex\" , (string) The asset blinding factor from the output being spent\n"
|
||||
" \"pegin_bitcoin_tx\": \"hex\", (string) The tx providing the peg-in in the format of the getrawtransaction RPC.\n"
|
||||
" \"pegin_claim_script\": \"hex\", (string) The claim script for the peg-in input\n"
|
||||
" \"pegin_txout_proof\": \"hex\", (string) The tx providing the peg-in input\n"
|
||||
" \"pegin_genesis_hash\": \"hex\", (string) The hash of the genesis block for this peg-in\n"
|
||||
" \"unknown\" : { (json object) The unknown input fields\n"
|
||||
" \"key\" : \"value\" (key-value pair) An unknown key-value pair\n"
|
||||
" ...\n"
|
||||
|
|
@ -1836,6 +1840,49 @@ UniValue decodepsbt(const JSONRPCRequest& request)
|
|||
in.pushKV("asset_blinding_factor", input.asset_blinding_factor.GetHex());
|
||||
}
|
||||
|
||||
// Peg-in stuff
|
||||
if (Params().GetConsensus().ParentChainHasPow()) {
|
||||
if (input.peg_in_tx.which() > 0) {
|
||||
const Sidechain::Bitcoin::CTransactionRef& btc_peg_in_tx = boost::get<Sidechain::Bitcoin::CTransactionRef>(input.peg_in_tx);
|
||||
if (btc_peg_in_tx) {
|
||||
CDataStream ss_tx(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
ss_tx << btc_peg_in_tx;
|
||||
in.pushKV("pegin_bitcoin_tx", HexStr(ss_tx.begin(), ss_tx.end()));
|
||||
}
|
||||
}
|
||||
if (input.txout_proof.which() > 0) {
|
||||
const Sidechain::Bitcoin::CMerkleBlock& btc_txout_proof = boost::get<Sidechain::Bitcoin::CMerkleBlock>(input.txout_proof);
|
||||
if (!btc_txout_proof.header.IsNull()) {
|
||||
CDataStream ss_mb(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
ss_mb << btc_txout_proof;
|
||||
in.pushKV("pegin_txout_proof", HexStr(ss_mb.begin(), ss_mb.end()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (input.peg_in_tx.which() > 0) {
|
||||
const CTransactionRef& elem_peg_in_tx = boost::get<CTransactionRef>(input.peg_in_tx);
|
||||
if (elem_peg_in_tx) {
|
||||
CDataStream ss_tx(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
ss_tx << elem_peg_in_tx;
|
||||
in.pushKV("pegin_bitcoin_tx", HexStr(ss_tx.begin(), ss_tx.end()));
|
||||
}
|
||||
}
|
||||
if (input.txout_proof.which() > 0) {
|
||||
const CMerkleBlock& elem_txout_proof = boost::get<CMerkleBlock>(input.txout_proof);
|
||||
if (!elem_txout_proof.header.IsNull()) {
|
||||
CDataStream ss_mb(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
ss_mb << elem_txout_proof;
|
||||
in.pushKV("pegin_txout_proof", HexStr(ss_mb.begin(), ss_mb.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!input.claim_script.empty()) {
|
||||
in.pushKV("pegin_claim_script", HexStr(input.claim_script.begin(), input.claim_script.end()));
|
||||
}
|
||||
if (!input.genesis_hash.IsNull()) {
|
||||
in.pushKV("pegin_genesis_hash", input.genesis_hash.GetHex());
|
||||
}
|
||||
|
||||
// Unknown data
|
||||
if (input.unknown.size() > 0) {
|
||||
UniValue unknowns(UniValue::VOBJ);
|
||||
|
|
@ -2062,6 +2109,9 @@ UniValue createpsbt(const JSONRPCRequest& request)
|
|||
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
|
||||
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
|
||||
{"sequence", RPCArg::Type::NUM, /* default */ "depends on the value of the 'replaceable' and 'locktime' arguments", "The sequence number"},
|
||||
{"pegin_bitcoin_tx", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The raw bitcoin transaction (in hex) depositing bitcoin to the mainchain_address generated by getpeginaddress"},
|
||||
{"pegin_txout_proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A rawtxoutproof (in hex) generated by the mainchain daemon's `gettxoutproof` containing a proof of only bitcoin_tx"},
|
||||
{"pegin_claim_script", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The witness program generated by getpeginaddress."},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -2111,7 +2161,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
|
|||
);
|
||||
|
||||
std::vector<CPubKey> output_pubkeys;
|
||||
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3], request.params[4], &output_pubkeys, false /* allow_peg_in */);
|
||||
CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3], request.params[4], &output_pubkeys);
|
||||
|
||||
// Make a blank psbt
|
||||
PartiallySignedTransaction psbtx(rawTx);
|
||||
|
|
@ -2119,6 +2169,42 @@ UniValue createpsbt(const JSONRPCRequest& request)
|
|||
psbtx.outputs[i].blinding_pubkey = output_pubkeys[i];
|
||||
}
|
||||
|
||||
// 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) {
|
||||
CScriptWitness& pegin_witness = psbtx.tx->witness.vtxinwit[i].m_pegin_witness;
|
||||
CAmount val;
|
||||
VectorReader vr_val(SER_NETWORK, PROTOCOL_VERSION, pegin_witness.stack[0], 0);
|
||||
vr_val >> val;
|
||||
psbtx.inputs[i].value = val;
|
||||
VectorReader vr_asset(SER_NETWORK, PROTOCOL_VERSION, pegin_witness.stack[1], 0);
|
||||
vr_asset >> psbtx.inputs[i].asset;
|
||||
VectorReader vr_genesis(SER_NETWORK, PROTOCOL_VERSION, pegin_witness.stack[2], 0);
|
||||
vr_genesis >> psbtx.inputs[i].genesis_hash;
|
||||
psbtx.inputs[i].claim_script.assign(pegin_witness.stack[3].begin(), pegin_witness.stack[3].end());
|
||||
|
||||
VectorReader vr_tx(SER_NETWORK, PROTOCOL_VERSION, pegin_witness.stack[4], 0);
|
||||
VectorReader vr_proof(SER_NETWORK, PROTOCOL_VERSION, pegin_witness.stack[5], 0);
|
||||
if (Params().GetConsensus().ParentChainHasPow()) {
|
||||
Sidechain::Bitcoin::CTransactionRef tx_btc;
|
||||
vr_tx >> tx_btc;
|
||||
psbtx.inputs[i].peg_in_tx = tx_btc;
|
||||
Sidechain::Bitcoin::CMerkleBlock tx_proof;
|
||||
vr_proof >> tx_proof;
|
||||
psbtx.inputs[i].txout_proof = tx_proof;
|
||||
} else {
|
||||
CTransactionRef tx_btc;
|
||||
vr_tx >> tx_btc;
|
||||
psbtx.inputs[i].peg_in_tx = tx_btc;
|
||||
CMerkleBlock tx_proof;
|
||||
vr_proof >> tx_proof;
|
||||
psbtx.inputs[i].txout_proof = tx_proof;
|
||||
}
|
||||
pegin_witness.SetNull();
|
||||
psbtx.tx->vin[i].m_is_pegin = false;
|
||||
}
|
||||
}
|
||||
|
||||
return EncodePSBT(psbtx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <confidential_validation.h>
|
||||
#include <pegins.h>
|
||||
#include <wallet/psbtwallet.h>
|
||||
|
||||
TransactionError FillPSBTInputsData(const CWallet* pwallet, PartiallySignedTransaction& psbtx, bool bip32derivs)
|
||||
|
|
@ -95,6 +96,27 @@ TransactionError SignPSBT(const CWallet* pwallet, PartiallySignedTransaction& ps
|
|||
}
|
||||
}
|
||||
|
||||
// Stuff in the peg-in data
|
||||
for (unsigned int i = 0; i < tx.vin.size(); ++i) {
|
||||
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);
|
||||
}
|
||||
tx.vin[i].m_is_pegin = true;
|
||||
tx.witness.vtxinwit[i].m_pegin_witness = pegin_witness;
|
||||
// Set the witness utxo
|
||||
input.witness_utxo = GetPeginOutputFromWitness(tx.witness.vtxinwit[i].m_pegin_witness);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a convenience/usability check -- it's not invalid to sign an unbalanced transaction, but it's easy to shoot yourself in the foot.
|
||||
if (!imbalance_ok) {
|
||||
// Get UTXOs for all inputs, to check that amounts balance before signing.
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ class FedPegTest(BitcoinTestFramework):
|
|||
"-keypool=1",
|
||||
"-listenonion=0",
|
||||
"-addresstype=legacy", # To make sure bitcoind gives back p2pkh no matter version
|
||||
"-fallbackfee=0.0002"
|
||||
])
|
||||
else:
|
||||
extra_args.extend([
|
||||
|
|
@ -290,6 +291,31 @@ class FedPegTest(BitcoinTestFramework):
|
|||
# Check the createrawtransaction makes the same unsigned peg-in transaction
|
||||
raw_pegin2 = sidechain.createrawtransaction([{"txid":txid1, "vout": vout, "pegin_bitcoin_tx": raw, "pegin_txout_proof": proof, "pegin_claim_script": addrs["claim_script"]}], outputs)
|
||||
assert_equal(raw_pegin, raw_pegin2)
|
||||
# Check that createpsbt makes the correct unsigned peg-in
|
||||
pegin_psbt = sidechain.createpsbt([{"txid":txid1, "vout": vout, "pegin_bitcoin_tx": raw, "pegin_txout_proof": proof, "pegin_claim_script": addrs["claim_script"]}], outputs)
|
||||
decoded_psbt = sidechain.decodepsbt(pegin_psbt)
|
||||
# Check that pegin_bitcoin_tx == raw, but due to stripping witnesses, we need to compare their txids
|
||||
txid1 = parent.decoderawtransaction(decoded_psbt['inputs'][0]['pegin_bitcoin_tx'])['txid']
|
||||
txid2 = parent.decoderawtransaction(raw)['txid']
|
||||
assert_equal(txid1, txid2)
|
||||
# Check the rest
|
||||
assert_equal(decoded_psbt['inputs'][0]['pegin_claim_script'], addrs["claim_script"])
|
||||
assert_equal(decoded_psbt['inputs'][0]['pegin_txout_proof'], proof)
|
||||
assert_equal(decoded_psbt['inputs'][0]['pegin_genesis_hash'], parent.getblockhash(0))
|
||||
# Make a psbt without those peg-in data and merge them
|
||||
merge_pegin_psbt = sidechain.createpsbt([{"txid":txid1, "vout": vout}], outputs)
|
||||
decoded_psbt = sidechain.decodepsbt(merge_pegin_psbt)
|
||||
assert 'pegin_bitcoin_tx' not in decoded_psbt['inputs'][0]
|
||||
assert 'pegin_claim_script' not in decoded_psbt['inputs'][0]
|
||||
assert 'pegin_txout_proof' not in decoded_psbt['inputs'][0]
|
||||
assert 'pegin_genesis_hash' not in decoded_psbt['inputs'][0]
|
||||
merged_pegin_psbt = sidechain.combinepsbt([pegin_psbt, merge_pegin_psbt])
|
||||
assert_equal(pegin_psbt, merged_pegin_psbt)
|
||||
# Now sign the psbt
|
||||
signed_psbt = sidechain.walletsignpsbt(pegin_psbt)
|
||||
# Finalize and extract and compare
|
||||
fin_psbt = sidechain.finalizepsbt(signed_psbt['psbt'])
|
||||
assert_equal(fin_psbt, signed_pegin)
|
||||
|
||||
sample_pegin_struct = FromHex(CTransaction(), signed_pegin["hex"])
|
||||
# Round-trip peg-in transaction using python serialization
|
||||
|
|
|
|||
|
|
@ -524,10 +524,7 @@ class PSBTTest(BitcoinTestFramework):
|
|||
# Some Confidential-Assets-specific tests
|
||||
self.run_ca_tests()
|
||||
|
||||
# Check that peg-ins are disallowed
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].createpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_bitcoin_tx": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].createpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_txout_proof": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].createpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_claim_script": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
# Check that peg-ins are disallowed for walletcreatefundedpsbt
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].walletcreatefundedpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_bitcoin_tx": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].walletcreatefundedpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_txout_proof": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
assert_raises_rpc_error(-8, 'pegin_ arguments provided but this command does not support peg-ins', self.nodes[0].walletcreatefundedpsbt, [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0, "pegin_claim_script": "00"}], [{self.nodes[0].getnewaddress(): 1}])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue