Skip to content

Commit 98d10e3

Browse files
committed
Stop implementing elements::Encodable with bitcoin::Encodable
Following bitcoin versions change `io` with `bitcoin_io`, upgrading would then require changing also elements::Encodable to match. Instead, we are re-implementing what is needed.
1 parent f875ae2 commit 98d10e3

File tree

6 files changed

+224
-56
lines changed

6 files changed

+224
-56
lines changed

src/block.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use std::io;
2323
use crate::dynafed;
2424
use crate::hashes::{Hash, sha256};
2525
use crate::Transaction;
26-
use crate::encode::{self, Encodable, Decodable, serialize};
27-
use crate::{BlockHash, Script, TxMerkleNode, VarInt};
26+
use crate::encode::{self, serialize, Decodable, Encodable, VarInt};
27+
use crate::{BlockHash, Script, TxMerkleNode};
2828

2929
/// Data related to block signatures
3030
#[derive(Clone, Debug, Eq, Hash, PartialEq)]

src/encode.rs

+185-40
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use std::io::Cursor;
1919
use std::{error, fmt, io, mem};
2020

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

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

6768
impl fmt::Display for Error {
@@ -87,23 +88,22 @@ impl fmt::Display for Error {
8788
Error::PsetError(ref e) => write!(f, "Pset Error: {}", e),
8889
Error::HexError(ref e) => write!(f, "Hex error {}", e),
8990
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
91+
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
9092
}
9193
}
9294
}
9395

