Add data types for raw PSBT key-value pairs
- Add (en)decoding logic for said data types
This commit is contained in:
parent
4fa39c4a3e
commit
528e39334c
|
@ -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 => {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue