【问题标题】:Problems using `u8` in Substrate and ink在 Substrate 和 ink 中使用“u8”的问题
【发布时间】:2019-05-09 09:03:48
【问题描述】:

我正在尝试向我的 Substrate 运行时模块添加一个简单的 u8

decl_storage! {
    trait Store for Module<T: Trait> as TemplateModule {
        MyByte: u8;
    }
}

但是,我收到一个编译器错误,它没有实现 Parity Codec 的 EncodeDecode

error[E0277]: the trait bound `u8: _IMPL_DECODE_FOR_Event::_parity_codec::Encode` is not satisfied
  --> /Users/shawntabrizi/Documents/GitHub/substrate-package/substrate-node-template/runtime/src/template.rs:23:1
   |
23 | / decl_storage! {
24 | |     trait Store for Module<T: Trait> as TemplateModule {
25 | |         MyByte: u8;
26 | |     }
27 | | }
   | |_^ the trait `_IMPL_DECODE_FOR_Event::_parity_codec::Encode` is not implemented for `u8`

当我尝试使用墨水将u8 存储在 Substrate 智能合约中时,会出现类似的问题!:

contract! {
    struct MyContract {
        value: storage::Value<u8>,
    }
    ...
}

错误:

error[E0277]: the trait bound `u8: parity_codec::codec::Encode` is not satisfied
  --> src/lib.rs:26:1
   |
26 | / contract! {
27 | |     struct MyContract {
28 | |         value: storage::Value<u8>,
29 | |     }
...  |
49 | |     }
50 | | }
   | |_^ the trait `parity_codec::codec::Encode` is not implemented for `u8`

为什么会这样,我可以做些什么来解决这个问题?

【问题讨论】:

    标签: blockchain substrate parity-io rust-ink


    【解决方案1】:

    今天,parity_codec 不支持 u8 的编码以避免类型冲突,因为 Vec&lt;u8&gt;Vec&lt;T&gt; 的一个特例。

    见:https://github.com/paritytech/parity-codec/issues/47

    加沃约克:

    因为否则会导致两种编码:Vec&lt;u8&gt;Vec&lt;T: Codec&gt; 发生冲突。

    未来可能会通过其他 Rust 功能解决此问题,但目前,您需要将单个字节存储为 [u8; 1] 并使用该类型。


    基板运行时模块

    Substrate 运行时模块的一个 hacky 解决方案如下所示:

    use support::{decl_module, decl_storage, decl_event, StorageValue, dispatch::Result};
    use system::ensure_signed;
    
    pub trait Trait: system::Trait {
        type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
    }
    
    type U8 = [u8; 1];
    
    decl_storage! {
        trait Store for Module<T: Trait> as TemplateModule {
            MyByte get(my_byte): U8;
        }
    }
    
    decl_module! {
        pub struct Module<T: Trait> for enum Call where origin: T::Origin {
    
            fn deposit_event<T>() = default;
    
            pub fn set_my_byte(origin, input: U8) -> Result {
                let who = ensure_signed(origin)?;
    
                <MyByte<T>>::put(input);
    
                Self::deposit_event(RawEvent::MyByteStored(input, who));
                Ok(())
            }
    
            pub fn add_to_byte(origin, input: U8) -> Result {
                let who = ensure_signed(origin)?;
    
                let my_byte = Self::my_byte()[0];
                let my_new_byte = my_byte.checked_add(input[0]).ok_or("Overflow")?;
    
                <MyByte<T>>::put([my_new_byte]);
                Self::deposit_event(RawEvent::MyByteStored([my_new_byte], who));
                Ok(())
            }
        }
    }
    
    decl_event!(
        pub enum Event<T> where AccountId = <T as system::Trait>::AccountId {
            MyByteStored(U8, AccountId),
        }
    );
    

    我们在其中分配了一个新类型type U8 = [u8; 1];。选择我们的新类型名称很重要,因为它会欺骗 Polkadot UI 将这个值简单地视为它生成的任何输入/输出字段的 u8。如果您尝试使用像 type Byte = [u8; 1] 这样的自定义类型,UI 将要求您导入该自定义类型的定义。如果你尝试直接使用[u8; 1],Polkadot UI 将不知道如何渲染该值的输入/输出。

    此外,在撰写本文时,decl_event! 宏由于模式匹配而直接存入 [u8; 1] 时存在问题。

    请注意,在使用此类型时,您需要将其视为数组。 add_to_byte() 显示了一个例子。所以最终,您需要提取数组的第一项来提取字节,并且您需要将字节包装在数组中以设置U8

    let my_byte = Self::my_byte()[0];
    ...
    <MyByte<T>>::put([my_new_byte]);
    

    其他解决方案可能涉及使用本机支持的其他类型,例如 Vec&lt;u8&gt;u16,并在运行时进行适当的检查,以确保将其视为单个 u8,但 UI 不会知道得更好。


    Substrate 智能合约

    我还没有为ink! 找到一个很好的解决方案,但是你应该可以在你的所有代码中直接使用[u8; 1]。同样,您需要将其视为 getter 和 setter 的数组。但是在生成 ABI 时,您需要手动将 [u8; 1] 的实例更改为 u8 以欺骗 UI 执行您想要的操作。

    【讨论】:

      猜你喜欢
      • 2021-08-08
      • 1970-01-01
      • 2022-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多