Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
RCasatta committed Aug 16, 2024
1 parent f875ae2 commit 8ce9c35
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 44 deletions.
159 changes: 119 additions & 40 deletions src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use std::io::Cursor;
use std::{error, fmt, io, mem};

use bitcoin::consensus::encode as btcenc;
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak};

use crate::hashes::{sha256, Hash};
Expand All @@ -38,7 +37,7 @@ pub enum Error {
/// And I/O error
Io(io::Error),
/// A Bitcoin encoding error.
Bitcoin(btcenc::Error),
Bitcoin(bitcoin::consensus::encode::Error),
/// Tried to allocate an oversized vector
OversizedVectorAllocation {
/// The capacity requested
Expand All @@ -62,6 +61,8 @@ pub enum Error {
HexError(crate::hex::Error),
/// Got a time-based locktime when expecting a height-based one, or vice-versa
BadLockTime(crate::LockTime),
/// VarInt was encoded in a non-minimal way.
NonMinimalVarInt,
}

impl fmt::Display for Error {
Expand All @@ -87,23 +88,22 @@ impl fmt::Display for Error {
Error::PsetError(ref e) => write!(f, "Pset Error: {}", e),
Error::HexError(ref e) => write!(f, "Hex error {}", e),
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
}
}
}

impl error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
Error::Bitcoin(ref e) => Some(e),
Error::Secp256k1zkp(ref e) => Some(e),
_ => None,
}
}
}

#[doc(hidden)]
impl From<btcenc::Error> for Error {
fn from(e: btcenc::Error) -> Error {
impl From<bitcoin::consensus::encode::Error> for Error {
fn from(e: bitcoin::consensus::encode::Error) -> Error {
Error::Bitcoin(e)
}
}
Expand Down Expand Up @@ -210,42 +210,11 @@ pub(crate) fn consensus_encode_with_size<S: io::Write>(
data: &[u8],
mut s: S,
) -> Result<usize, Error> {
let vi_len = bitcoin::VarInt(data.len() as u64).consensus_encode(&mut s)?;
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?;
s.emit_slice(data)?;
Ok(vi_len + data.len())
}

/// Implement Elements encodable traits for Bitcoin encodable types.
macro_rules! impl_upstream {
($type: ty) => {
impl Encodable for $type {
fn consensus_encode<W: io::Write>(&self, mut e: W) -> Result<usize, Error> {
Ok(btcenc::Encodable::consensus_encode(self, &mut e)?)
}
}

impl Decodable for $type {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
Ok(btcenc::Decodable::consensus_decode(&mut d)?)
}
}
};
}
impl_upstream!(u8);
impl_upstream!(u32);
impl_upstream!(u64);
impl_upstream!([u8; 4]);
impl_upstream!([u8; 32]);
impl_upstream!(Box<[u8]>);
impl_upstream!([u8; 33]);
impl_upstream!(Vec<u8>);
impl_upstream!(Vec<Vec<u8>>);
impl_upstream!(btcenc::VarInt);
impl_upstream!(bitcoin::Transaction);
impl_upstream!(bitcoin::BlockHash);
impl_upstream!(bitcoin::ScriptBuf);
impl_upstream!(crate::hashes::sha256d::Hash);

// Specific locktime types (which appear in PSET/PSBT2 but not in rust-bitcoin PSBT)
impl Encodable for crate::locktime::Height {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
Expand Down Expand Up @@ -275,14 +244,124 @@ impl Decodable for crate::locktime::Time {
}
}

macro_rules! impl_todo {
($type: ty) => {
impl Encodable for $type {
fn consensus_encode<W: io::Write>(&self, _w: W) -> Result<usize, Error> {
todo!()
}
}

impl Decodable for $type {
fn consensus_decode<R: io::Read>(_r: R) -> Result<Self, Error> {
todo!()
}
}
};
}

// TODO use bitcoin::{ReadExt,WriteExt} when varint available
struct VarInt(u64);
impl Encodable for VarInt {
fn consensus_encode<W: io::Write>(&self, mut e: W) -> Result<usize, Error> {
match self.0 {
i @ 0..=0xFC => {
e.emit_u8(i as u8)?;
Ok(1)
}
i @ 0xFD..=0xFFFF => {
e.emit_u8(0xFD)?;
e.emit_u16(i as u16)?;
Ok(3)
}
i @ 0x10000..=0xFFFFFFFF => {
e.emit_u8(0xFE)?;
e.emit_u32(i as u32)?;
Ok(5)
}
i => {
e.emit_u8(0xFF)?;
e.emit_u64(i)?;
Ok(9)
}
}
}
}
impl Decodable for VarInt {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
match d.read_u8()? {
0xFF => {
let x = d.read_u64()?;
if x < 0x100000000 {
Err(Error::NonMinimalVarInt)
} else {
Ok(VarInt(x))
}
}
0xFE => {
let x = d.read_u32()?;
if x < 0x10000 {
Err(Error::NonMinimalVarInt)
} else {
Ok(VarInt(x as u64))
}
}
0xFD => {
let x = d.read_u16()?;
if x < 0xFD {
Err(Error::NonMinimalVarInt)
} else {
Ok(VarInt(x as u64))
}
}
n => Ok(VarInt(n as u64)),
}
}
}

