Skip to content

Commit 4aad862

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 4aad862

6 files changed

Lines changed: 222 additions & 56 deletions

File tree

src/block.rs

Lines changed: 2 additions & 2 deletions
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

Lines changed: 183 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use std::io::Cursor;
1919
use std::{error, fmt, io, mem};
2020

21-
use bitcoin::consensus::encode as btcenc;
21+
use bitcoin::ScriptBuf;
2222
use secp256k1_zkp::{self, RangeProof, SurjectionProof, Tweak};
2323

2424
use crate::hashes::{sha256, Hash};
@@ -38,7 +38,7 @@ pub enum Error {
3838
/// And I/O error
3939
Io(io::Error),
4040
/// A Bitcoin encoding error.
41-
Bitcoin(btcenc::Error),
41+
Bitcoin(bitcoin::consensus::encode::Error),
4242
/// Tried to allocate an oversized vector
4343
OversizedVectorAllocation {
4444
/// The capacity requested
@@ -62,6 +62,8 @@ pub enum Error {
6262
HexError(crate::hex::Error),
6363
/// Got a time-based locktime when expecting a height-based one, or vice-versa
6464
BadLockTime(crate::LockTime),
65+
/// VarInt was encoded in a non-minimal way.
66+
NonMinimalVarInt,
6567
}
6668

6769
impl fmt::Display for Error {
@@ -87,23 +89,22 @@ impl fmt::Display for Error {
8789
Error::PsetError(ref e) => write!(f, "Pset Error: {}", e),
8890
Error::HexError(ref e) => write!(f, "Hex error {}", e),
8991
Error::BadLockTime(ref lt) => write!(f, "Invalid locktime {}", lt),
92+
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
9093
}
9194
}
9295
}
9396

9497
impl error::Error for Error {
9598
fn cause(&self) -> Option<&dyn error::Error> {
9699
match *self {
97-
Error::Bitcoin(ref e) => Some(e),
98100
Error::Secp256k1zkp(ref e) => Some(e),
99101
_ => None,
100102
}
101103
}
102104
}
103-
104105
#[doc(hidden)]
105-
impl From<btcenc::Error> for Error {
106-
fn from(e: btcenc::Error) -> Error {
106+
impl From<bitcoin::consensus::encode::Error> for Error {
107+
fn from(e: bitcoin::consensus::encode::Error) -> Error {
107108
Error::Bitcoin(e)
108109
}
109110
}
@@ -210,42 +211,11 @@ pub(crate) fn consensus_encode_with_size<S: io::Write>(
210211
data: &[u8],
211212
mut s: S,
212213
) -> Result<usize, Error> {
213-
let vi_len = bitcoin::VarInt(data.len() as u64).consensus_encode(&mut s)?;
214+
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?;
214215
s.emit_slice(data)?;
215216
Ok(vi_len + data.len())
216217
}
217218

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-
249219
// Specific locktime types (which appear in PSET/PSBT2 but not in rust-bitcoin PSBT)
250220
impl Encodable for crate::locktime::Height {
251221
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, Error> {
@@ -275,14 +245,133 @@ impl Decodable for crate::locktime::Time {
275245
}
276246
}
277247

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

320463
macro_rules! impl_box_option {
321464
($type: ty) => {

src/lib.rs

Lines changed: 0 additions & 1 deletion
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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 2 additions & 3 deletions
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)