9496
impl error::Error for Error {
9597
fn cause(&self) -> Option<&dyn error::Error> {
9698
match *self {
97-
Error::Bitcoin(ref e) => Some(e),
9899
Error::Secp256k1zkp(ref e) => Some(e),
99100
_ => None,
100101
}
101102
}
102103
}
103-
104104
#[doc(hidden)]
105-
impl From<btcenc::Error> for Error {
106-
fn from(e: btcenc::Error) -> Error {
105+
impl From<bitcoin::consensus::encode::Error> for Error {
106+
fn from(e: bitcoin::consensus::encode::Error) -> Error {
107107
Error::Bitcoin(e)
108108
}
109109
}
@@ -210,42 +210,11 @@ pub(crate) fn consensus_encode_with_size<S: io::Write>(
210210
data: &[u8],
211211
mut s: S,
212212
) -> Result<usize, Error> {
213-
let vi_len = bitcoin::VarInt(data.len() as u64).consensus_encode(&mut s)?;
213+
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?;
214214
s.emit_slice(data)?;
215215
Ok(vi_len + data.len())
216216
}
217217

218-
/// Implement Elements encodable traits for Bitcoin encodable types.
219-
macro_rules! impl_upstream {
220-
($type: ty) => {
221-
impl Encodable for $type {
222-
fn consensus_encode<W: io::Write>(&self, mut e: W) -> Result<usize, Error> {
223-
Ok(btcenc::Encodable::consensus_encode(self, &mut e)?)
224-
}
225-
}
226-
227-
impl Decodable for $type {
228-
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
229-
Ok(btcenc::Decodable::consensus_decode(&mut d)?)
230-
}
231-
}
232-
};
233-
}
234-
impl_upstream!(u8);
235-
impl_upstream!(u32);
236-
impl_upstream!(u64);
237-
impl_upstream!([u8; 4]);
238-
impl_upstream!([u8; 32]);
239-
impl_upstream!(Box<[u8]>);
240-
impl_upstream!([u8; 33]);
241-
impl_upstream!(Vec<u8>);
242-
impl_upstream!(Vec<Vec<u8>>);
243-
impl_upstream!(btcenc::VarInt);
244-
impl_upstream!(bitcoin::Transaction);
245-
impl_upstream!(bitcoin::BlockHash);
246-
impl_upstream!(bitcoin::ScriptBuf);
247-
impl_upstream!(crate::hashes::sha256d::Hash);
248-
249218
// Specific locktime types (which appear in PSET/PSBT2 but not in rust-bitcoin PSBT)
250219
impl Encodable for crate::locktime::Height {
251220
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
@@ -275,14 +244,136 @@ impl Decodable for crate::locktime::Time {
275244
}
276245
}
277246

247+
// TODO reuse bitcoin's `WriteExt::emit_varint`, `ReadExt::read_varint` when available
248+
249+
/// A variable sized integer.
250+
pub struct VarInt(pub u64);
251+
impl Encodable for VarInt {
252+
fn consensus_encode<W: io::Write>(&self, mut e: W) -> Result<usize, Error> {
253+
match self.0 {
254+
i @ 0..=0xFC => {
255+
e.emit_u8(i as u8)?;
256+
Ok(1)
257+
}
258+
i @ 0xFD..=0xFFFF => {
259+
e.emit_u8(0xFD)?;
260+
e.emit_u16(i as u16)?;
261+
Ok(3)
262+
}
263+
i @ 0x10000..=0xFFFFFFFF => {
264+
e.emit_u8(0xFE)?;
265+
e.emit_u32(i as u32)?;
266+
Ok(5)
267+
}
268+
i => {
269+
e.emit_u8(0xFF)?;
270+
e.emit_u64(i)?;
271+
Ok(9)
272+
}
273+
}
274+
}
275+
}
276+
impl Decodable for VarInt {
277+
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
278+
match d.read_u8()? {
279+
0xFF => {
280+
let x = d.read_u64()?;
281+
if x < 0x100000000 {
282+
Err(Error::NonMinimalVarInt)
283+
} else {
284+
Ok(VarInt(x))
285+
}
286+
}
287+
0xFE => {
288+
let x = d.read_u32()?;
289+
if x < 0x10000 {
290+
Err(Error::NonMinimalVarInt)
291+
} else {
292+
Ok(VarInt(x as u64))
293+
}
294+
}
295+
0xFD => {
296+
let x = d.read_u16()?;
297+
if x < 0xFD {
298+
Err(Error::NonMinimalVarInt)
299+
} else {
300+
Ok(VarInt(x as u64))
301+
}
302+
}
303+
n => Ok(VarInt(n as u64)),
304+
}
305+
}
306+
}
307+
impl VarInt {
308+
/// returns the byte size used if this var int is serialized
309+
pub fn size(&self) -> usize {
310+
match self.0 {
311+
0..=0xFC => 1,
312+
0xFD..=0xFFFF => 3,
313+
0x10000..=0xFFFFFFFF => 5,
314+
_ => 9,
315+
}
316+
}
317+
}
318+
319+
// Primitive types
320+
macro_rules! impl_int {
321+
($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
322+
impl Encodable for $ty {
323+
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
324+
w.$meth_enc(*self)?;
325+
Ok(mem::size_of::<$ty>())
326+
}
327+
}
328+
impl Decodable for $ty {
329+
fn consensus_decode<R: io::Read>(mut r: R) -> Result<Self, Error> {
330+
Ok(ReadExt::$meth_dec(&mut r)?)
331+
}
332+
}
333+
};
334+
}
335+
336+
impl_int!(u8, read_u8, emit_u8);
337+
impl_int!(u16, read_u16, emit_u16);
338+
impl_int!(u32, read_u32, emit_u32);
339+
impl_int!(u64, read_u64, emit_u64);
340+
341+
impl Encodable for bitcoin::ScriptBuf {
342+
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
343+
Ok(bitcoin::consensus::encode::Encodable::consensus_encode(
344+
&self, &mut w,
345+
)?)
346+
}
347+
}
348+
impl Decodable for bitcoin::ScriptBuf {
349+
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
350+
Ok(bitcoin::consensus::encode::Decodable::consensus_decode(
351+
&mut d,
352+
)?)
353+
}
354+
}
355+
356+
impl Encodable for bitcoin::hashes::sha256d::Hash {
357+
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
358+
self.as_byte_array().consensus_encode(&mut w)
359+
}
360+
}
361+
impl Decodable for bitcoin::hashes::sha256d::Hash {
362+
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
363+
Ok(Self::from_byte_array(
364+
<<Self as Hash>::Bytes>::consensus_decode(d)?,
365+
))
366+
}
367+
}
368+
278369
// Vectors
279370
macro_rules! impl_vec {
280371
($type: ty) => {
281372
impl Encodable for Vec<$type> {
282373
#[inline]
283374
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, Error> {
284375
let mut len = 0;
285-
len += btcenc::VarInt(self.len() as u64).consensus_encode(&mut s)?;
376+
len += VarInt(self.len() as u64).consensus_encode(&mut s)?;
286377
for c in self.iter() {
287378
len += c.consensus_encode(&mut s)?;
288379
}
@@ -293,7 +384,7 @@ macro_rules! impl_vec {
293384
impl Decodable for Vec<$type> {
294385
#[inline]
295386
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
296-
let len = btcenc::VarInt::consensus_decode(&mut d)?.0;
387+
let len = VarInt::consensus_decode(&mut d)?.0;
297388
let byte_size = (len as usize)
298389
.checked_mul(mem::size_of::<$type>())
299390
.ok_or(self::Error::ParseFailed("Invalid length"))?;
@@ -316,6 +407,60 @@ impl_vec!(TxIn);
316407
impl_vec!(TxOut);
317408
impl_vec!(Transaction);
318409
impl_vec!(TapLeafHash);
410+
impl_vec!(Vec<u8>); // Vec<Vec<u8>>
411+
412+
macro_rules! impl_array {
413+
( $size:literal ) => {
414+
impl Encodable for [u8; $size] {
415+
#[inline]
416+
fn consensus_encode<W: WriteExt>(
417+
&self,
418+
mut w: W,
419+
) -> core::result::Result<usize, Error> {
420+
w.emit_slice(&self[..])?;
421+
Ok($size)
422+
}
423+
}
424+
425+
impl Decodable for [u8; $size] {
426+
#[inline]
427+
fn consensus_decode<R: ReadExt>(mut r: R) -> core::result::Result<Self, Error> {
428+
let mut ret = [0; $size];
429+
r.read_slice(&mut ret)?;
430+
Ok(ret)
431+
}
432+
}
433+
};
434+
}
435+
impl_array!(4);
436+
impl_array!(32);
437+
impl_array!(33);
438+
439+
impl Encodable for Box<[u8]> {
440+
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
441+
consensus_encode_with_size(&self[..], &mut w)
442+
}
443+
}
444+
impl Decodable for Box<[u8]> {
445+
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
446+
let v = Vec::<u8>::consensus_decode(d)?;
447+
Ok(v.into())
448+
}
449+
}
450+
451+
impl Encodable for Vec<u8> {
452+
fn consensus_encode<W: io::Write>(&self, mut w: W) -> Result<usize, Error> {
453+
consensus_encode_with_size(&self[..], &mut w)
454+
}
455+
}
456+
impl Decodable for Vec<u8> {
457+
fn consensus_decode<D: io::Read>(mut d: D) -> Result<Self, Error> {
458+
let s = VarInt::consensus_decode(&mut d)?.0 as usize;
459+
let mut v = vec![0; s];
460+
d.read_slice(&mut v)?;
461+
Ok(v)
462+
}
463+
}
319464

320465
macro_rules! impl_box_option {
321466
($type: ty) => {

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ pub use crate::transaction::Sequence;
7474
pub use crate::blind::{ConfidentialTxOutError, TxOutSecrets, SurjectionInput, TxOutError, VerificationError, BlindError, UnblindError, BlindValueProofs, BlindAssetProofs, RangeProofMessage};
7575
pub use crate::block::{BlockHeader, Block};
7676
pub use crate::block::ExtData as BlockExtData;
77-
pub use ::bitcoin::consensus::encode::VarInt;
7877
pub use crate::fast_merkle_root::fast_merkle_root;
7978
pub use crate::hash_types::*;
8079
pub use crate::issuance::{AssetId, ContractHash};

src/pset/map/global.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use std::{
2020
io::{self, Cursor, Read},
2121
};
2222

23-
use crate::encode;
23+
use crate::encode::{self, VarInt};
2424
use crate::encode::Decodable;
2525
use crate::endian::u32_to_array_le;
2626
use crate::pset::{self, map::Map, raw, Error};
27-
use crate::{LockTime, VarInt};
27+
use crate::LockTime;
2828
use bitcoin::bip32::{ChildNumber, DerivationPath, Xpub, Fingerprint, KeySource};
2929
use secp256k1_zkp::Tweak;
3030

src/pset/raw.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ use std::{fmt, io};
2121

2222
use super::Error;
2323
use crate::encode::{
24-
self, deserialize, serialize, Decodable, Encodable, ReadExt, WriteExt, MAX_VEC_SIZE,
24+
self, deserialize, serialize, Decodable, Encodable, VarInt, WriteExt, MAX_VEC_SIZE,
2525
};
2626
use crate::hex;
27-
use crate::VarInt;
2827
/// A PSET key in its raw byte form.
2928
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
3029
#[cfg_attr(
@@ -198,7 +197,7 @@ where
198197
let prefix = Vec::<u8>::consensus_decode(&mut d)?;
199198
let mut key = vec![];
200199

201-
let subtype = Subtype::from(d.read_u8()?);
200+
let subtype = Subtype::from(u8::consensus_decode(&mut d)?);
202201
d.read_to_end(&mut key)?;
203202

204203
Ok(ProprietaryKey {

0 commit comments

Comments
 (0)