Merge #730: Change Proprietary types to use the method specified in BIP 174

34e135011 Use Elements PSBT magic when in Elements mode (Andrew Chow)
3fa355c76 Change Proprietary types to use the method specified in BIP 174 (Andrew Chow)

Pull request description:

  https://github.com/bitcoin/bips/pull/849 (not yet merged) adds to BIP 174 proprietary types. This PR changes the PSBT types used in Elements to be in line with the proposed changes to the BIP/

Tree-SHA512: 73085a16005448d9f6ad1b74da4a40043ec29738256a439f35106793d11d0e95cb8d728db5cfefe1ddd49cd80367f7f5790d09efaa95bc443e1d6ba295240c4d
This commit is contained in:
Steven Roose 2019-10-09 16:46:01 +01:00
commit 4b2fac45b9
No known key found for this signature in database
GPG key ID: 2F2A88D7F8D68E87

View file

@ -13,9 +13,11 @@
// 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;
@ -27,26 +29,30 @@ 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 = 0xf0;
static constexpr uint8_t PSBT_IN_VALUE_BLINDER = 0xf1;
static constexpr uint8_t PSBT_IN_ASSET = 0xf2;
static constexpr uint8_t PSBT_IN_ASSET_BLINDER = 0xf3;
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;
// 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 = 0xf0;
static constexpr uint8_t PSBT_OUT_VALUE_BLINDER = 0xf1;
static constexpr uint8_t PSBT_OUT_ASSET_COMMITMENT = 0xf2;
static constexpr uint8_t PSBT_OUT_ASSET_BLINDER = 0xf3;
static constexpr uint8_t PSBT_OUT_RANGE_PROOF = 0xf4;
static constexpr uint8_t PSBT_OUT_SURJECTION_PROOF = 0xf5;
static constexpr uint8_t PSBT_OUT_BLINDING_PUBKEY = 0xf6;
static constexpr uint8_t PSBT_OUT_NONCE_COMMITMENT = 0xf7;
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.
@ -122,22 +128,22 @@ struct PSBTInput
// Write the Confidential Assets blinding data
if (value) {
SerializeToVector(s, PSBT_IN_VALUE);
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_VALUE);
SerializeToVector(s, *value);
}
if (!value_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_IN_VALUE_BLINDER);
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_VALUE_BLINDER);
SerializeToVector(s, value_blinding_factor);
}
if (!asset.IsNull()) {
SerializeToVector(s, PSBT_IN_ASSET);
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_ASSET);
SerializeToVector(s, asset);
}
if (!asset_blinding_factor.IsNull()) {
SerializeToVector(s, PSBT_IN_ASSET_BLINDER);
SerializeToVector(s, PSBT_IN_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_IN_ASSET_BLINDER);
SerializeToVector(s, asset_blinding_factor);
}
@ -279,46 +285,64 @@ struct PSBTInput
UnserializeFromVector(s, final_script_witness.stack);
break;
}
case PSBT_IN_VALUE:
case PSBT_IN_PROPRIETARY:
{
if (value != boost::none) {
throw std::ios_base::failure("Duplicate Key, input value already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Final value key is more than one byte type");
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;
}
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 (key.size() != 1) {
throw std::ios_base::failure("Final value_blinding_factor key is more than one byte type");
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;
}
}
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 (key.size() != 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 (key.size() != 1) {
throw std::ios_base::failure("Final asset_blinding_factor key is more than one byte type");
}
UnserializeFromVector(s, asset_blinding_factor);
break;
}
// Unknown stuff
@ -390,42 +414,42 @@ struct PSBTOutput
if (g_con_elementsmode) {
// Write the Confidential Assets blinding data
if (!value_commitment.IsNull()) {
SerializeToVector(s, PSBT_OUT_VALUE_COMMITMENT);
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_VALUE_BLINDER);
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_ASSET_COMMITMENT);
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_ASSET_BLINDER);
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_NONCE_COMMITMENT);
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_NONCE_COMMITMENT);
SerializeToVector(s, nonce_commitment);
}
if (!range_proof.empty()) {
SerializeToVector(s, PSBT_OUT_RANGE_PROOF);
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_RANGE_PROOF);
s << range_proof;
}
if (!surjection_proof.empty()) {
SerializeToVector(s, PSBT_OUT_SURJECTION_PROOF);
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_SURJECTION_PROOF);
s << surjection_proof;
}
if (blinding_pubkey.IsValid()) {
SerializeToVector(s, PSBT_OUT_BLINDING_PUBKEY);
SerializeToVector(s, PSBT_OUT_PROPRIETARY, PSBT_ELEMENTS_ID, PSBT_OUT_BLINDING_PUBKEY);
s << blinding_pubkey;
}
}
@ -486,84 +510,102 @@ struct PSBTOutput
DeserializeHDKeypaths(s, key, hd_keypaths);
break;
}
case PSBT_OUT_VALUE_COMMITMENT:
case PSBT_OUT_PROPRIETARY:
{
if (!value_commitment.IsNull()) {
throw std::ios_base::failure("Duplicate Key, output value_commitment already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output value_commitment key is more than one byte type");
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;
}
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 (key.size() != 1) {
throw std::ios_base::failure("Output value_blinding_factor key is more than one byte type");
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;
}
}
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 (key.size() != 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 (key.size() != 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 (key.size() != 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 (key.size() != 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 (key.size() != 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 (key.size() != 1) {
throw std::ios_base::failure("Output blinding_pubkey key is more than one byte type");
}
s >> blinding_pubkey;
break;
}
// Unknown stuff
@ -623,7 +665,11 @@ struct PartiallySignedTransaction
inline void Serialize(Stream& s) const {
// magic bytes
s << PSBT_MAGIC_BYTES;
if (g_con_elementsmode) {
s << PSBT_ELEMENTS_MAGIC_BYTES;
} else {
s << PSBT_MAGIC_BYTES;
}
// unsigned tx flag
SerializeToVector(s, PSBT_GLOBAL_UNSIGNED_TX);
@ -657,8 +703,14 @@ struct PartiallySignedTransaction
// Read the magic bytes
uint8_t magic[5];
s >> magic;
if (!std::equal(magic, magic + 5, PSBT_MAGIC_BYTES)) {
throw std::ios_base::failure("Invalid PSBT magic bytes");
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");
}
}
// Read global data