Проблемы с использованием `u8` в субстрате и чернилах
Я пытаюсь добавить простой u8
к моему модулю времени выполнения субстрата:
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
в субстрате смарт-контракт с использованием чернил!:
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`
Почему, и что я могу сделать, чтобы решить проблему?
1 ответ
Сегодня parity_codec
не поддерживает кодирование u8
чтобы избежать столкновения типов, так как Vec<u8>
это особый случай из Vec<T>
,
См.: https://github.com/paritytech/parity-codec/issues/47
gavofyork:
Потому что иначе было бы сделано две кодировки:
Vec<u8>
а такжеVec<T: Codec>
столкновение.
Возможно, это может быть исправлено в будущем с помощью дополнительных функций Rust, но сейчас вам нужно будет хранить свои отдельные байты как [u8; 1]
и работать с этим типом.
Модуль времени выполнения субстрата
Одно хакерское решение для Substrate Runtime Module выглядит примерно так:
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 обманет это значение просто как u8
для любых полей ввода / вывода, которые он генерирует. Если вы попытаетесь использовать пользовательский тип, такой как type Byte = [u8; 1]
пользовательский интерфейс попросит вас импортировать определение этого пользовательского типа. Если вы попытаетесь использовать [u8; 1]
непосредственно пользовательский интерфейс Polkadot не будет знать, как визуализировать ввод / вывод этого значения.
Кроме того, на момент написания этого поста 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]
непосредственно во всем вашем коде. Опять же, вам нужно обращаться с ним как с массивом для методов получения и установки. Но при создании ABI вам нужно будет вручную изменить экземпляры [u8; 1]
в u8
обманывать пользовательский интерфейс, чтобы делать то, что вы хотите.