18
18
use std:: io:: Cursor ;
19
19
use std:: { error, fmt, io, mem} ;
20
20
21
- use bitcoin:: consensus:: encode as btcenc;
22
21
use secp256k1_zkp:: { self , RangeProof , SurjectionProof , Tweak } ;
23
22
24
23
use crate :: hashes:: { sha256, Hash } ;
@@ -38,7 +37,7 @@ pub enum Error {
38
37
/// And I/O error
39
38
Io ( io:: Error ) ,
40
39
/// A Bitcoin encoding error.
41
- Bitcoin ( btcenc :: Error ) ,
40
+ Bitcoin ( bitcoin :: consensus :: encode :: Error ) ,
42
41
/// Tried to allocate an oversized vector
43
42
OversizedVectorAllocation {
44
43
/// The capacity requested
@@ -62,6 +61,8 @@ pub enum Error {
62
61
HexError ( crate :: hex:: Error ) ,
63
62
/// Got a time-based locktime when expecting a height-based one, or vice-versa
64
63
BadLockTime ( crate :: LockTime ) ,
64
+ /// VarInt was encoded in a non-minimal way.
65
+ NonMinimalVarInt ,
65
66
}
66
67
67
68
impl fmt:: Display for Error {
@@ -87,23 +88,22 @@ impl fmt::Display for Error {
87
88
Error :: PsetError ( ref e) => write ! ( f, "Pset Error: {}" , e) ,
88
89
Error :: HexError ( ref e) => write ! ( f, "Hex error {}" , e) ,
89
90
Error :: BadLockTime ( ref lt) => write ! ( f, "Invalid locktime {}" , lt) ,
91
+ Error :: NonMinimalVarInt => write ! ( f, "non-minimal varint" ) ,
90
92
}
91
93
}
92
94
}
93
95
94
96
impl error:: Error for Error {
95
97
fn cause ( & self ) -> Option < & dyn error:: Error > {
96
98
match * self {
97
- Error :: Bitcoin ( ref e) => Some ( e) ,
98
99
Error :: Secp256k1zkp ( ref e) => Some ( e) ,
99
100
_ => None ,
100
101
}
101
102
}
102
103
}
103
-
104
104
#[ 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 {
107
107
Error :: Bitcoin ( e)
108
108
}
109
109
}
@@ -210,42 +210,11 @@ pub(crate) fn consensus_encode_with_size<S: io::Write>(
210
210
data : & [ u8 ] ,
211
211
mut s : S ,
212
212
) -> 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) ?;
214
214
s. emit_slice ( data) ?;
215
215
Ok ( vi_len + data. len ( ) )
216
216
}
217
217
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
-
249
218
// Specific locktime types (which appear in PSET/PSBT2 but not in rust-bitcoin PSBT)
250
219
impl Encodable for crate :: locktime:: Height {
251
220
fn consensus_encode < S : io:: Write > ( & self , s : S ) -> Result < usize , Error > {
@@ -275,14 +244,136 @@ impl Decodable for crate::locktime::Time {
275
244
}
276
245
}
277
246
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
+
278
369
// Vectors
279
370
macro_rules! impl_vec {
280
371
( $type: ty) => {
281
372
impl Encodable for Vec <$type> {
282
373
#[ inline]
283
374
fn consensus_encode<S : io:: Write >( & self , mut s: S ) -> Result <usize , Error > {
284
375
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) ?;
286
377
for c in self . iter( ) {
287
378
len += c. consensus_encode( & mut s) ?;
288
379
}
@@ -293,7 +384,7 @@ macro_rules! impl_vec {
293
384
impl Decodable for Vec <$type> {
294
385
#[ inline]
295
386
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 ;
297
388
let byte_size = ( len as usize )
298
389
. checked_mul( mem:: size_of:: <$type>( ) )
299
390
. ok_or( self :: Error :: ParseFailed ( "Invalid length" ) ) ?;
@@ -316,6 +407,60 @@ impl_vec!(TxIn);
316
407
impl_vec ! ( TxOut ) ;
317
408
impl_vec ! ( Transaction ) ;
318
409
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
+ }
319
464
320
465
macro_rules! impl_box_option {
321
466
( $type: ty) => {
0 commit comments