Merge pull request #2969 from TheBlueMatt/2024-03-fix-upgradable-enum
[rust-lightning] / lightning / src / util / ser_macros.rs
index d1e152feb09b11ecf96b701387f63c86234f9fb7..df030d0b01eb4452ccf8e7b391e8c738bb9af453 100644 (file)
@@ -400,6 +400,17 @@ macro_rules! _decode_tlv {
        // but we can no longer understand it.
        ($outer_reader: expr, $reader: expr, $field: ident, upgradable_option) => {{
                $field = $crate::util::ser::MaybeReadable::read(&mut $reader)?;
+               if $field.is_none() {
+                       #[cfg(not(debug_assertions))] {
+                               // In general, MaybeReadable implementations are required to consume all the bytes
+                               // of the object even if they don't understand it, but due to a bug in the
+                               // serialization format for `impl_writeable_tlv_based_enum_upgradable` we sometimes
+                               // don't know how many bytes that is. In such cases, we'd like to spuriously allow
+                               // TLV length mismatches, which we do here by calling `eat_remaining` so that the
+                               // `s.bytes_remain()` check in `_decode_tlv_stream_range` doesn't fail.
+                               $reader.eat_remaining()?;
+                       }
+               }
        }};
        ($outer_reader: expr, $reader: expr, $field: ident, (option: $trait: ident $(, $read_arg: expr)?)) => {{
                $field = Some($trait::read(&mut $reader $(, $read_arg)*)?);
@@ -1042,7 +1053,7 @@ macro_rules! impl_writeable_tlv_based_enum {
                                        $($variant_id => {
                                                // Because read_tlv_fields creates a labeled loop, we cannot call it twice
                                                // in the same function body. Instead, we define a closure and call it.
-                                               let f = || {
+                                               let mut f = || {
                                                        $crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
                                                                $(($type, $field, $fieldty)),*
                                                        });
@@ -1100,7 +1111,7 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable {
                                        $($variant_id => {
                                                // Because read_tlv_fields creates a labeled loop, we cannot call it twice
                                                // in the same function body. Instead, we define a closure and call it.
-                                               let f = || {
+                                               let mut f = || {
                                                        $crate::_init_and_read_len_prefixed_tlv_fields!(reader, {
                                                                $(($type, $field, $fieldty)),*
                                                        });
@@ -1132,8 +1143,10 @@ macro_rules! impl_writeable_tlv_based_enum_upgradable {
 
 #[cfg(test)]
 mod tests {
-       use crate::io::{self, Cursor};
+       #[allow(unused_imports)]
        use crate::prelude::*;
+
+       use crate::io::{self, Cursor};
        use crate::ln::msgs::DecodeError;
        use crate::util::ser::{Writeable, HighZeroBytesDroppedBigSize, VecWriter};
        use bitcoin::hashes::hex::FromHex;