我正在尝试将一个简单的u8
添加到我的Substrate Runtime Module中:
decl_storage! {
trait Store for Module<T: Trait> as TemplateModule {
MyByte: u8;
}
}
但是,我收到一个编译器错误,指出它没有实现奇偶校验编解码器的Encode
或Decode
:
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 Smart Contract中时,也会发生类似的问题:
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`
那是为什么,我该怎么解决这个问题?
答案 0 :(得分:0)
由于parity_codec
是u8
的特殊情况,今天的Vec<u8>
不支持Vec<T>
的编码,因为避免了类型冲突。
请参阅:https://github.com/paritytech/parity-codec/issues/47
gavofyork:
因为否则会产生两种编码:
Vec<u8>
和Vec<T: Codec>
冲突。
将来有可能通过附加的Rust功能解决此问题,但是现在,您需要将单个字节存储为[u8; 1]
并使用该类型。
一种针对底物运行模块的骇人解决方案看起来像这样:
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<u8>
或u16
,并在运行时进行适当的检查,以将其视为单个u8
,但是,用户界面不会更好。
我还没有找到ink!
的理想解决方案,但是您应该可以直接在所有代码中使用[u8; 1]
。同样,您将需要将其视为用于getter和setter的数组。但是,在生成ABI时,您需要手动将[u8; 1]
的实例更改为u8
,以欺骗UI来完成您想要的事情。