|
| 1 | +macro_rules! encode_tlv { |
| 2 | + ($stream: expr, {$(($type: expr, $field: expr)),*}) => { { |
| 3 | + use util::ser::{BigSize, LengthCalculatingWriter}; |
| 4 | + $( |
| 5 | + BigSize($type).write($stream)?; |
| 6 | + let mut len_calc = LengthCalculatingWriter(0); |
| 7 | + $field.write(&mut len_calc)?; |
| 8 | + BigSize(len_calc.0 as u64).write($stream)?; |
| 9 | + $field.write($stream)?; |
| 10 | + )* |
| 11 | + } } |
| 12 | +} |
| 13 | + |
| 14 | +macro_rules! encode_varint_length_prefixed_tlv { |
| 15 | + ($stream: expr, {$(($type: expr, $field: expr)),*}) => { { |
| 16 | + use util::ser::{BigSize, LengthCalculatingWriter}; |
| 17 | + let mut len = LengthCalculatingWriter(0); |
| 18 | + { |
| 19 | + $( |
| 20 | + BigSize($type).write(&mut len)?; |
| 21 | + let mut field_len = LengthCalculatingWriter(0); |
| 22 | + $field.write(&mut field_len)?; |
| 23 | + BigSize(field_len.0 as u64).write(&mut len)?; |
| 24 | + len.0 += field_len.0; |
| 25 | + )* |
| 26 | + } |
| 27 | + |
| 28 | + BigSize(len.0 as u64).write($stream)?; |
| 29 | + encode_tlv!($stream, { |
| 30 | + $(($type, $field)),* |
| 31 | + }); |
| 32 | + } } |
| 33 | +} |
| 34 | + |
| 35 | +macro_rules! decode_tlv { |
| 36 | + ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),*}, {$(($type: expr, $field: ident)),*}) => { { |
| 37 | + use ln::msgs::DecodeError; |
| 38 | + let mut last_seen_type: Option<u64> = None; |
| 39 | + 'tlv_read: loop { |
| 40 | + use util::ser; |
| 41 | + |
| 42 | + // First decode the type of this TLV: |
| 43 | + let typ: ser::BigSize = { |
| 44 | + // We track whether any bytes were read during the consensus_decode call to |
| 45 | + // determine whether we should break or return ShortRead if we get an |
| 46 | + // UnexpectedEof. This should in every case be largely cosmetic, but its nice to |
| 47 | + // pass the TLV test vectors exactly, which requre this distinction. |
| 48 | + let mut tracking_reader = ser::ReadTrackingReader::new($stream); |
| 49 | + match ser::Readable::read(&mut tracking_reader) { |
| 50 | + Err(DecodeError::ShortRead) => { |
| 51 | + if !tracking_reader.have_read { |
| 52 | + break 'tlv_read |
| 53 | + } else { |
| 54 | + Err(DecodeError::ShortRead)? |
| 55 | + } |
| 56 | + }, |
| 57 | + Err(e) => Err(e)?, |
| 58 | + Ok(t) => t, |
| 59 | + } |
| 60 | + }; |
| 61 | + |
| 62 | + // Types must be unique and monotonically increasing: |
| 63 | + match last_seen_type { |
| 64 | + Some(t) if typ.0 <= t => { |
| 65 | + Err(DecodeError::InvalidValue)? |
| 66 | + }, |
| 67 | + _ => {}, |
| 68 | + } |
| 69 | + // As we read types, make sure we hit every required type: |
| 70 | + $(if (last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype) && typ.0 > $reqtype { |
| 71 | + Err(DecodeError::InvalidValue)? |
| 72 | + })* |
| 73 | + last_seen_type = Some(typ.0); |
| 74 | + |
| 75 | + // Finally, read the length and value itself: |
| 76 | + let length: ser::BigSize = Readable::read($stream)?; |
| 77 | + let mut s = ser::FixedLengthReader::new($stream, length.0); |
| 78 | + match typ.0 { |
| 79 | + $($reqtype => { |
| 80 | + $reqfield = ser::Readable::read(&mut s)?; |
| 81 | + if s.bytes_remain() { |
| 82 | + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes |
| 83 | + Err(DecodeError::InvalidValue)? |
| 84 | + } |
| 85 | + },)* |
| 86 | + $($type => { |
| 87 | + $field = Some(ser::Readable::read(&mut s)?); |
| 88 | + if s.bytes_remain() { |
| 89 | + s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes |
| 90 | + Err(DecodeError::InvalidValue)? |
| 91 | + } |
| 92 | + },)* |
| 93 | + x if x % 2 == 0 => { |
| 94 | + Err(DecodeError::UnknownRequiredFeature)? |
| 95 | + }, |
| 96 | + _ => {}, |
| 97 | + } |
| 98 | + s.eat_remaining()?; |
| 99 | + } |
| 100 | + // Make sure we got to each required type after we've read every TLV: |
| 101 | + $(if last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype { |
| 102 | + Err(DecodeError::InvalidValue)? |
| 103 | + })* |
| 104 | + } } |
| 105 | +} |
| 106 | + |
1 | 107 | macro_rules! impl_writeable {
|
2 | 108 | ($st:ident, $len: expr, {$($field:ident),*}) => {
|
3 | 109 | impl ::util::ser::Writeable for $st {
|
@@ -40,3 +146,224 @@ macro_rules! impl_writeable_len_match {
|
40 | 146 | }
|
41 | 147 | }
|
42 | 148 | }
|
| 149 | + |
| 150 | +#[cfg(test)] |
| 151 | +mod tests { |
| 152 | + use std::io::{Cursor, Read}; |
| 153 | + use ln::msgs::DecodeError; |
| 154 | + use util::ser::{Readable, Writeable, HighZeroBytesDroppedVarInt, VecWriter}; |
| 155 | + use secp256k1::PublicKey; |
| 156 | + |
| 157 | + // The BOLT TLV test cases don't include any tests which use our "required-value" logic since |
| 158 | + // the encoding layer in the BOLTs has no such concept, though it makes our macros easier to |
| 159 | + // work with so they're baked into the decoder. Thus, we have a few additional tests below |
| 160 | + fn tlv_reader(s: &[u8]) -> Result<(u64, u32, Option<u32>), DecodeError> { |
| 161 | + let mut s = Cursor::new(s); |
| 162 | + let mut a: u64 = 0; |
| 163 | + let mut b: u32 = 0; |
| 164 | + let mut c: Option<u32> = None; |
| 165 | + decode_tlv!(&mut s, {(2, a), (3, b)}, {(4, c)}); |
| 166 | + Ok((a, b, c)) |
| 167 | + } |
| 168 | + |
| 169 | + #[test] |
| 170 | + fn tlv_v_short_read() { |
| 171 | + // We only expect a u32 for type 3 (which we are given), but the L says its 8 bytes. |
| 172 | + if let Err(DecodeError::ShortRead) = tlv_reader(&::hex::decode( |
| 173 | + concat!("0100", "0208deadbeef1badbeef", "0308deadbeef") |
| 174 | + ).unwrap()[..]) { |
| 175 | + } else { panic!(); } |
| 176 | + } |
| 177 | + |
| 178 | + #[test] |
| 179 | + fn tlv_types_out_of_order() { |
| 180 | + if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode( |
| 181 | + concat!("0100", "0304deadbeef", "0208deadbeef1badbeef") |
| 182 | + ).unwrap()[..]) { |
| 183 | + } else { panic!(); } |
| 184 | + // ...even if its some field we don't understand |
| 185 | + if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode( |
| 186 | + concat!("0208deadbeef1badbeef", "0100", "0304deadbeef") |
| 187 | + ).unwrap()[..]) { |
| 188 | + } else { panic!(); } |
| 189 | + } |
| 190 | + |
| 191 | + #[test] |
| 192 | + fn tlv_req_type_missing_or_extra() { |
| 193 | + // It's also bad if they included even fields we don't understand |
| 194 | + if let Err(DecodeError::UnknownRequiredFeature) = tlv_reader(&::hex::decode( |
| 195 | + concat!("0100", "0208deadbeef1badbeef", "0304deadbeef", "0600") |
| 196 | + ).unwrap()[..]) { |
| 197 | + } else { panic!(); } |
| 198 | + // ... or if they're missing fields we need |
| 199 | + if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode( |
| 200 | + concat!("0100", "0208deadbeef1badbeef") |
| 201 | + ).unwrap()[..]) { |
| 202 | + } else { panic!(); } |
| 203 | + // ... even if that field is even |
| 204 | + if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode( |
| 205 | + concat!("0304deadbeef", "0500") |
| 206 | + ).unwrap()[..]) { |
| 207 | + } else { panic!(); } |
| 208 | + } |
| 209 | + |
| 210 | + #[test] |
| 211 | + fn tlv_simple_good_cases() { |
| 212 | + assert_eq!(tlv_reader(&::hex::decode( |
| 213 | + concat!("0208deadbeef1badbeef", "03041bad1dea") |
| 214 | + ).unwrap()[..]).unwrap(), |
| 215 | + (0xdeadbeef1badbeef, 0x1bad1dea, None)); |
| 216 | + assert_eq!(tlv_reader(&::hex::decode( |
| 217 | + concat!("0208deadbeef1badbeef", "03041bad1dea", "040401020304") |
| 218 | + ).unwrap()[..]).unwrap(), |
| 219 | + (0xdeadbeef1badbeef, 0x1bad1dea, Some(0x01020304))); |
| 220 | + } |
| 221 | + |
| 222 | + impl<R: Read> Readable<R> for (PublicKey, u64, u64) { |
| 223 | + #[inline] |
| 224 | + fn read(reader: &mut R) -> Result<(PublicKey, u64, u64), DecodeError> { |
| 225 | + Ok((Readable::read(reader)?, Readable::read(reader)?, Readable::read(reader)?)) |
| 226 | + } |
| 227 | + } |
| 228 | + |
| 229 | + // BOLT TLV test cases |
| 230 | + fn tlv_reader_n1(s: &[u8]) -> Result<(Option<HighZeroBytesDroppedVarInt<u64>>, Option<u64>, Option<(PublicKey, u64, u64)>, Option<u16>), DecodeError> { |
| 231 | + let mut s = Cursor::new(s); |
| 232 | + let mut tlv1: Option<HighZeroBytesDroppedVarInt<u64>> = None; |
| 233 | + let mut tlv2: Option<u64> = None; |
| 234 | + let mut tlv3: Option<(PublicKey, u64, u64)> = None; |
| 235 | + let mut tlv4: Option<u16> = None; |
| 236 | + decode_tlv!(&mut s, {}, {(1, tlv1), (2, tlv2), (3, tlv3), (254, tlv4)}); |
| 237 | + Ok((tlv1, tlv2, tlv3, tlv4)) |
| 238 | + } |
| 239 | + |
| 240 | + #[test] |
| 241 | + fn bolt_tlv_bogus_stream() { |
| 242 | + macro_rules! do_test { |
| 243 | + ($stream: expr, $reason: ident) => { |
| 244 | + if let Err(DecodeError::$reason) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) { |
| 245 | + } else { panic!(); } |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + // TLVs from the BOLT test cases which should not decode as either n1 or n2 |
| 250 | + do_test!(concat!("fd01"), ShortRead); |
| 251 | + do_test!(concat!("fd0001", "00"), InvalidValue); |
| 252 | + do_test!(concat!("fd0101"), ShortRead); |
| 253 | + do_test!(concat!("0f", "fd"), ShortRead); |
| 254 | + do_test!(concat!("0f", "fd26"), ShortRead); |
| 255 | + do_test!(concat!("0f", "fd2602"), ShortRead); |
| 256 | + do_test!(concat!("0f", "fd0001", "00"), InvalidValue); |
| 257 | + do_test!(concat!("0f", "fd0201", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), ShortRead); |
| 258 | + |
| 259 | + do_test!(concat!("12", "00"), UnknownRequiredFeature); |
| 260 | + do_test!(concat!("fd0102", "00"), UnknownRequiredFeature); |
| 261 | + do_test!(concat!("fe01000002", "00"), UnknownRequiredFeature); |
| 262 | + do_test!(concat!("ff0100000000000002", "00"), UnknownRequiredFeature); |
| 263 | + } |
| 264 | + |
| 265 | + #[test] |
| 266 | + fn bolt_tlv_bogus_n1_stream() { |
| 267 | + macro_rules! do_test { |
| 268 | + ($stream: expr, $reason: ident) => { |
| 269 | + if let Err(DecodeError::$reason) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) { |
| 270 | + } else { panic!(); } |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + // TLVs from the BOLT test cases which should not decode as n1 |
| 275 | + do_test!(concat!("01", "09", "ffffffffffffffffff"), InvalidValue); |
| 276 | + do_test!(concat!("01", "01", "00"), InvalidValue); |
| 277 | + do_test!(concat!("01", "02", "0001"), InvalidValue); |
| 278 | + do_test!(concat!("01", "03", "000100"), InvalidValue); |
| 279 | + do_test!(concat!("01", "04", "00010000"), InvalidValue); |
| 280 | + do_test!(concat!("01", "05", "0001000000"), InvalidValue); |
| 281 | + do_test!(concat!("01", "06", "000100000000"), InvalidValue); |
| 282 | + do_test!(concat!("01", "07", "00010000000000"), InvalidValue); |
| 283 | + do_test!(concat!("01", "08", "0001000000000000"), InvalidValue); |
| 284 | + do_test!(concat!("02", "07", "01010101010101"), ShortRead); |
| 285 | + do_test!(concat!("02", "09", "010101010101010101"), InvalidValue); |
| 286 | + do_test!(concat!("03", "21", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb"), ShortRead); |
| 287 | + do_test!(concat!("03", "29", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001"), ShortRead); |
| 288 | + do_test!(concat!("03", "30", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb000000000000000100000000000001"), ShortRead); |
| 289 | + do_test!(concat!("03", "31", "043da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"), InvalidValue); |
| 290 | + do_test!(concat!("03", "32", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001000000000000000001"), InvalidValue); |
| 291 | + do_test!(concat!("fd00fe", "00"), ShortRead); |
| 292 | + do_test!(concat!("fd00fe", "01", "01"), ShortRead); |
| 293 | + do_test!(concat!("fd00fe", "03", "010101"), InvalidValue); |
| 294 | + do_test!(concat!("00", "00"), UnknownRequiredFeature); |
| 295 | + |
| 296 | + do_test!(concat!("02", "08", "0000000000000226", "01", "01", "2a"), InvalidValue); |
| 297 | + do_test!(concat!("02", "08", "0000000000000231", "02", "08", "0000000000000451"), InvalidValue); |
| 298 | + do_test!(concat!("1f", "00", "0f", "01", "2a"), InvalidValue); |
| 299 | + do_test!(concat!("1f", "00", "1f", "01", "2a"), InvalidValue); |
| 300 | + |
| 301 | + // The last BOLT test modified to not require creating a new decoder for one trivial test. |
| 302 | + do_test!(concat!("ffffffffffffffffff", "00", "01", "00"), InvalidValue); |
| 303 | + } |
| 304 | + |
| 305 | + #[test] |
| 306 | + fn bolt_tlv_valid_n1_stream() { |
| 307 | + macro_rules! do_test { |
| 308 | + ($stream: expr, $tlv1: expr, $tlv2: expr, $tlv3: expr, $tlv4: expr) => { |
| 309 | + if let Ok((tlv1, tlv2, tlv3, tlv4)) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) { |
| 310 | + assert_eq!(tlv1.map(|v| v.0), $tlv1); |
| 311 | + assert_eq!(tlv2, $tlv2); |
| 312 | + assert_eq!(tlv3, $tlv3); |
| 313 | + assert_eq!(tlv4, $tlv4); |
| 314 | + } else { panic!(); } |
| 315 | + } |
| 316 | + } |
| 317 | + |
| 318 | + do_test!(concat!(""), None, None, None, None); |
| 319 | + do_test!(concat!("21", "00"), None, None, None, None); |
| 320 | + do_test!(concat!("fd0201", "00"), None, None, None, None); |
| 321 | + do_test!(concat!("fd00fd", "00"), None, None, None, None); |
| 322 | + do_test!(concat!("fd00ff", "00"), None, None, None, None); |
| 323 | + do_test!(concat!("fe02000001", "00"), None, None, None, None); |
| 324 | + do_test!(concat!("ff0200000000000001", "00"), None, None, None, None); |
| 325 | + |
| 326 | + do_test!(concat!("01", "00"), Some(0), None, None, None); |
| 327 | + do_test!(concat!("01", "01", "01"), Some(1), None, None, None); |
| 328 | + do_test!(concat!("01", "02", "0100"), Some(256), None, None, None); |
| 329 | + do_test!(concat!("01", "03", "010000"), Some(65536), None, None, None); |
| 330 | + do_test!(concat!("01", "04", "01000000"), Some(16777216), None, None, None); |
| 331 | + do_test!(concat!("01", "05", "0100000000"), Some(4294967296), None, None, None); |
| 332 | + do_test!(concat!("01", "06", "010000000000"), Some(1099511627776), None, None, None); |
| 333 | + do_test!(concat!("01", "07", "01000000000000"), Some(281474976710656), None, None, None); |
| 334 | + do_test!(concat!("01", "08", "0100000000000000"), Some(72057594037927936), None, None, None); |
| 335 | + do_test!(concat!("02", "08", "0000000000000226"), None, Some((0 << 30) | (0 << 5) | (550 << 0)), None, None); |
| 336 | + do_test!(concat!("03", "31", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"), |
| 337 | + None, None, Some(( |
| 338 | + PublicKey::from_slice(&::hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]).unwrap(), 1, 2)), |
| 339 | + None); |
| 340 | + do_test!(concat!("fd00fe", "02", "0226"), None, None, None, Some(550)); |
| 341 | + } |
| 342 | + |
| 343 | + fn do_simple_test_tlv_write() -> Result<(), ::std::io::Error> { |
| 344 | + let mut stream = VecWriter(Vec::new()); |
| 345 | + |
| 346 | + stream.0.clear(); |
| 347 | + encode_varint_length_prefixed_tlv!(&mut stream, { (1, 1u8) }); |
| 348 | + assert_eq!(stream.0, ::hex::decode("03010101").unwrap()); |
| 349 | + |
| 350 | + stream.0.clear(); |
| 351 | + encode_varint_length_prefixed_tlv!(&mut stream, { (4, 0xabcdu16) }); |
| 352 | + assert_eq!(stream.0, ::hex::decode("040402abcd").unwrap()); |
| 353 | + |
| 354 | + stream.0.clear(); |
| 355 | + encode_varint_length_prefixed_tlv!(&mut stream, { (0xff, 0xabcdu16) }); |
| 356 | + assert_eq!(stream.0, ::hex::decode("06fd00ff02abcd").unwrap()); |
| 357 | + |
| 358 | + stream.0.clear(); |
| 359 | + encode_varint_length_prefixed_tlv!(&mut stream, { (0, 1u64), (0xff, HighZeroBytesDroppedVarInt(0u64)) }); |
| 360 | + assert_eq!(stream.0, ::hex::decode("0e00080000000000000001fd00ff00").unwrap()); |
| 361 | + |
| 362 | + Ok(()) |
| 363 | + } |
| 364 | + |
| 365 | + #[test] |
| 366 | + fn simple_test_tlv_write() { |
| 367 | + do_simple_test_tlv_write().unwrap(); |
| 368 | + } |
| 369 | +} |
0 commit comments