Skip to content

Commit f6342bc

Browse files
committed
Merge #250: Release 0.26.1 with some minor API extensions
05a24ad bump version to 0.26.1 (Andrew Poelstra) 2b89d5f encode: implement Encodable and Decodable for Vec<T> (Andrew Poelstra) 45a6938 export pset::error::PsetHash (Andrew Poelstra) Pull request description: I want to do the dtolnay "semver trick" where I release 0.25.3 which re-exports most of the types and traits from 0.26. This will make migration easier for users since they could use elements 0.25 and 0.26 in the same crate and have compatible types. In particular ElementsProject/elements-miniscript#97 would compile without needing to update `simplicity` and `elements` at the same time. However, when doing this I identified some gaps in the API which make this harder than it should be. See the commit messages for detailed justifications. Also release 0.26.1 with these changes. ACKs for top commit: RCasatta: utACK 05a24ad Tree-SHA512: 447d09950586da98a1d8a13fe8dc1ce69761d2a3152b9ea243264ec874f04bc1219d42a562e0470246c266980e77d2a46d807c78ed5ca9bbcf8f4055af3ea4c6
2 parents 6da502c + 05a24ad commit f6342bc

File tree

6 files changed

+86
-72
lines changed

6 files changed

+86
-72
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11

2+
# 0.26.1 - 2025-08-28
3+
4+
* [#250](https://github.com/ElementsProject/rust-elements/pull/250) API cleanups
5+
* implement `Encodable` and `Decodable` for `Vec<T>` whenever `T` is `Encodable`/`Decodable` and `'static`
6+
* add missing export of error sub-type `pset::PsetHash`
7+
28
# 0.26.0 - 2025-08-22
39

410
* [#249](https://github.com/ElementsProject/rust-elements/pull/249) docs: fix changelog links

Cargo-latest.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
190190

191191
[[package]]
192192
name = "elements"
193-
version = "0.26.0"
193+
version = "0.26.1"
194194
dependencies = [
195195
"bech32",
196196
"bincode",

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "elements"
3-
version = "0.26.0"
3+
version = "0.26.1"
44
authors = ["Andrew Poelstra <[email protected]>"]
55
description = "Library with support for de/serialization, parsing and executing on data structures and network messages related to Elements"
66
license = "CC0-1.0"

src/encode.rs

Lines changed: 73 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@
1616
//!
1717
1818
use std::io::Cursor;
19-
use std::{error, fmt, io, mem};
19+
use std::{any, error, fmt, io, mem};
2020

2121
use bitcoin::ScriptBuf;
2222
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak};
2323

2424
use crate::hashes::{sha256, Hash};
2525
use crate::pset;
26-
use crate::transaction::{Transaction, TxIn, TxOut};
2726

2827
pub use bitcoin::{self, consensus::encode::MAX_VEC_SIZE};
2928

@@ -314,47 +313,84 @@ impl Decodable for bitcoin::hashes::sha256d::Hash {
314313
}
315314

316315
// Vectors
317-
macro_rules! impl_vec {
318-
($type: ty) => {
319-
impl Encodable for Vec<$type> {
320-
#[inline]
321-
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
322-
let mut len = 0;
323-
len += VarInt(self.len() as u64).consensus_encode(&mut s)?;
324-
for c in self.iter() {
325-
len += c.consensus_encode(&mut s)?;
326-
}
327-
Ok(len)
316+
impl<T: Encodable + any::Any> Encodable for [T] {
317+
#[inline]
318+
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
319+
if any::TypeId::of::<T>() == any::TypeId::of::<u8>() {
320+
// SAFETY: checked that T is exactly u8, so &self, of type, &[T], is exactly &[u8]
321+
let u8_slice = unsafe {
322+
std::slice::from_raw_parts(self.as_ptr().cast::<u8>(), self.len())
323+
};
324+
consensus_encode_with_size(u8_slice, s)
325+
} else {
326+
let mut len = 0;
327+
len += VarInt(self.len() as u64).consensus_encode(&mut s)?;
328+
for c in self {
329+
len += c.consensus_encode(&mut s)?;
328330
}
331+
Ok(len)
329332
}
333+
}
334+
}
330335

331-
impl Decodable for Vec<$type> {
332-
#[inline]
333-
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
334-
let len = VarInt::consensus_decode(&mut d)?.0;
335-
let byte_size = (len as usize)
336-
.checked_mul(mem::size_of::<$type>())
337-
.ok_or(self::Error::ParseFailed("Invalid length"))?;
338-
if byte_size > MAX_VEC_SIZE {
339-
return Err(self::Error::OversizedVectorAllocation {
340-
requested: byte_size,
341-
max: MAX_VEC_SIZE,
342-
});
343-
}
344-
let mut ret = Vec::with_capacity(len as usize);
345-
for _ in 0..len {
346-
ret.push(Decodable::consensus_decode(&mut d)?);
347-
}
348-
Ok(ret)
336+
impl<T: Encodable + any::Any> Encodable for Vec<T> {
337+
#[inline]
338+
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
339+
self[..].consensus_encode(s)
340+
}
341+
}
342+
343+
impl<T: Encodable + any::Any> Encodable for Box<[T]> {
344+
#[inline]
345+
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
346+
self[..].consensus_encode(s)
347+
}
348+
}
349+
350+
impl<T: Decodable + any::Any> Decodable for Vec<T> {
351+
#[inline]
352+
fn consensus_decode<D: crate::ReadExt>(mut d: D) -> Result<Self, Error> {
353+
if any::TypeId::of::<T>() == any::TypeId::of::<u8>() {
354+
let s = VarInt::consensus_decode(&mut d)?.0 as usize;
355+
if s > MAX_VEC_SIZE {
356+
return Err(self::Error::OversizedVectorAllocation {
357+
requested: s,
358+
max: MAX_VEC_SIZE,
359+
});
360+
}
361+
let mut v = vec![0; s];
362+
d.read_slice(&mut v)?;
363+
// SAFETY: checked that T is exactly u8, so v, of type, Vec<u8>, is exactly Vec<T>
364+
unsafe {
365+
Ok(std::mem::transmute::<Vec<u8>, Vec<T>>(v))
366+
}
367+
} else {
368+
let len = VarInt::consensus_decode(&mut d)?.0;
369+
let byte_size = (len as usize)
370+
.checked_mul(mem::size_of::<T>())
371+
.ok_or(self::Error::ParseFailed("Invalid length"))?;
372+
if byte_size > MAX_VEC_SIZE {
373+
return Err(self::Error::OversizedVectorAllocation {
374+
requested: byte_size,
375+
max: MAX_VEC_SIZE,
376+
});
349377
}
378+
let mut ret = Vec::with_capacity(len as usize);
379+
for _ in 0..len {
380+
ret.push(Decodable::consensus_decode(&mut d)?);
381+
}
382+
Ok(ret)
350383
}
351-
};
384+
}
385+
}
386+
387+
impl<T: Decodable + any::Any> Decodable for Box<[T]> {
388+
#[inline]
389+
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
390+
let v = Vec::<T>::consensus_decode(d)?;
391+
Ok(v.into())
392+
}
352393
}
353-
impl_vec!(TxIn);
354-
impl_vec!(TxOut);
355-
impl_vec!(Transaction);
356-
impl_vec!(TapLeafHash);
357-
impl_vec!(Vec<u8>); // Vec<Vec<u8>>
358394

359395
macro_rules! impl_array {
360396
( $size:literal ) => {
@@ -383,38 +419,6 @@ impl_array!(4);
383419
impl_array!(32);
384420
impl_array!(33);
385421

386-
impl Encodable for Box<[u8]> {
387-
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
388-
consensus_encode_with_size(&self[..], &mut w)
389-
}
390-
}
391-
impl Decodable for Box<[u8]> {
392-
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
393-
let v = Vec::<u8>::consensus_decode(d)?;
394-
Ok(v.into())
395-
}
396-
}
397-
398-
impl Encodable for Vec<u8> {
399-
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
400-
consensus_encode_with_size(&self[..], &mut w)
401-
}
402-
}
403-
impl Decodable for Vec<u8> {
404-
fn consensus_decode<D: crate::ReadExt>(mut d: D) -> Result<Self, Error> {
405-
let s = VarInt::consensus_decode(&mut d)?.0 as usize;
406-
if s > MAX_VEC_SIZE {
407-
return Err(self::Error::OversizedVectorAllocation {
408-
requested: s,
409-
max: MAX_VEC_SIZE,
410-
});
411-
}
412-
let mut v = vec![0; s];
413-
d.read_slice(&mut v)?;
414-
Ok(v)
415-
}
416-
}
417-
418422
macro_rules! impl_box_option {
419423
($type: ty) => {
420424
impl Encodable for Option<Box<$type>> {

src/pset/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ use secp256k1_zkp;
2626
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2727
/// Enum for marking pset hash error
2828
pub enum PsetHash {
29+
/// Bad preimage for `RIPEMD160` hash.
2930
Ripemd,
31+
/// Bad preimage for `SHA256` hash.
3032
Sha256,
33+
/// Bad preimage for `RIPEMD160-SHA256` hash.
3134
Hash160,
35+
/// Bad preimage for double-`SHA256` hash.
3236
Hash256,
3337
}
3438
/// Ways that a Partially Signed Transaction might fail.

src/pset/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use crate::{
5353
use secp256k1_zkp::rand::{CryptoRng, RngCore};
5454
use secp256k1_zkp::{self, RangeProof, SecretKey, SurjectionProof};
5555

56-
pub use self::error::{Error, PsetBlindError};
56+
pub use self::error::{Error, PsetBlindError, PsetHash};
5757
use self::map::Map;
5858
pub use self::map::{Global, GlobalTxData, Input, Output, PsbtSighashType, TapTree};
5959

0 commit comments

Comments
 (0)