psbt: Use u64 for key type

Currently we use `u8` for key type but it was pointed out that we should
be using a `u64` and encoding it as a compact type. The reason our code
works now is because the compact type encoding for a `u8` (less than
253) is the same as for a `u8`.

This breaks the `serde` impl, as shown by changes to the regression tests.
This commit is contained in:
Tobin C. Harding 2024-08-29 08:53:48 +10:00
parent 78bcca71ca
commit 2f656f77ba
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
9 changed files with 49 additions and 49 deletions

View File

@ -12,13 +12,13 @@ use crate::psbt::{raw, Error, Psbt};
use crate::transaction::Transaction; use crate::transaction::Transaction;
/// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00 /// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00
const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00; const PSBT_GLOBAL_UNSIGNED_TX: u64 = 0x00;
/// Type: Extended Public Key PSBT_GLOBAL_XPUB = 0x01 /// Type: Extended Public Key PSBT_GLOBAL_XPUB = 0x01
const PSBT_GLOBAL_XPUB: u8 = 0x01; const PSBT_GLOBAL_XPUB: u64 = 0x01;
/// Type: Version Number PSBT_GLOBAL_VERSION = 0xFB /// Type: Version Number PSBT_GLOBAL_VERSION = 0xFB
const PSBT_GLOBAL_VERSION: u8 = 0xFB; const PSBT_GLOBAL_VERSION: u64 = 0xFB;
/// Type: Proprietary Use Type PSBT_GLOBAL_PROPRIETARY = 0xFC /// Type: Proprietary Use Type PSBT_GLOBAL_PROPRIETARY = 0xFC
const PSBT_GLOBAL_PROPRIETARY: u8 = 0xFC; const PSBT_GLOBAL_PROPRIETARY: u64 = 0xFC;
impl Map for Psbt { impl Map for Psbt {
fn get_pairs(&self) -> Vec<raw::Pair> { fn get_pairs(&self) -> Vec<raw::Pair> {

View File

@ -23,45 +23,45 @@ use crate::transaction::{Transaction, TxOut};
use crate::witness::Witness; use crate::witness::Witness;
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00 /// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
const PSBT_IN_NON_WITNESS_UTXO: u8 = 0x00; const PSBT_IN_NON_WITNESS_UTXO: u64 = 0x00;
/// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01 /// Type: Witness UTXO PSBT_IN_WITNESS_UTXO = 0x01
const PSBT_IN_WITNESS_UTXO: u8 = 0x01; const PSBT_IN_WITNESS_UTXO: u64 = 0x01;
/// Type: Partial Signature PSBT_IN_PARTIAL_SIG = 0x02 /// Type: Partial Signature PSBT_IN_PARTIAL_SIG = 0x02
const PSBT_IN_PARTIAL_SIG: u8 = 0x02; const PSBT_IN_PARTIAL_SIG: u64 = 0x02;
/// Type: Sighash Type PSBT_IN_SIGHASH_TYPE = 0x03 /// Type: Sighash Type PSBT_IN_SIGHASH_TYPE = 0x03
const PSBT_IN_SIGHASH_TYPE: u8 = 0x03; const PSBT_IN_SIGHASH_TYPE: u64 = 0x03;
/// Type: Redeem Script PSBT_IN_REDEEM_SCRIPT = 0x04 /// Type: Redeem Script PSBT_IN_REDEEM_SCRIPT = 0x04
const PSBT_IN_REDEEM_SCRIPT: u8 = 0x04; const PSBT_IN_REDEEM_SCRIPT: u64 = 0x04;
/// Type: Witness Script PSBT_IN_WITNESS_SCRIPT = 0x05 /// Type: Witness Script PSBT_IN_WITNESS_SCRIPT = 0x05
const PSBT_IN_WITNESS_SCRIPT: u8 = 0x05; const PSBT_IN_WITNESS_SCRIPT: u64 = 0x05;
/// Type: BIP 32 Derivation Path PSBT_IN_BIP32_DERIVATION = 0x06 /// Type: BIP 32 Derivation Path PSBT_IN_BIP32_DERIVATION = 0x06
const PSBT_IN_BIP32_DERIVATION: u8 = 0x06; const PSBT_IN_BIP32_DERIVATION: u64 = 0x06;
/// Type: Finalized scriptSig PSBT_IN_FINAL_SCRIPTSIG = 0x07 /// Type: Finalized scriptSig PSBT_IN_FINAL_SCRIPTSIG = 0x07
const PSBT_IN_FINAL_SCRIPTSIG: u8 = 0x07; const PSBT_IN_FINAL_SCRIPTSIG: u64 = 0x07;
/// Type: Finalized scriptWitness PSBT_IN_FINAL_SCRIPTWITNESS = 0x08 /// Type: Finalized scriptWitness PSBT_IN_FINAL_SCRIPTWITNESS = 0x08
const PSBT_IN_FINAL_SCRIPTWITNESS: u8 = 0x08; const PSBT_IN_FINAL_SCRIPTWITNESS: u64 = 0x08;
/// Type: RIPEMD160 preimage PSBT_IN_RIPEMD160 = 0x0a /// Type: RIPEMD160 preimage PSBT_IN_RIPEMD160 = 0x0a
const PSBT_IN_RIPEMD160: u8 = 0x0a; const PSBT_IN_RIPEMD160: u64 = 0x0a;
/// Type: SHA256 preimage PSBT_IN_SHA256 = 0x0b /// Type: SHA256 preimage PSBT_IN_SHA256 = 0x0b
const PSBT_IN_SHA256: u8 = 0x0b; const PSBT_IN_SHA256: u64 = 0x0b;
/// Type: HASH160 preimage PSBT_IN_HASH160 = 0x0c /// Type: HASH160 preimage PSBT_IN_HASH160 = 0x0c
const PSBT_IN_HASH160: u8 = 0x0c; const PSBT_IN_HASH160: u64 = 0x0c;
/// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d /// Type: HASH256 preimage PSBT_IN_HASH256 = 0x0d
const PSBT_IN_HASH256: u8 = 0x0d; const PSBT_IN_HASH256: u64 = 0x0d;
/// Type: Taproot Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13 /// Type: Taproot Signature in Key Spend PSBT_IN_TAP_KEY_SIG = 0x13
const PSBT_IN_TAP_KEY_SIG: u8 = 0x13; const PSBT_IN_TAP_KEY_SIG: u64 = 0x13;
/// Type: Taproot Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14 /// Type: Taproot Signature in Script Spend PSBT_IN_TAP_SCRIPT_SIG = 0x14
const PSBT_IN_TAP_SCRIPT_SIG: u8 = 0x14; const PSBT_IN_TAP_SCRIPT_SIG: u64 = 0x14;
/// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14 /// Type: Taproot Leaf Script PSBT_IN_TAP_LEAF_SCRIPT = 0x14
const PSBT_IN_TAP_LEAF_SCRIPT: u8 = 0x15; const PSBT_IN_TAP_LEAF_SCRIPT: u64 = 0x15;
/// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16 /// Type: Taproot Key BIP 32 Derivation Path PSBT_IN_TAP_BIP32_DERIVATION = 0x16
const PSBT_IN_TAP_BIP32_DERIVATION: u8 = 0x16; const PSBT_IN_TAP_BIP32_DERIVATION: u64 = 0x16;
/// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17 /// Type: Taproot Internal Key PSBT_IN_TAP_INTERNAL_KEY = 0x17
const PSBT_IN_TAP_INTERNAL_KEY: u8 = 0x17; const PSBT_IN_TAP_INTERNAL_KEY: u64 = 0x17;
/// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18 /// Type: Taproot Merkle Root PSBT_IN_TAP_MERKLE_ROOT = 0x18
const PSBT_IN_TAP_MERKLE_ROOT: u8 = 0x18; const PSBT_IN_TAP_MERKLE_ROOT: u64 = 0x18;
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
const PSBT_IN_PROPRIETARY: u8 = 0xFC; const PSBT_IN_PROPRIETARY: u64 = 0xFC;
/// A key-value map for an input of the corresponding index in the unsigned /// A key-value map for an input of the corresponding index in the unsigned
/// transaction. /// transaction.

View File

@ -10,19 +10,19 @@ use crate::script::ScriptBuf;
use crate::taproot::{TapLeafHash, TapTree}; use crate::taproot::{TapLeafHash, TapTree};
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00 /// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00; const PSBT_OUT_REDEEM_SCRIPT: u64 = 0x00;
/// Type: Witness ScriptBuf PSBT_OUT_WITNESS_SCRIPT = 0x01 /// Type: Witness ScriptBuf PSBT_OUT_WITNESS_SCRIPT = 0x01
const PSBT_OUT_WITNESS_SCRIPT: u8 = 0x01; const PSBT_OUT_WITNESS_SCRIPT: u64 = 0x01;
/// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02 /// Type: BIP 32 Derivation Path PSBT_OUT_BIP32_DERIVATION = 0x02
const PSBT_OUT_BIP32_DERIVATION: u8 = 0x02; const PSBT_OUT_BIP32_DERIVATION: u64 = 0x02;
/// Type: Taproot Internal Key PSBT_OUT_TAP_INTERNAL_KEY = 0x05 /// Type: Taproot Internal Key PSBT_OUT_TAP_INTERNAL_KEY = 0x05
const PSBT_OUT_TAP_INTERNAL_KEY: u8 = 0x05; const PSBT_OUT_TAP_INTERNAL_KEY: u64 = 0x05;
/// Type: Taproot Tree PSBT_OUT_TAP_TREE = 0x06 /// Type: Taproot Tree PSBT_OUT_TAP_TREE = 0x06
const PSBT_OUT_TAP_TREE: u8 = 0x06; const PSBT_OUT_TAP_TREE: u64 = 0x06;
/// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07 /// Type: Taproot Key BIP 32 Derivation Path PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
const PSBT_OUT_TAP_BIP32_DERIVATION: u8 = 0x07; const PSBT_OUT_TAP_BIP32_DERIVATION: u64 = 0x07;
/// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC /// Type: Proprietary Use Type PSBT_IN_PROPRIETARY = 0xFC
const PSBT_OUT_PROPRIETARY: u8 = 0xFC; const PSBT_OUT_PROPRIETARY: u64 = 0xFC;
/// A key-value map for an output of the corresponding index in the unsigned /// A key-value map for an output of the corresponding index in the unsigned
/// transaction. /// transaction.

View File

@ -1440,7 +1440,7 @@ mod tests {
#[test] #[test]
fn serialize_then_deserialize_psbtkvpair() { fn serialize_then_deserialize_psbtkvpair() {
let expected = raw::Pair { let expected = raw::Pair {
key: raw::Key { type_value: 0u8, key_data: vec![42u8, 69u8] }, key: raw::Key { type_value: 0u64, key_data: vec![42u8, 69u8] },
value: vec![69u8, 42u8, 4u8], value: vec![69u8, 42u8, 4u8],
}; };
@ -1850,7 +1850,7 @@ mod tests {
let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new(); let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new();
let key: raw::Key = let key: raw::Key =
raw::Key { type_value: 0x0fu8, key_data: hex!("010203040506070809") }; raw::Key { type_value: 0x0fu64, key_data: hex!("010203040506070809") };
let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f"); let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f");
unknown.insert(key, value); unknown.insert(key, value);
@ -2080,7 +2080,7 @@ mod tests {
fn serialize_and_deserialize_proprietary() { fn serialize_and_deserialize_proprietary() {
let mut psbt: Psbt = hex_psbt("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap(); let mut psbt: Psbt = hex_psbt("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
psbt.proprietary.insert( psbt.proprietary.insert(
raw::ProprietaryKey { prefix: b"test".to_vec(), subtype: 0u8, key: b"test".to_vec() }, raw::ProprietaryKey { prefix: b"test".to_vec(), subtype: 0u64, key: b"test".to_vec() },
b"test".to_vec(), b"test".to_vec(),
); );
assert!(!psbt.proprietary.is_empty()); assert!(!psbt.proprietary.is_empty());

View File

@ -7,12 +7,12 @@
use core::fmt; use core::fmt;
use internals::ToU64 as _; use internals::{ToU64 as _};
use io::{BufRead, Write}; use io::{BufRead, Write};
use super::serialize::{Deserialize, Serialize}; use super::serialize::{Deserialize, Serialize};
use crate::consensus::encode::{ use crate::consensus::encode::{
self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE, self, deserialize, serialize, Decodable, Encodable, MAX_VEC_SIZE, ReadExt, WriteExt,
}; };
use crate::prelude::{DisplayHex, Vec}; use crate::prelude::{DisplayHex, Vec};
use crate::psbt::Error; use crate::psbt::Error;
@ -24,7 +24,7 @@ use crate::psbt::Error;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Key { pub struct Key {
/// The type of this PSBT key. /// The type of this PSBT key.
pub type_value: u8, pub type_value: u64, // Encoded as a compact size.
/// The key data itself in raw byte form. /// The key data itself in raw byte form.
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))] #[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
pub key_data: Vec<u8>, pub key_data: Vec<u8>,
@ -44,7 +44,7 @@ pub struct Pair {
} }
/// Default implementation for proprietary key subtyping /// Default implementation for proprietary key subtyping
pub type ProprietaryType = u8; pub type ProprietaryType = u64;
/// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal /// Proprietary keys (i.e. keys starting with 0xFC byte) with their internal
/// structure according to BIP 174. /// structure according to BIP 174.
@ -52,7 +52,7 @@ pub type ProprietaryType = u8;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ProprietaryKey<Subtype = ProprietaryType> pub struct ProprietaryKey<Subtype = ProprietaryType>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u64> + Into<u64>,
{ {
/// Proprietary type prefix used for grouping together keys under some /// Proprietary type prefix used for grouping together keys under some
/// application and avoid namespace collision /// application and avoid namespace collision
@ -89,7 +89,7 @@ impl Key {
.into()); .into());
} }
let type_value: u8 = Decodable::consensus_decode(r)?; let type_value = r.read_compact_size()?;
let mut key_data = Vec::with_capacity(key_byte_size as usize); let mut key_data = Vec::with_capacity(key_byte_size as usize);
for _ in 0..key_byte_size { for _ in 0..key_byte_size {
@ -105,7 +105,7 @@ impl Serialize for Key {
let mut buf = Vec::new(); let mut buf = Vec::new();
buf.emit_compact_size(self.key_data.len() + 1).expect("in-memory writers don't error"); buf.emit_compact_size(self.key_data.len() + 1).expect("in-memory writers don't error");
self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error"); buf.emit_compact_size(self.type_value).expect("in-memory writers don't error");
for key in &self.key_data { for key in &self.key_data {
key.consensus_encode(&mut buf).expect("in-memory writers don't error"); key.consensus_encode(&mut buf).expect("in-memory writers don't error");
@ -140,11 +140,11 @@ impl Pair {
impl<Subtype> Encodable for ProprietaryKey<Subtype> impl<Subtype> Encodable for ProprietaryKey<Subtype>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u64> + Into<u64>,
{ {
fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> { fn consensus_encode<W: Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
let mut len = self.prefix.consensus_encode(w)? + 1; let mut len = self.prefix.consensus_encode(w)? + 1;
w.emit_u8(self.subtype.into())?; w.emit_compact_size(self.subtype.into())?;
w.write_all(&self.key)?; w.write_all(&self.key)?;
len += self.key.len(); len += self.key.len();
Ok(len) Ok(len)
@ -153,11 +153,11 @@ where
impl<Subtype> Decodable for ProprietaryKey<Subtype> impl<Subtype> Decodable for ProprietaryKey<Subtype>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u64> + Into<u64>,
{ {
fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> { fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?; let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?); let subtype = Subtype::from(r.read_compact_size()?);
// The limit is a DOS protection mechanism the exact value is not // The limit is a DOS protection mechanism the exact value is not
// important, 1024 bytes is bigger than any key should be. // important, 1024 bytes is bigger than any key should be.
@ -170,7 +170,7 @@ where
impl<Subtype> ProprietaryKey<Subtype> impl<Subtype> ProprietaryKey<Subtype>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u64> + Into<u64>,
{ {
/// Constructs full [Key] corresponding to this proprietary key type /// Constructs full [Key] corresponding to this proprietary key type
pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key_data: serialize(self) } } pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key_data: serialize(self) } }
@ -178,7 +178,7 @@ where
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype> impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
where where
Subtype: Copy + From<u8> + Into<u8>, Subtype: Copy + From<u64> + Into<u64>,
{ {
type Error = Error; type Error = Error;

View File

@ -325,7 +325,7 @@ fn serde_regression_psbt() {
#[test] #[test]
fn serde_regression_raw_pair() { fn serde_regression_raw_pair() {
let pair = Pair { let pair = Pair {
key: Key { type_value: 1u8, key_data: vec![0u8, 1u8, 2u8, 3u8] }, key: Key { type_value: 1u64, key_data: vec![0u8, 1u8, 2u8, 3u8] },
value: vec![0u8, 1u8, 2u8, 3u8], value: vec![0u8, 1u8, 2u8, 3u8],
}; };
let got = serialize(&pair).unwrap(); let got = serialize(&pair).unwrap();
@ -337,7 +337,7 @@ fn serde_regression_raw_pair() {
fn serde_regression_proprietary_key() { fn serde_regression_proprietary_key() {
let key = ProprietaryKey { let key = ProprietaryKey {
prefix: vec![0u8, 1u8, 2u8, 3u8], prefix: vec![0u8, 1u8, 2u8, 3u8],
subtype: 1u8, subtype: 1u64,
key: vec![0u8, 1u8, 2u8, 3u8], key: vec![0u8, 1u8, 2u8, 3u8],
}; };
let got = serialize(&key).unwrap(); let got = serialize(&key).unwrap();