3

When developing Ink! smart contracts I found that SpreadLayout and SpreadAllocate cannot be derived for simple structs or enums that are members variables of the contract and I have to implement the traits manually.

The compilation error occurs only when building the contract ( cargo +nightly contract build) but not when running test (cargo +nightly test)

for instance for the simple struct:

#[cfg_attr(feature = "std", derive(Debug, scale_info::TypeInfo, StorageLayout, SpreadAllocate))]
pub struct Data {
    pub a: u64,
    pub b: u64,
}

fails with:

error[E0277]: the trait bound `Data: SpreadAllocate` is not satisfied
  --> /../lib.rs:23:14
   |
23 |     #[derive(SpreadAllocate)]
   |              ^^^^^^^^^^^^^^ the trait `SpreadAllocate` is not implemented for `Data`
   |
   = help: the following other types implement trait `SpreadAllocate`:
             ()
             (A, B)
             (A, B, C)
             (A, B, C, D)
             (A, B, C, D, E)
             (A, B, C, D, E, F)
             (A, B, C, D, E, F, G)
             (A, B, C, D, E, F, G, H)
           and 47 others
   = note: this error originates in the derive macro `SpreadAllocate` (in Nightly builds, run with -Z macro-backtrace for more info)

adding SpreadLayout and SpreadAllocate to the derive macro fails. Same for the enum

#[cfg_attr(feature = "std", derive(Debug, Clone, Copy, Encode, Decode, scale_info::TypeInfo, StorageLayout, SpreadLayout))]
pub enum Type {
    Unknown,
    A,
    B,
}

what am I missing?

1 Answer 1

7

SpreadAllocate can't be derived for the enums(issue), so you should implement it manually.

You are deriving SpreadLayout wrong=) #[cfg_attr(feature = "std", derive(...)] means - derive it only if the std feature is enabled.

But the contract build has two phases:

  1. Build the contract's WASM in no_std mode.
  2. Build fo the contract's metadata in std mode.

SpreadLayout and SpreadAllocate should be derived for both phases. StorageLayout only for std because it is required to generate metadata.

The right deriving:

#[derive(SpreadLayout, SpreadAllocate)]
#[cfg_attr(feature = "std", derive(Debug, scale_info::TypeInfo, StorageLayout))]
pub struct Data {
    pub a: u64,
    pub b: u64,
}

#[derive(SpreadLayout)]
#[cfg_attr(feature = "std", derive(Debug, Clone, Copy, Encode, Decode, scale_info::TypeInfo, StorageLayout))]
pub enum Type {
    Unknown,
    A,
    B,
}

impl SpreadAllocate for Type {
...
}
3
  • wow this works like a charm! do you have any reference or link where this is explained as you did?
    – mastro
    Commented May 16, 2022 at 3:22
  • 1
    No=) Soon all those traits should be removed in github.com/paritytech/ink/pull/1217. After OpenBrush or ink! will describe a new storage in details and examples. Commented May 17, 2022 at 17:32
  • For people who are interested in knowing what could go inside impl SpreadAllocate for Type, here is an example: ``` impl SpreadAllocate for Type { fn allocate_spread(_: &mut KeyPtr) -> Self { Type::Unknown } } ```
    – Alex Sed
    Commented Dec 6, 2022 at 23:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.