2

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

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

但是,我得到一个编译器错误,它没有实现 Parity CodecEncodeDecode

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使用 ink 将 a 存储在 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`

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

4

1 回答 1

1

今天,由于避免类型冲突,parity_codec不支持编码,因为是.u8Vec<u8>Vec<T>

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

加沃约克:

因为否则它会使两种编码:Vec<u8>Vec<T: Codec>冲突。

将来可能会通过其他 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 type U8 = [u8; 1];。选择我们的新类型名称很重要,因为它会欺骗 Polkadot UI 将这个值简单地视为u8它生成的任何输入/输出字段的 a。如果您尝试使用自定义类型,如type Byte = [u8; 1],UI 将要求您导入该自定义类型的定义。如果你尝试[u8; 1]直接使用,Polkadot UI 将不知道如何渲染该值的输入/输出。

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

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

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

其他解决方案可能涉及使用本机支持的其他类型,例如Vec<u8>or u16,并在您的运行时进行适当的检查,将其视为单个u8,但 UI 不会更好地知道。


Substrate 智能合约

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

于 2019-05-09T13:22:38.870 回答