fix(codec): fix last field compilation check (#3543)

This commit is contained in:
joshieDo
2023-07-03 12:29:17 +01:00
committed by GitHub
parent f2f3425f1c
commit 73eeca0e29
3 changed files with 27 additions and 11 deletions

View File

@ -58,7 +58,12 @@ fn generate_from_compact(fields: &FieldList, ident: &Ident, is_zstd: bool) -> To
// it's hard to figure out with derive_macro which types have bytes::Bytes fields.
//
// This removes the requirement of the field to be placed last in the struct.
known_types.append(&mut vec!["TransactionKind", "AccessList", "Signature"]);
known_types.append(&mut vec![
"TransactionKind",
"AccessList",
"Signature",
"CheckpointBlockRange",
]);
// let mut handle = FieldListHandler::new(fields);
let is_enum = fields.iter().any(|field| matches!(field, FieldTypes::EnumVariant(_)));

View File

@ -116,17 +116,26 @@ impl<'a> StructHandler<'a> {
format_ident!("specialized_from_compact")
};
// ! Be careful before changing the following assert ! Especially if the type does not
// implement proptest tests.
//
// The limitation of the last placed field applies to fields with potentially large sizes,
// like the `Transaction` field. These fields may have inner "Bytes" fields, sometimes even
// nested further, making it impossible to check with `proc_macro`. The goal is to place
// such fields as the last ones, so we don't need to store their length separately. Instead,
// we can simply read them until the end of the buffer.
//
// However, certain types don't require this approach because they don't contain inner
// "Bytes" fields. For these types, we can add them to a "known_types" list so it doesn't
// trigger this error. These types can handle their own deserialization without
// relying on the length provided by the higher-level deserializer. For example, a
// type "T" with two "u64" fields doesn't need the length parameter from
// "T::from_compact(buf, len)" since the length of "u64" is known internally (bitpacked).
assert!(
known_types.contains(&ftype.as_str()) ||
is_flag_type(ftype) ||
self.fields_iterator.peek().map_or(true, |ftypes| {
if let FieldTypes::StructField((_, ftype, _, _)) = ftypes {
!known_types.contains(&ftype.as_str())
} else {
false
}
}),
"`{ftype}` field should be placed as the last one since it's not known.
self.fields_iterator.peek().is_none(),
"`{ftype}` field should be placed as the last one since it's not known.
If it's an alias type (which are not supported by proc_macro), be sure to add it to either `known_types` or `get_bit_size` lists in the derive crate."
);

View File

@ -23,11 +23,13 @@ pub fn derive_zstd(input: TokenStream) -> TokenStream {
compact::derive(input, is_zstd)
}
/// Implements the main codec. If the codec supports it, it will call `derive_arbitrary(..)`.
/// This code implements the main codec. If the codec supports it, it will also provide the [derive_arbitrary()] function, which automatically implements arbitrary traits and roundtrip fuzz tests.
///
/// If you prefer to manually implement the arbitrary traits, you can still use the [add_arbitrary_tests()] function to add arbitrary fuzz tests.
///
/// Example usage:
/// * `#[main_codec(rlp)]`: will implement `derive_arbitrary(rlp)` or `derive_arbitrary(compact, rlp)`, if `compact` is the `main_codec`.
/// * `#[main_codec(no_arbitrary)]`: will skip `derive_arbitrary`
/// * `#[main_codec(no_arbitrary)]`: will skip `derive_arbitrary` (both trait implementations and tests)
#[proc_macro_attribute]
#[rustfmt::skip]
#[allow(unreachable_code)]