@@ -6,6 +6,7 @@ use std::io::{Read, Write};
6
6
use std:: collections:: HashMap ;
7
7
use std:: hash:: Hash ;
8
8
use std:: sync:: Mutex ;
9
+ use std:: cmp;
9
10
10
11
use secp256k1:: Signature ;
11
12
use secp256k1:: key:: { PublicKey , SecretKey } ;
@@ -67,6 +68,83 @@ impl Writer for VecWriter {
67
68
}
68
69
}
69
70
71
+ pub ( crate ) struct LengthCalculatingWriter ( pub usize ) ;
72
+ impl Writer for LengthCalculatingWriter {
73
+ #[ inline]
74
+ fn write_all ( & mut self , buf : & [ u8 ] ) -> Result < ( ) , :: std:: io:: Error > {
75
+ self . 0 += buf. len ( ) ;
76
+ Ok ( ( ) )
77
+ }
78
+ #[ inline]
79
+ fn size_hint ( & mut self , _size : usize ) { }
80
+ }
81
+
82
+ /// Essentially std::io::Take but a bit simpler and with a method to walk the underlying stream
83
+ /// forward to ensure we always consume exactly the fixed length specified.
84
+ pub ( crate ) struct FixedLengthReader < R : Read > {
85
+ read : R ,
86
+ bytes_read : u64 ,
87
+ total_bytes : u64 ,
88
+ }
89
+ impl < R : Read > FixedLengthReader < R > {
90
+ pub fn new ( read : R , total_bytes : u64 ) -> Self {
91
+ Self { read, bytes_read : 0 , total_bytes }
92
+ }
93
+
94
+ pub fn bytes_remain ( & mut self ) -> bool {
95
+ self . bytes_read != self . total_bytes
96
+ }
97
+
98
+ pub fn eat_remaining ( & mut self ) -> Result < ( ) , DecodeError > {
99
+ :: std:: io:: copy ( self , & mut :: std:: io:: sink ( ) ) . unwrap ( ) ;
100
+ if self . bytes_read != self . total_bytes {
101
+ Err ( DecodeError :: ShortRead )
102
+ } else {
103
+ Ok ( ( ) )
104
+ }
105
+ }
106
+ }
107
+ impl < R : Read > Read for FixedLengthReader < R > {
108
+ fn read ( & mut self , dest : & mut [ u8 ] ) -> Result < usize , :: std:: io:: Error > {
109
+ if self . total_bytes == self . bytes_read {
110
+ Ok ( 0 )
111
+ } else {
112
+ let read_len = cmp:: min ( dest. len ( ) as u64 , self . total_bytes - self . bytes_read ) ;
113
+ match self . read . read ( & mut dest[ 0 ..( read_len as usize ) ] ) {
114
+ Ok ( v) => {
115
+ self . bytes_read += v as u64 ;
116
+ Ok ( v)
117
+ } ,
118
+ Err ( e) => Err ( e) ,
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ /// A Read which tracks whether any bytes have been read at all. This allows us to distinguish
125
+ /// between "EOF reached before we started" and "EOF reached mid-read".
126
+ pub ( crate ) struct ReadTrackingReader < R : Read > {
127
+ read : R ,
128
+ pub have_read : bool ,
129
+ }
130
+ impl < R : Read > ReadTrackingReader < R > {
131
+ pub fn new ( read : R ) -> Self {
132
+ Self { read, have_read : false }
133
+ }
134
+ }
135
+ impl < R : Read > Read for ReadTrackingReader < R > {
136
+ fn read ( & mut self , dest : & mut [ u8 ] ) -> Result < usize , :: std:: io:: Error > {
137
+ match self . read . read ( dest) {
138
+ Ok ( 0 ) => Ok ( 0 ) ,
139
+ Ok ( len) => {
140
+ self . have_read = true ;
141
+ Ok ( len)
142
+ } ,
143
+ Err ( e) => Err ( e) ,
144
+ }
145
+ }
146
+ }
147
+
70
148
/// A trait that various rust-lightning types implement allowing them to be written out to a Writer
71
149
pub trait Writeable {
72
150
/// Writes self out to the given Writer
@@ -125,6 +203,76 @@ impl<R: Read> Readable<R> for U48 {
125
203
}
126
204
}
127
205
206
+ /// Lightning TLV uses a custom variable-length integer called BigSize. It is similar to Bitcoin's
207
+ /// variable-length integers except that it is serialized in big-endian instead of little-endian.
208
+ ///
209
+ /// Like Bitcoin's variable-length integer, it exhibits ambiguity in that certain values can be
210
+ /// encoded in several different ways, which we must check for at deserialization-time. Thus, if
211
+ /// you're looking for an example of a variable-length integer to use for your own project, move
212
+ /// along, this is a rather poor design.
213
+ pub ( crate ) struct BigSize ( pub u64 ) ;
214
+ impl Writeable for BigSize {
215
+ #[ inline]
216
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , :: std:: io:: Error > {
217
+ match self . 0 {
218
+ 0 ...0xFC => {
219
+ ( self . 0 as u8 ) . write ( writer)
220
+ } ,
221
+ 0xFD ...0xFFFF => {
222
+ 0xFDu8 . write ( writer) ?;
223
+ ( self . 0 as u16 ) . write ( writer)
224
+ } ,
225
+ 0x10000 ...0xFFFFFFFF => {
226
+ 0xFEu8 . write ( writer) ?;
227
+ ( self . 0 as u32 ) . write ( writer)
228
+ } ,
229
+ _ => {
230
+ 0xFFu8 . write ( writer) ?;
231
+ ( self . 0 as u64 ) . write ( writer)
232
+ } ,
233
+ }
234
+ }
235
+ }
236
+ impl < R : Read > Readable < R > for BigSize {
237
+ #[ inline]
238
+ fn read ( reader : & mut R ) -> Result < BigSize , DecodeError > {
239
+ let n: u8 = Readable :: read ( reader) ?;
240
+ match n {
241
+ 0xFF => {
242
+ let x: u64 = Readable :: read ( reader) ?;
243
+ if x < 0x100000000 {
244
+ Err ( DecodeError :: InvalidValue )
245
+ } else {
246
+ Ok ( BigSize ( x) )
247
+ }
248
+ }
249
+ 0xFE => {
250
+ let x: u32 = Readable :: read ( reader) ?;
251
+ if x < 0x10000 {
252
+ Err ( DecodeError :: InvalidValue )
253
+ } else {
254
+ Ok ( BigSize ( x as u64 ) )
255
+ }
256
+ }
257
+ 0xFD => {
258
+ let x: u16 = Readable :: read ( reader) ?;
259
+ if x < 0xFD {
260
+ Err ( DecodeError :: InvalidValue )
261
+ } else {
262
+ Ok ( BigSize ( x as u64 ) )
263
+ }
264
+ }
265
+ n => Ok ( BigSize ( n as u64 ) )
266
+ }
267
+ }
268
+ }
269
+
270
+ /// In TLV we occasionally send fields which only consist of, or potentially end with, a
271
+ /// variabe-length integer which is simply truncated by skipping high zero bytes. This type
272
+ /// encapsulates such integers implementing Readable/Writeable for them.
273
+ #[ cfg_attr( test, derive( PartialEq , Debug ) ) ]
274
+ pub ( crate ) struct HighZeroBytesDroppedVarInt < T > ( pub T ) ;
275
+
128
276
macro_rules! impl_writeable_primitive {
129
277
( $val_type: ty, $meth_write: ident, $len: expr, $meth_read: ident) => {
130
278
impl Writeable for $val_type {
@@ -133,6 +281,13 @@ macro_rules! impl_writeable_primitive {
133
281
writer. write_all( & $meth_write( * self ) )
134
282
}
135
283
}
284
+ impl Writeable for HighZeroBytesDroppedVarInt <$val_type> {
285
+ #[ inline]
286
+ fn write<W : Writer >( & self , writer: & mut W ) -> Result <( ) , :: std:: io:: Error > {
287
+ // Skip any full leading 0 bytes when writing (in BE):
288
+ writer. write_all( & $meth_write( self . 0 ) [ ( self . 0 . leading_zeros( ) /8 ) as usize ..$len] )
289
+ }
290
+ }
136
291
impl <R : Read > Readable <R > for $val_type {
137
292
#[ inline]
138
293
fn read( reader: & mut R ) -> Result <$val_type, DecodeError > {
@@ -141,6 +296,30 @@ macro_rules! impl_writeable_primitive {
141
296
Ok ( $meth_read( & buf) )
142
297
}
143
298
}
299
+ impl <R : Read > Readable <R > for HighZeroBytesDroppedVarInt <$val_type> {
300
+ #[ inline]
301
+ fn read( reader: & mut R ) -> Result <HighZeroBytesDroppedVarInt <$val_type>, DecodeError > {
302
+ // We need to accept short reads (read_len == 0) as "EOF" and handle them as simply
303
+ // the high bytes being dropped. To do so, we start reading in the middle of buf
304
+ // and then convert the appropriate number of bytes with extra high bytes out of
305
+ // buf.
306
+ let mut buf = [ 0 ; $len* 2 ] ;
307
+ let mut read_len = reader. read( & mut buf[ $len..] ) ?;
308
+ let mut total_read_len = read_len;
309
+ while read_len != 0 && total_read_len != $len {
310
+ read_len = reader. read( & mut buf[ ( $len + read_len) ..] ) ?;
311
+ total_read_len += read_len;
312
+ }
313
+ if total_read_len == 0 || buf[ $len] != 0 {
314
+ let first_byte = $len - ( $len - total_read_len) ;
315
+ Ok ( HighZeroBytesDroppedVarInt ( $meth_read( & buf[ first_byte..first_byte + $len] ) ) )
316
+ } else {
317
+ // If the encoding had extra zero bytes, return a failure even though we know
318
+ // what they meant (as the TLV test vectors require this)
319
+ Err ( DecodeError :: InvalidValue )
320
+ }
321
+ }
322
+ }
144
323
}
145
324
}
146
325
0 commit comments