0

I am creating a parachain with a custom pallet, where i have this set up in storage:

    pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
    pub type NeuronMetadataOf<T> = NeuronMetadata<AccountIdOf<T>>;
    pub type BalanceOf<T> = <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

    #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)]
    pub struct NeuronMetadata<AccountId> {
      
              /// ---- The associated hotkey account.
        /// Registration and changing weights can be made by this
        /// account.
        pub key1: AccountId,

        pub key2: AccountId,
     }

    #[pallet::storage]
    #[pallet::getter(fn uid)]
    pub(super) type Neurons<T:Config> = StorageMap<
        _, 
        Identity, 
        u32, 
        NeuronMetadataOf<T>, 
        ValueQuery
    >;

        #[cfg(feature = "std")]
        impl<T> Default for NeuronMetadata<T> {
        fn default() -> Self {
            Self { 
                key1: Default::default(),
                key2: Default::default(),
                }
        }

My understanding is AccountId is not designed to be bound to Default. A "default" AccountId doesn't make any sense to have and it helped mask a previous issue and so it was removed in a recent release. (This is from: Why is there no `Default` implementation for `T::AccountId`?). However now that I've defined a Default implementation for it, I keep getting an error that says

error[E0277]: the trait bound `T: std::default::Default` is not satisfied
   --> pallets/subtensor/src/lib.rs:245:13
    |
245 |                 key1: Default::default(),
    |                         ^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `T`
    |
note: required by `std::default::Default::default`

So my question is, I don't understand how to manually define Default for an AccountId struct like NeuronMetaData<AccountId>. Any examples would be super helpful here.

1
  • The following code is misleading: ``` #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo)] pub struct NeuronMetadata<AccountId> { /// ---- The associated hotkey account. /// Registration and changing weights can be made by this /// account. pub key1: AccountId, pub key2: AccountId, } ``` What you really declare here is template type name is AccountId, it has no relationship with <T as frame_system::Config>::AccountId. Commented Apr 18, 2022 at 8:08

2 Answers 2

3

The error message actually gives a clue. It says that you are trying to call Default::default() → Self and assign it to key1.

You cannot call a function of a trait, you can only call a function on the implementing type. Rustc figures out that this type is T, the type of key1.

impl<T> Default for NeuronMetadata<T> {
  fn default() -> Self {
    Self { 
      key1: Default::default(),
      key2: Default::default(),
    }
  }
}

Look at the impl<T> part. It just declares T without any bounds. That is to say, that T can be any type whatsoever, including a type that does not implement Default. That's what rustc is trying to tell you.

It's not obvious to me what you are trying to achieve in the end, but since AccountId doesn't have a proper Default implementation as was mentioned in the linked answer, you will have to come up with a way that avoids using that.

For example, a common way to introduce "defaultness" is to use Option<T> instead of bare T. Option<T> has a None variant. This scheme is similar to having a null-reference in other languages such as Java/JS, etc.

3
  • I have a struct that contains two keys that are of type AccountId. I'm just trying to set up a Default implementation for it, but because I have AccountId type values in it (key1, key2) then it is complaining to me about not having a proper Default implementation. Can you please give me a basic example of using Option<T>? I'm still learning my way around Rust and Substrate, would really appreciate it.
    – shibshib
    Commented Apr 17, 2022 at 18:48
  • By that, I meant changing the type of key1 and key2 from AccountId to Option<AccountId>. If you do so, then you won't need an explicit impl Default because you'd be able to put derive(Default) on NeuronMetadata.
    – pepyakin
    Commented Apr 18, 2022 at 15:08
  • Thanks so much @pepyakin! You've been super helpful. I decided to instead remove AccountId from the struct and use it separately, as it appears that setting up a Default for AccountId is a bit counterintuitive as it was removed for security reasons. Going to mark this as solved.
    – shibshib
    Commented Apr 18, 2022 at 17:34
0

For anyone who stumbles onto this same issue, I resolved it by moving the AccountId type variables (key1, key2) out of the struct, and working with them from the outside. This way it's more secure and you don't need to deal with setting up defaults for it, which was removed for security reasons anyways.

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.