parity-common icon indicating copy to clipboard operation
parity-common copied to clipboard

Issues wrapping ethereum types and deriving scale-codec methods

Open drewstone opened this issue 1 year ago • 2 comments

I'm trying to implement wrapper types for ethereum_types types in order to provide other traits necessary for making my code compatible with https://github.com/sigp/lighthouse dependencies and Substrate. The following snippet demonstrates my intention.

macro_rules! uint_declare_wrapper_and_serde {
    ($name: ident, $len: expr) => {
        #[derive(
            Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Debug, Add, Sub, Mul, Div, Rem,
            AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, Display, From, Into,
            Encode, EncodeLike, Decode, MaxEncodedLen, TypeInfo,
        )]
        // #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
        pub struct $name(pub ethereum_types::$name);

        impl Encodable for $name {
            fn rlp_append(&self, s: &mut RlpStream) {
                <ethereum_types::$name>::rlp_append(&self.0, s);
            }
        }

        impl Decodable for $name {
            fn decode(rlp: &Rlp) -> Result<Self, RlpDecoderError> {
                Ok($name(<ethereum_types::$name>::rlp_derive(rlp)?))
            }
        }
    };
}

uint_declare_wrapper_and_serde!(U64, 1);
uint_declare_wrapper_and_serde!(U128, 2);
uint_declare_wrapper_and_serde!(U256, 4);

Unfortunately, I keep fighting with the compiler who doesn't think that these types can implement Encode/Decode even though I am importing the package with those features. My TOML is below:

ethereum-types = { version = "0.12.1", features = ["codec", "rlp", "num-traits"], default-features = false }

Errors

error[E0599]: no function or associated item named `max_encoded_len` found for struct `ethereum_types::U64` in the current scope
  --> src/lib.rs:62:30
   |
62 |         pub struct $name(pub ethereum_types::$name);
   |                              ^^^^^^^^^^^^^^ function or associated item not found in `ethereum_types::U64`
...
78 | uint_declare_wrapper_and_serde!(U64, 1);
   | --------------------------------------- in this macro invocation
   |
   = help: items from traits can only be used if the trait is in scope
   = note: this error originates in the macro `uint_declare_wrapper_and_serde` (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
4  | use parity_scale_codec::max_encoded_len::MaxEncodedLen;
   |

drewstone avatar Sep 18 '22 14:09 drewstone

A similar thing happens with a trait for HXX types like H64 and H256, sometimes referencing traits not being present even though they are in the lib.rs.

error[E0599]: no function or associated item named `max_encoded_len` found for struct `ethereum_types::U64` in the current scope
  --> src/lib.rs:62:30
   |
62 |         pub struct $name(pub ethereum_types::$name);
   |                              ^^^^^^^^^^^^^^ function or associated item not found in `ethereum_types::U64`
...
78 | uint_declare_wrapper_and_serde!(U64, 1);
   | --------------------------------------- in this macro invocation
   |
   = help: items from traits can only be used if the trait is in scope
   = note: this error originates in the macro `uint_declare_wrapper_and_serde` (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
4  | use parity_scale_codec::max_encoded_len::MaxEncodedLen;
   |

If I try implementing the trait myself:

impl Encode for $name {
    fn encode(&self) -> Vec<u8> {
        self.0.encode()
    }
}

I get the following error as well:

error[E0599]: the method `encode` exists for struct `ethereum_types::H64`, but its trait bounds were not satisfied
   --> src/macros.rs:199:24
    |
199 |                   self.0.encode()
    |                          ^^^^^^ method cannot be called on `ethereum_types::H64` due to unsatisfied trait bounds
    |
   ::: src/lib.rs:27:1
    |
27  |   arr_ethereum_types_wrapper_impl!(H64, 8);
    |   ---------------------------------------- in this macro invocation
    |
   ::: /Users/drew/.cargo/registry/src/github.com-1ecc6299db9ec823/ethereum-types-0.12.1/src/hash.rs:33:1
    |
33  | / construct_fixed_hash! {
34  | |     #[cfg_attr(feature = "codec", derive(scale_info::TypeInfo))]
35  | |     pub struct H64(8);
36  | | }
    | | -
    | | |
    | | doesn't satisfy `<ethereum_types::H64 as Deref>::Target = _`
    | |_doesn't satisfy `ethereum_types::H64: WrapperTypeEncode`
    |   doesn't satisfy `ethereum_types::H64: parity_scale_codec::Encode`
    |
    = note: the following trait bounds were not satisfied:
            `<ethereum_types::H64 as Deref>::Target = _`
            which is required by `ethereum_types::H64: parity_scale_codec::Encode`
            `ethereum_types::H64: WrapperTypeEncode`
            which is required by `ethereum_types::H64: parity_scale_codec::Encode`
    = help: items from traits can only be used if the trait is in scope
    = note: this error originates in the macro `arr_ethereum_types_wrapper_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   --> |src/lib.rs:4:1
    |
4   | use parity_scale_codec::codec::Encode;
    |

drewstone avatar Sep 18 '22 14:09 drewstone

From what I can see, this is a general rust question. The compiler is your friend and it tells you what's wrong:

help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   --> |src/lib.rs:4:1
    |
4   | use parity_scale_codec::codec::Encode;

In your implementation of the macro, you assume that Encode and Decode are in scope. Generally, that's not a good idea as it leads to the subpar developer experience, as you are seeing directly. Unless you're only planning to use this macro only where it's defined, then you'll have to import the required traits in the scope.

Take a look at how codec is implemented in https://github.com/paritytech/parity-common/blob/master/primitive-types/impls/codec/src/lib.rs. Note the $crate::codec::Encode and

#[doc(hidden)]
pub use parity_scale_codec as codec;

ordian avatar Sep 18 '22 20:09 ordian