Add data types for raw PSBT key-value pairs

- Add (en)decoding logic for said data types
This commit is contained in:
Carl Dong 2018-08-10 08:28:48 -07:00
parent 4fa39c4a3e
commit 528e39334c
3 changed files with 124 additions and 6 deletions

View File

@ -2,6 +2,7 @@ use std::error;
use std::fmt;
use blockdata::transaction::Transaction;
use util::psbt::raw;
/// Ways that a Partially Signed Transaction might fail.
#[derive(Debug)]
@ -12,9 +13,9 @@ pub enum Error {
/// The separator for a PSBT must be `0xff`.
InvalidSeparator,
/// Known keys must be according to spec.
InvalidKey,
InvalidKey(raw::Key),
/// Keys within key-value map should never be duplicated.
DuplicateKey,
DuplicateKey(raw::Key),
/// The scriptSigs for the unsigned transaction must be empty.
UnsignedTxHasScriptSigs,
/// The scriptWitnesses for the unsigned transaction must be empty.
@ -38,12 +39,12 @@ pub enum Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::InvalidKey(ref rkey) => write!(f, "{}: {}", error::Error::description(self), rkey),
Error::DuplicateKey(ref rkey) => write!(f, "{}: {}", error::Error::description(self), rkey),
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e.txid(), a.txid()),
Error::NonStandardSigHashType(ref sht) => write!(f, "{}: {}", error::Error::description(self), sht),
Error::InvalidMagic
| Error::InvalidSeparator
| Error::InvalidKey
| Error::DuplicateKey
| Error::UnsignedTxHasScriptSigs
| Error::UnsignedTxHasScriptWitnesses
| Error::MustHaveUnsignedTx
@ -57,8 +58,8 @@ impl error::Error for Error {
match *self {
Error::InvalidMagic => "invalid magic",
Error::InvalidSeparator => "invalid separator",
Error::InvalidKey => "invalid key",
Error::DuplicateKey => "duplicate key",
Error::InvalidKey(..) => "invalid key",
Error::DuplicateKey(..) => "duplicate key",
Error::UnsignedTxHasScriptSigs => "the unsigned transaction has script sigs",
Error::UnsignedTxHasScriptWitnesses => "the unsigned transaction has script witnesses",
Error::MustHaveUnsignedTx => {

View File

@ -6,3 +6,26 @@
mod error;
pub use self::error::Error;
pub mod raw;
#[cfg(test)]
mod tests {
use consensus::encode::{deserialize, serialize};
use util::psbt::raw;
#[test]
fn serialize_then_deserialize_psbtkvpair() {
let expected = raw::Pair {
key: raw::Key {
type_value: 0u8,
key: vec![42u8, 69u8],
},
value: vec![69u8, 42u8, 4u8],
};
let actual: raw::Pair = deserialize(&serialize(&expected)).unwrap();
assert_eq!(expected, actual);
}
}

94
src/util/psbt/raw.rs Normal file
View File

@ -0,0 +1,94 @@
//! # Raw PSBT Key-Value Pairs
//!
//! Raw PSBT key-value pairs as defined at
//! https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki.
use std::fmt;
use consensus::encode::{Decodable, Encodable, VarInt, MAX_VEC_SIZE};
use consensus::encode::{self, Decoder, Encoder};
use util::psbt::Error;
/// A PSBT key in its raw byte form.
#[derive(Debug, PartialEq, Hash, Eq, Clone)]
pub struct Key {
/// The type of this PSBT key.
pub type_value: u8,
/// The key itself in raw byte form.
pub key: Vec<u8>,
}
/// A PSBT key-value pair in its raw byte form.
#[derive(Debug, PartialEq)]
pub struct Pair {
/// The key of this key-value pair.
pub key: Key,
/// The value of this key-value pair in raw byte form.
pub value: Vec<u8>,
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use hex;
write!(f, "type: {:#x}, key: {}", self.type_value, hex::encode(&self.key))
}
}
impl<D: Decoder> Decodable<D> for Key {
fn consensus_decode(d: &mut D) -> Result<Self, encode::Error> {
let VarInt(byte_size): VarInt = Decodable::consensus_decode(d)?;
if byte_size == 0 {
return Err(Error::NoMorePairs.into());
}
let key_byte_size: u64 = byte_size - 1;
if key_byte_size > MAX_VEC_SIZE as u64 {
return Err(encode::Error::OversizedVectorAllocation { requested: key_byte_size as usize, max: MAX_VEC_SIZE } )
}
let type_value: u8 = Decodable::consensus_decode(d)?;
let mut key = Vec::with_capacity(key_byte_size as usize);
for _ in 0..key_byte_size {
key.push(Decodable::consensus_decode(d)?);
}
Ok(Key {
type_value: type_value,
key: key,
})
}
}
impl<S: Encoder> Encodable<S> for Key {
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
VarInt((self.key.len() + 1) as u64).consensus_encode(s)?;
self.type_value.consensus_encode(s)?;
for key in &self.key {
key.consensus_encode(s)?
}
Ok(())
}
}
impl<S: Encoder> Encodable<S> for Pair {
fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
self.key.consensus_encode(s)?;
self.value.consensus_encode(s)
}
}
impl<D: Decoder> Decodable<D> for Pair {
fn consensus_decode(d: &mut D) -> Result<Self, encode::Error> {
Ok(Pair {
key: Decodable::consensus_decode(d)?,
value: Decodable::consensus_decode(d)?,
})
}
}