@@ -42,7 +42,7 @@ use io_extras::read_to_end;
42
42
43
43
use util:: events:: MessageSendEventsProvider ;
44
44
use util:: logger;
45
- use util:: ser:: { LengthReadable , Readable , ReadableArgs , Writeable , Writer , FixedLengthReader , HighZeroBytesDroppedVarInt , Hostname } ;
45
+ use util:: ser:: { BigSize , LengthReadable , Readable , ReadableArgs , Writeable , Writer , FixedLengthReader , HighZeroBytesDroppedBigSize , Hostname } ;
46
46
47
47
use ln:: { PaymentPreimage , PaymentHash , PaymentSecret } ;
48
48
@@ -1375,14 +1375,14 @@ impl Writeable for OnionMessage {
1375
1375
impl Writeable for FinalOnionHopData {
1376
1376
fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
1377
1377
self . payment_secret . 0 . write ( w) ?;
1378
- HighZeroBytesDroppedVarInt ( self . total_msat ) . write ( w)
1378
+ HighZeroBytesDroppedBigSize ( self . total_msat ) . write ( w)
1379
1379
}
1380
1380
}
1381
1381
1382
1382
impl Readable for FinalOnionHopData {
1383
1383
fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1384
1384
let secret: [ u8 ; 32 ] = Readable :: read ( r) ?;
1385
- let amt: HighZeroBytesDroppedVarInt < u64 > = Readable :: read ( r) ?;
1385
+ let amt: HighZeroBytesDroppedBigSize < u64 > = Readable :: read ( r) ?;
1386
1386
Ok ( Self { payment_secret : PaymentSecret ( secret) , total_msat : amt. 0 } )
1387
1387
}
1388
1388
}
@@ -1399,15 +1399,15 @@ impl Writeable for OnionHopData {
1399
1399
} ,
1400
1400
OnionHopDataFormat :: NonFinalNode { short_channel_id } => {
1401
1401
encode_varint_length_prefixed_tlv ! ( w, {
1402
- ( 2 , HighZeroBytesDroppedVarInt ( self . amt_to_forward) , required) ,
1403
- ( 4 , HighZeroBytesDroppedVarInt ( self . outgoing_cltv_value) , required) ,
1402
+ ( 2 , HighZeroBytesDroppedBigSize ( self . amt_to_forward) , required) ,
1403
+ ( 4 , HighZeroBytesDroppedBigSize ( self . outgoing_cltv_value) , required) ,
1404
1404
( 6 , short_channel_id, required)
1405
1405
} ) ;
1406
1406
} ,
1407
1407
OnionHopDataFormat :: FinalNode { ref payment_data, ref keysend_preimage } => {
1408
1408
encode_varint_length_prefixed_tlv ! ( w, {
1409
- ( 2 , HighZeroBytesDroppedVarInt ( self . amt_to_forward) , required) ,
1410
- ( 4 , HighZeroBytesDroppedVarInt ( self . outgoing_cltv_value) , required) ,
1409
+ ( 2 , HighZeroBytesDroppedBigSize ( self . amt_to_forward) , required) ,
1410
+ ( 4 , HighZeroBytesDroppedBigSize ( self . outgoing_cltv_value) , required) ,
1411
1411
( 8 , payment_data, option) ,
1412
1412
( 5482373484 , keysend_preimage, option)
1413
1413
} ) ;
@@ -1417,36 +1417,23 @@ impl Writeable for OnionHopData {
1417
1417
}
1418
1418
}
1419
1419
1420
- // ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
1421
- // onion message packets.
1422
- impl ReadableArgs < ( ) > for OnionHopData {
1423
- fn read < R : Read > ( r : & mut R , _arg : ( ) ) -> Result < Self , DecodeError > {
1424
- <Self as Readable >:: read ( r)
1425
- }
1426
- }
1427
-
1428
1420
impl Readable for OnionHopData {
1429
- fn read < R : Read > ( mut r : & mut R ) -> Result < Self , DecodeError > {
1430
- use bitcoin:: consensus:: encode:: { Decodable , Error , VarInt } ;
1431
- let v: VarInt = Decodable :: consensus_decode ( & mut r)
1432
- . map_err ( |e| match e {
1433
- Error :: Io ( ioe) => DecodeError :: from ( ioe) ,
1434
- _ => DecodeError :: InvalidValue
1435
- } ) ?;
1421
+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1422
+ let b: BigSize = Readable :: read ( r) ?;
1436
1423
const LEGACY_ONION_HOP_FLAG : u64 = 0 ;
1437
- let ( format, amt, cltv_value) = if v . 0 != LEGACY_ONION_HOP_FLAG {
1438
- let mut rd = FixedLengthReader :: new ( r, v . 0 ) ;
1439
- let mut amt = HighZeroBytesDroppedVarInt ( 0u64 ) ;
1440
- let mut cltv_value = HighZeroBytesDroppedVarInt ( 0u32 ) ;
1424
+ let ( format, amt, cltv_value) = if b . 0 != LEGACY_ONION_HOP_FLAG {
1425
+ let mut rd = FixedLengthReader :: new ( r, b . 0 ) ;
1426
+ let mut amt = HighZeroBytesDroppedBigSize ( 0u64 ) ;
1427
+ let mut cltv_value = HighZeroBytesDroppedBigSize ( 0u32 ) ;
1441
1428
let mut short_id: Option < u64 > = None ;
1442
1429
let mut payment_data: Option < FinalOnionHopData > = None ;
1443
1430
let mut keysend_preimage: Option < PaymentPreimage > = None ;
1444
- // The TLV type is chosen to be compatible with lnd and c-lightning.
1445
1431
decode_tlv_stream ! ( & mut rd, {
1446
1432
( 2 , amt, required) ,
1447
1433
( 4 , cltv_value, required) ,
1448
1434
( 6 , short_id, option) ,
1449
1435
( 8 , payment_data, option) ,
1436
+ // See https://github.com/lightning/blips/blob/master/blip-0003.md
1450
1437
( 5482373484 , keysend_preimage, option)
1451
1438
} ) ;
1452
1439
rd. eat_remaining ( ) . map_err ( |_| DecodeError :: ShortRead ) ?;
@@ -1488,6 +1475,14 @@ impl Readable for OnionHopData {
1488
1475
}
1489
1476
}
1490
1477
1478
+ // ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
1479
+ // onion message packets.
1480
+ impl ReadableArgs < ( ) > for OnionHopData {
1481
+ fn read < R : Read > ( r : & mut R , _arg : ( ) ) -> Result < Self , DecodeError > {
1482
+ <Self as Readable >:: read ( r)
1483
+ }
1484
+ }
1485
+
1491
1486
impl Writeable for Ping {
1492
1487
fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
1493
1488
self . ponglen . write ( w) ?;
@@ -1913,7 +1908,7 @@ mod tests {
1913
1908
use bitcoin:: secp256k1:: { PublicKey , SecretKey } ;
1914
1909
use bitcoin:: secp256k1:: { Secp256k1 , Message } ;
1915
1910
1916
- use io:: Cursor ;
1911
+ use io:: { self , Cursor } ;
1917
1912
use prelude:: * ;
1918
1913
use core:: convert:: TryFrom ;
1919
1914
@@ -2824,4 +2819,40 @@ mod tests {
2824
2819
assert_eq ! ( gossip_timestamp_filter. first_timestamp, 1590000000 ) ;
2825
2820
assert_eq ! ( gossip_timestamp_filter. timestamp_range, 0xffff_ffff ) ;
2826
2821
}
2822
+
2823
+ #[ test]
2824
+ fn decode_onion_hop_data_len_as_bigsize ( ) {
2825
+ // Tests that we can decode an onion payload that is >253 bytes.
2826
+ // Previously, receiving a payload of this size could've caused us to fail to decode a valid
2827
+ // payload, because we were decoding the length (a BigSize, big-endian) as a VarInt
2828
+ // (little-endian).
2829
+
2830
+ // Encode a test onion payload with a big custom TLV such that it's >253 bytes, forcing the
2831
+ // payload length to be encoded over multiple bytes rather than a single u8.
2832
+ let big_payload = encode_big_payload ( ) . unwrap ( ) ;
2833
+ let mut rd = Cursor :: new ( & big_payload[ ..] ) ;
2834
+ <msgs:: OnionHopData as Readable >:: read ( & mut rd) . unwrap ( ) ;
2835
+ }
2836
+ // see above test, needs to be a separate method for use of the serialization macros.
2837
+ fn encode_big_payload ( ) -> Result < Vec < u8 > , io:: Error > {
2838
+ use util:: ser:: HighZeroBytesDroppedBigSize ;
2839
+ let payload = msgs:: OnionHopData {
2840
+ format : OnionHopDataFormat :: NonFinalNode {
2841
+ short_channel_id : 0xdeadbeef1bad1dea ,
2842
+ } ,
2843
+ amt_to_forward : 1000 ,
2844
+ outgoing_cltv_value : 0xffffffff ,
2845
+ } ;
2846
+ let mut encoded_payload = Vec :: new ( ) ;
2847
+ let test_bytes = vec ! [ 42u8 ; 1000 ] ;
2848
+ if let OnionHopDataFormat :: NonFinalNode { short_channel_id } = payload. format {
2849
+ encode_varint_length_prefixed_tlv ! ( & mut encoded_payload, {
2850
+ ( 1 , test_bytes, vec_type) ,
2851
+ ( 2 , HighZeroBytesDroppedBigSize ( payload. amt_to_forward) , required) ,
2852
+ ( 4 , HighZeroBytesDroppedBigSize ( payload. outgoing_cltv_value) , required) ,
2853
+ ( 6 , short_channel_id, required)
2854
+ } ) ;
2855
+ }
2856
+ Ok ( encoded_payload)
2857
+ }
2827
2858
}
0 commit comments