diff --git a/CHANGELOG.md b/CHANGELOG.md index 70f719f0..179c2d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +# 0.26.1 - 2025-08-28 + +* [#250](https://github.com/ElementsProject/rust-elements/pull/250) API cleanups + * implement `Encodable` and `Decodable` for `Vec` whenever `T` is `Encodable`/`Decodable` and `'static` + * add missing export of error sub-type `pset::PsetHash` + # 0.26.0 - 2025-08-22 * [#249](https://github.com/ElementsProject/rust-elements/pull/249) docs: fix changelog links diff --git a/Cargo-latest.lock b/Cargo-latest.lock index 5f9503a1..426e4104 100644 --- a/Cargo-latest.lock +++ b/Cargo-latest.lock @@ -190,7 +190,7 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elements" -version = "0.26.0" +version = "0.26.1" dependencies = [ "bech32", "bincode", diff --git a/Cargo.toml b/Cargo.toml index 31614b4e..5b5f627f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "elements" -version = "0.26.0" +version = "0.26.1" authors = ["Andrew Poelstra "] description = "Library with support for de/serialization, parsing and executing on data structures and network messages related to Elements" license = "CC0-1.0" diff --git a/src/encode.rs b/src/encode.rs index 6868cee2..e8718c36 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -16,14 +16,13 @@ //! use std::io::Cursor; -use std::{error, fmt, io, mem}; +use std::{any, error, fmt, io, mem}; use bitcoin::ScriptBuf; use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak}; use crate::hashes::{sha256, Hash}; use crate::pset; -use crate::transaction::{Transaction, TxIn, TxOut}; pub use bitcoin::{self, consensus::encode::MAX_VEC_SIZE}; @@ -314,47 +313,84 @@ impl Decodable for bitcoin::hashes::sha256d::Hash { } // Vectors -macro_rules! impl_vec { - ($type: ty) => { - impl Encodable for Vec<$type> { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - let mut len = 0; - len += VarInt(self.len() as u64).consensus_encode(&mut s)?; - for c in self.iter() { - len += c.consensus_encode(&mut s)?; - } - Ok(len) +impl Encodable for [T] { + #[inline] + fn consensus_encode(&self, mut s: S) -> Result { + if any::TypeId::of::() == any::TypeId::of::() { + // SAFETY: checked that T is exactly u8, so &self, of type, &[T], is exactly &[u8] + let u8_slice = unsafe { + std::slice::from_raw_parts(self.as_ptr().cast::(), self.len()) + }; + consensus_encode_with_size(u8_slice, s) + } else { + let mut len = 0; + len += VarInt(self.len() as u64).consensus_encode(&mut s)?; + for c in self { + len += c.consensus_encode(&mut s)?; } + Ok(len) } + } +} - impl Decodable for Vec<$type> { - #[inline] - fn consensus_decode(mut d: D) -> Result { - 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"))?; - if byte_size > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { - requested: byte_size, - max: MAX_VEC_SIZE, - }); - } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { - ret.push(Decodable::consensus_decode(&mut d)?); - } - Ok(ret) +impl Encodable for Vec { + #[inline] + fn consensus_encode(&self, s: S) -> Result { + self[..].consensus_encode(s) + } +} + +impl Encodable for Box<[T]> { + #[inline] + fn consensus_encode(&self, s: S) -> Result { + self[..].consensus_encode(s) + } +} + +impl Decodable for Vec { + #[inline] + fn consensus_decode(mut d: D) -> Result { + if any::TypeId::of::() == any::TypeId::of::() { + let s = VarInt::consensus_decode(&mut d)?.0 as usize; + if s > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { + requested: s, + max: MAX_VEC_SIZE, + }); + } + let mut v = vec![0; s]; + d.read_slice(&mut v)?; + // SAFETY: checked that T is exactly u8, so v, of type, Vec, is exactly Vec + unsafe { + Ok(std::mem::transmute::, Vec>(v)) + } + } else { + let len = VarInt::consensus_decode(&mut d)?.0; + let byte_size = (len as usize) + .checked_mul(mem::size_of::()) + .ok_or(self::Error::ParseFailed("Invalid length"))?; + if byte_size > MAX_VEC_SIZE { + return Err(self::Error::OversizedVectorAllocation { + requested: byte_size, + max: MAX_VEC_SIZE, + }); } + let mut ret = Vec::with_capacity(len as usize); + for _ in 0..len { + ret.push(Decodable::consensus_decode(&mut d)?); + } + Ok(ret) } - }; + } +} + +impl Decodable for Box<[T]> { + #[inline] + fn consensus_decode(d: D) -> Result { + let v = Vec::::consensus_decode(d)?; + Ok(v.into()) + } } -impl_vec!(TxIn); -impl_vec!(TxOut); -impl_vec!(Transaction); -impl_vec!(TapLeafHash); -impl_vec!(Vec); // Vec> macro_rules! impl_array { ( $size:literal ) => { @@ -383,38 +419,6 @@ impl_array!(4); impl_array!(32); impl_array!(33); -impl Encodable for Box<[u8]> { - fn consensus_encode(&self, mut w: W) -> Result { - consensus_encode_with_size(&self[..], &mut w) - } -} -impl Decodable for Box<[u8]> { - fn consensus_decode(d: D) -> Result { - let v = Vec::::consensus_decode(d)?; - Ok(v.into()) - } -} - -impl Encodable for Vec { - fn consensus_encode(&self, mut w: W) -> Result { - consensus_encode_with_size(&self[..], &mut w) - } -} -impl Decodable for Vec { - fn consensus_decode(mut d: D) -> Result { - let s = VarInt::consensus_decode(&mut d)?.0 as usize; - if s > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { - requested: s, - max: MAX_VEC_SIZE, - }); - } - let mut v = vec![0; s]; - d.read_slice(&mut v)?; - Ok(v) - } -} - macro_rules! impl_box_option { ($type: ty) => { impl Encodable for Option> { diff --git a/src/pset/error.rs b/src/pset/error.rs index 0cce0c61..1f6d4564 100644 --- a/src/pset/error.rs +++ b/src/pset/error.rs @@ -26,9 +26,13 @@ use secp256k1_zkp; #[derive(Copy, Clone, PartialEq, Eq, Debug)] /// Enum for marking pset hash error pub enum PsetHash { + /// Bad preimage for `RIPEMD160` hash. Ripemd, + /// Bad preimage for `SHA256` hash. Sha256, + /// Bad preimage for `RIPEMD160-SHA256` hash. Hash160, + /// Bad preimage for double-`SHA256` hash. Hash256, } /// Ways that a Partially Signed Transaction might fail. diff --git a/src/pset/mod.rs b/src/pset/mod.rs index 34106095..85ee99b6 100644 --- a/src/pset/mod.rs +++ b/src/pset/mod.rs @@ -53,7 +53,7 @@ use crate::{ use secp256k1_zkp::rand::{CryptoRng, RngCore}; use secp256k1_zkp::{self, RangeProof, SecretKey, SurjectionProof}; -pub use self::error::{Error, PsetBlindError}; +pub use self::error::{Error, PsetBlindError, PsetHash}; use self::map::Map; pub use self::map::{Global, GlobalTxData, Input, Output, PsbtSighashType, TapTree};