Add peg-in PSBT fields

This commit is contained in:
Andrew Chow 2019-10-10 17:05:39 -04:00
parent 0d2832a6d1
commit b5590b20ce

View file

@ -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;
}