@@ -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 , HighZeroBytesDroppedVarInt , Hostname } ;
4646
4747use ln:: { PaymentPreimage , PaymentHash , PaymentSecret } ;
4848
@@ -1418,16 +1418,11 @@ impl Writeable for OnionHopData {
14181418}
14191419
14201420impl Readable for OnionHopData {
1421- fn read < R : Read > ( mut r : & mut R ) -> Result < Self , DecodeError > {
1422- use bitcoin:: consensus:: encode:: { Decodable , Error , VarInt } ;
1423- let v: VarInt = Decodable :: consensus_decode ( & mut r)
1424- . map_err ( |e| match e {
1425- Error :: Io ( ioe) => DecodeError :: from ( ioe) ,
1426- _ => DecodeError :: InvalidValue
1427- } ) ?;
1421+ fn read < R : Read > ( r : & mut R ) -> Result < Self , DecodeError > {
1422+ let b: BigSize = Readable :: read ( r) ?;
14281423 const LEGACY_ONION_HOP_FLAG : u64 = 0 ;
1429- let ( format, amt, cltv_value) = if v . 0 != LEGACY_ONION_HOP_FLAG {
1430- let mut rd = FixedLengthReader :: new ( r, v . 0 ) ;
1424+ let ( format, amt, cltv_value) = if b . 0 != LEGACY_ONION_HOP_FLAG {
1425+ let mut rd = FixedLengthReader :: new ( r, b . 0 ) ;
14311426 let mut amt = HighZeroBytesDroppedVarInt ( 0u64 ) ;
14321427 let mut cltv_value = HighZeroBytesDroppedVarInt ( 0u32 ) ;
14331428 let mut short_id: Option < u64 > = None ;
@@ -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:: HighZeroBytesDroppedVarInt ;
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 , HighZeroBytesDroppedVarInt ( payload. amt_to_forward) , required) ,
2852+ ( 4 , HighZeroBytesDroppedVarInt ( payload. outgoing_cltv_value) , required) ,
2853+ ( 6 , short_channel_id, required)
2854+ } ) ;
2855+ }
2856+ Ok ( encoded_payload)
2857+ }
28272858}
0 commit comments