在底材和墨水中使用u8的问题

时间:2019-05-09 09:03:48

标签: blockchain parity-io substrate ink

我正在尝试将一个简单的u8添加到我的Substrate Runtime Module中:

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

但是,我收到一个编译器错误,指出它没有实现奇偶校验编解码器的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 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`

那是为什么,我该怎么解决这个问题?

1 个答案:

答案 0 :(得分:0)

由于parity_codecu8的特殊情况,今天的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来完成您想要的事情。