@@ -42,7 +42,7 @@ use io_extras::read_to_end;
4242
4343use util:: events:: MessageSendEventsProvider ;
4444use 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 } ;
4646
4747use ln:: { PaymentPreimage , PaymentHash , PaymentSecret } ;
4848
@@ -1375,14 +1375,14 @@ impl Writeable for OnionMessage {
13751375impl Writeable for FinalOnionHopData {
13761376 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
13771377 self . payment_secret . 0 . write ( w) ?;
1378- HighZeroBytesDroppedVarInt ( self . total_msat ) . write ( w)
1378+ HighZeroBytesDroppedBigSize ( self . total_msat ) . write ( w)
13791379 }
13801380}
13811381
13821382impl Readable for FinalOnionHopData {
13831383 fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
13841384 let secret: [ u8 ; 32 ] = Readable :: read ( r) ?;
1385- let amt: HighZeroBytesDroppedVarInt < u64 > = Readable :: read ( r) ?;
1385+ let amt: HighZeroBytesDroppedBigSize < u64 > = Readable :: read ( r) ?;
13861386 Ok ( Self { payment_secret : PaymentSecret ( secret) , total_msat : amt. 0 } )
13871387 }
13881388}
@@ -1399,15 +1399,15 @@ impl Writeable for OnionHopData {
13991399 } ,
14001400 OnionHopDataFormat :: NonFinalNode { short_channel_id } => {
14011401 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) ,
14041404 ( 6 , short_channel_id, required)
14051405 } ) ;
14061406 } ,
14071407 OnionHopDataFormat :: FinalNode { ref payment_data, ref keysend_preimage } => {
14081408 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) ,
14111411 ( 8 , payment_data, option) ,
14121412 ( 5482373484 , keysend_preimage, option)
14131413 } ) ;
@@ -1417,36 +1417,23 @@ impl Writeable for OnionHopData {
14171417 }
14181418}
14191419
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-
14281420impl 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) ?;
14361423 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 ) ;
14411428 let mut short_id: Option < u64 > = None ;
14421429 let mut payment_data: Option < FinalOnionHopData > = None ;
14431430 let mut keysend_preimage: Option < PaymentPreimage > = None ;
1444- // The TLV type is chosen to be compatible with lnd and c-lightning.
14451431 decode_tlv_stream ! ( & mut rd, {
14461432 ( 2 , amt, required) ,
14471433 ( 4 , cltv_value, required) ,
14481434 ( 6 , short_id, option) ,
14491435 ( 8 , payment_data, option) ,
1436+ // See https://github.com/lightning/blips/blob/master/blip-0003.md
14501437 ( 5482373484 , keysend_preimage, option)
14511438 } ) ;
14521439 rd. eat_remaining ( ) . map_err ( |_| DecodeError :: ShortRead ) ?;
@@ -1488,6 +1475,14 @@ impl Readable for OnionHopData {
14881475 }
14891476}
14901477
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+
14911486impl Writeable for Ping {
14921487 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
14931488 self . ponglen . write ( w) ?;
@@ -1913,7 +1908,7 @@ mod tests {
19131908 use bitcoin:: secp256k1:: { PublicKey , SecretKey } ;
19141909 use bitcoin:: secp256k1:: { Secp256k1 , Message } ;
19151910
1916- use io:: Cursor ;
1911+ use io:: { self , Cursor } ;
19171912 use prelude:: * ;
19181913 use core:: convert:: TryFrom ;
19191914
@@ -2824,4 +2819,40 @@ mod tests {
28242819 assert_eq ! ( gossip_timestamp_filter. first_timestamp, 1590000000 ) ;
28252820 assert_eq ! ( gossip_timestamp_filter. timestamp_range, 0xffff_ffff ) ;
28262821 }
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+ }
28272858}
0 commit comments