// Primitive types
macro_rules! impl_int {
($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
impl Encodable for $ty {
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
w.$meth_enc(*self)?;
Ok(mem::size_of::<$ty>())
}
}
impl Decodable for $ty {
fn consensus_decode<R: io::Read>(mut r: R) -> Result<Self, Error> {
Ok(ReadExt::$meth_dec(&mut r)?)
}
}
};
}

impl_int!(u8, read_u8, emit_u8);
impl_int!(u16, read_u16, emit_u16);
impl_int!(u32, read_u32, emit_u32);
impl_int!(u64, read_u64, emit_u64);

impl_todo!([u8; 32]);
impl_todo!([u8; 33]);
impl_todo!([u8; 4]);
impl_todo!(Vec<u8>);
impl_todo!(Vec<Vec<u8>>);
impl_todo!(Box<[u8]>);

// TODO reuse bitcoin impl
impl_todo!(bitcoin::Transaction);
impl_todo!(bitcoin::VarInt);
impl_todo!(bitcoin::ScriptBuf);
impl_todo!(bitcoin::hashes::sha256d::Hash);

// Vectors
macro_rules! impl_vec {
($type: ty) => {
impl Encodable for Vec<$type> {
#[inline]
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
let mut len = 0;
len += btcenc::VarInt(self.len() as u64).consensus_encode(&mut s)?;
len += VarInt(self.len() as u64).consensus_encode(&mut s)?;
for c in self.iter() {
len += c.consensus_encode(&mut s)?;
}
Expand All @@ -293,7 +372,7 @@ macro_rules! impl_vec {
impl Decodable for Vec<$type> {
#[inline]
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
let len = btcenc::VarInt::consensus_decode(&mut d)?.0;
let len = VarInt::consensus_decode(&mut d)?.0;
let byte_size = (len as usize)
.checked_mul(mem::size_of::<$type>())
.ok_or(self::Error::ParseFailed("Invalid length"))?;
Expand Down
6 changes: 2 additions & 4 deletions src/pset/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
use std::{fmt, io};

use super::Error;
use crate::encode::{
self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE,
};
use crate::encode::{self, deserialize, serialize, Decodable, Encodable, WriteExt, MAX_VEC_SIZE};
use crate::hex;
use crate::VarInt;
/// A PSET key in its raw byte form.
Expand Down Expand Up @@ -198,7 +196,7 @@ where
let prefix = Vec::<u8>::consensus_decode(&mut d)?;
let mut key = vec![];

let subtype = Subtype::from(d.read_u8()?);
let subtype = Subtype::from(u8::consensus_decode(&mut d)?);
d.read_to_end(&mut key)?;

Ok(ProprietaryKey {
Expand Down

0 comments on commit 8ce9c35

Please sign in to comment.