SETP5,Substrate Runtime 開(kāi)發(fā)簡(jiǎn)述

簡(jiǎn)介

https://substrate.dev/recipes/runtime-api.html
https://crates.parity.io/sp_api/macro.decl_runtime_apis.html
https://crates.parity.io/sp_api/macro.impl_runtime_apis.html

Substrate runtime 宏

Runtime 模塊開(kāi)發(fā)常用的宏

  • frame_support::pallet 定義功能模塊
  • pallet::config 定義配置接口
  • pallet::storage 存存儲(chǔ)單元
  • pallet::event 事件
  • pallet::error 錯(cuò)誤信息
  • pallet::call 包含可調(diào)用函數(shù)
  • pallet::hooks 區(qū)塊不同時(shí)期的執(zhí)行邏輯油猫。
  • construct_runtime 添加到模塊Runtime

常見(jiàn)的數(shù)據(jù)類(lèi)型

  • StorageValue 單值類(lèi)型
  • StorageMap 映射類(lèi)型
  • StorageDoubleMap 雙鍵映射
  • 舉例:
#[pallet::storage]
#[pallet::getter(fn something)]
pub type Something<T> = StorageValue<_, u32>;

Call宏舉例

  • Call 宏用來(lái)定義一個(gè)可調(diào)用的函數(shù)
#[pallet::call]
impl<T:Config> Pallet<T> {
    #[pallet::weight(10_000)]
    pub fn do_something(origin: OriginFor<T>, something: u32) -> DispathResultWithPostInfo {
        let who = ensure_signed(origin)?;
        
        // Update storage.
        <Something<T>>::pub(something);
        
        // Emit an event.
        Self::deposit_event(Event::SomethingStored(something, who));

        Ok(().into())
    }
}

event 宏

  • 區(qū)塊鏈?zhǔn)且粋€(gè)異步系統(tǒng),runtime 通過(guò)觸發(fā)事件通知交易執(zhí)行結(jié)果朵夏。
  • 舉例:
#[pallet::event]
#[pallet::metadata(T::AccountId="AccountId")]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
    SomethingStored(u32, T::AccountId),
}

// -- snippet --
Self::deposit_event(Event::SomethingStored(something, who));

error 宏

  • 不能給他們添加數(shù)據(jù)。
  • 通過(guò)emtadata 暴露給客戶端。
  • 錯(cuò)誤發(fā)生時(shí)觸發(fā) system.ExtrinsicFailed 事件,包含了對(duì)應(yīng)錯(cuò)誤的索引信息白修。
  • 當(dāng)可調(diào)用函數(shù)執(zhí)行過(guò)程中發(fā)生錯(cuò)誤是,通過(guò)error信息通知客戶端重斑。
  • 舉例
#[pallet::error]
pub enum Error <T> {
    /// Error names should be descriptive.
    NoneValue,
    /// Error should have helpful documentation associated with them.
    StorageOverflow,
}

hooks 宏

  • Runtime 模塊里存在保留函數(shù)兵睛,用于執(zhí)行特定的邏輯:

on_initialize,在每個(gè)區(qū)塊的開(kāi)頭執(zhí)行绸狐。
on_finalize卤恳,在每個(gè)區(qū)塊結(jié)束時(shí)執(zhí)行累盗。
offchain_worker 開(kāi)頭且是鏈外執(zhí)行寒矿,不占用鏈上的資源。
on_runtime_upgrade 當(dāng)有runtime 升級(jí)時(shí)才會(huì)執(zhí)行若债,用來(lái)遷移數(shù)據(jù)符相。

construct_runtime 加載模塊

舉例:

impl pallet_template::Config for Runtime {
    type Event = Event;
}
construct_runtime! {
    pub enum Runtime where 
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic {
            // -- snippet --
            TemplateModule: pallet_template:: { Module, Call, Storage, Event<T> },
        }
}

區(qū)塊鏈存儲(chǔ)

區(qū)塊鏈存儲(chǔ)的特點(diǎn)

  • 開(kāi)源可查,對(duì)等節(jié)點(diǎn)蠢琳,引入延遲和隨機(jī)來(lái)達(dá)到共識(shí)啊终。
  • 鏈?zhǔn)健⒃隽康卮鎯?chǔ)數(shù)據(jù)傲须。
  • 區(qū)塊鏈應(yīng)用的節(jié)點(diǎn)依賴于高效的鍵值對(duì)數(shù)據(jù)庫(kù)蓝牲,比如LevelDBRocksDb等泰讽。

區(qū)塊鏈存儲(chǔ)的限制

  • 大文件直接存儲(chǔ)在鏈上的成本很高例衍。
  • 鏈?zhǔn)絽^(qū)塊存儲(chǔ)結(jié)構(gòu)昔期,不利于對(duì)歷史數(shù)據(jù)的索引(這也催生了區(qū)塊鏈瀏覽器這種應(yīng)用的存在)。
  • 另外一個(gè)約束是佛玄,在進(jìn)行數(shù)值運(yùn)算時(shí)不能使用浮點(diǎn)數(shù)硼一,因?yàn)楦↑c(diǎn)數(shù)在不同編譯環(huán)境下是不一致的。

開(kāi)發(fā)鏈上存儲(chǔ)單元的特點(diǎn):

  • Rust 原生數(shù)據(jù)類(lèi)型的子集梦抢,定義在核心庫(kù)和 alloc 庫(kù)中般贼。
  • 原生類(lèi)型構(gòu)成的映射類(lèi)型。
  • 滿足一定的編解碼條件奥吩。
  • 分為3大類(lèi)“單值”哼蛆、“簡(jiǎn)單映射”、“雙鍵映射”

單值類(lèi)型

  • 存儲(chǔ)某種單一類(lèi)型的值圈驼,入布爾人芽、數(shù)值、枚舉绩脆、結(jié)構(gòu)體等萤厅。
  • 數(shù)值:u8, i8, u32, i32, u64, i64, u128, i128
  • 大整數(shù):U128, U256, U512
  • 布爾:bool
  • 集合:Vec<T>, BTreeMap, BTreeSet
  • 定點(diǎn)小數(shù):Percent, Permill, Perbill, FixedU128 他們的主要目的是取代浮點(diǎn)數(shù)。
  • 定長(zhǎng)哈希:H128, H256, H512
  • 其他復(fù)雜類(lèi)型:Option<T>, tuple, enum, struct
  • 內(nèi)置自定義類(lèi)型:Moment, AccountId (連上時(shí)間戳類(lèi)型靴迫、賬戶ID類(lèi)型)

數(shù)值類(lèi)型u8的定義

  • 例子:
#[pallet::storage]
#[pallet::getter(fn my_unsigned_number)]
pub type MyUnsignedNumber<T> = StorageValue<_, u8>;

#[pallet::storage]
#[pallet::getter(fn my_signed_number)]
pub type MySignedNumber<T> = StorageValue<_, i8, ValueQuery>;

// ValueQuery 表示使用默認(rèn)查詢值惕味,如果不填寫(xiě)這個(gè)值則使用 OptionQuery 那么如果為空會(huì)返回一個(gè) Null
  • 可以使用的方法

增:MyUnsignedNumber::<T>::pub(number);
查:MyUnsignedNumber::<T>::get();
改:MyUnsignedNumber::<T>::mutate(|v|v+1);
刪:MyUnsignedNumber::<T>::kill();

返回Result 類(lèi)型:checked_add玉锌、checked_sub名挥、checked_mul、checked_div

// 舉例
my_unsigned_num.checked_add(10)?;

溢出返回飽和值:saturating_add, saturating_sub, saturating_mul

// 舉例
my_unsigned_num.saturating_add(10000);

大整數(shù) U256主守,U512類(lèi)型定義:

use sp_core::U256;

#[pallet::storage]
#[pallet::getter(fn my_big_integer)]
pub type MyBigInteger<T> = StorageValue<_, 256>;

bool 類(lèi)型定義

#[pallet::storage]
#[pallet::getter(fn my_bool)]
pub type MyBool<T> = StorageValue<_, bool>;
  • 對(duì)于 ValueQuery参淫,默認(rèn)值為 false

Vec<T> 類(lèi)型定義:

use sp_std::prelude::* ;

#[pallet::storage]
#[pallet::getter(fn my_string)]
// 這種定義方式通常用于字符串救湖,因?yàn)殒溕蠈?shí)際沒(méi)有字符串。
pub type MyString<T> = StorageValue<_, Vec<u8>>; 

Percent, Permill, Perbill 類(lèi)型定義

use sp_runtime::Permill;

#[pallet::storage]
#[pallet::getter(fn my_permill)]
pub type MyPermill<T> = StorageValue<_, Permil>; 
  • 構(gòu)造方式

Permill::from_percent(value);
Permill::from_parts(value);
Permill::from_rational(p, q);

  • 計(jì)算

permill_one.saturating_mul(permill_two);
my_permill * 20000 as u32

Moment 時(shí)間類(lèi)型定義

#[pallet::config] // 別忘了加上 pallet_timestamp::Config 約束
pub trait Config: pallet_timestamp::Config + frame_system::Config {
    // -- snippet --
}

#[pallet::storage]
#[pallet::getter(fn my_time)]
pub type MyTime<T: Config> = StorageValue<_, T::Moment>;
  • Moment 是 u64 的類(lèi)型別名
  • 獲取鏈上時(shí)間的方法:pallet_timestamp::Pallet::<T>::get()

AccountId 賬戶類(lèi)型定義

#[pallet::storage]
#[pallet::getter(fn my_account_id)]
pub type MyAccountId<T: Config> = StorageValue<_, T::AccountId>;

  • 定義在 frame_system 中涎才,通常是 Public key
  • 獲取AccountId:`let sender = ensure_signed(origin)?

struct 類(lèi)型定義

  • 這個(gè)需要注意的是鞋既,結(jié)構(gòu)類(lèi)型必須實(shí)現(xiàn) Clone ,Encode, Decode , Default 接口。
  • 可以通過(guò) dervie 屬性宏實(shí)現(xiàn)如上的接口耍铜,例如:
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)]
pub struct People {
    name: Vec<u8>, 
    age: u8,
}

#[pallet::storage]
#[pallet::getter(fn my_struct)]
pub type MyStruct<T: Config> = StorageValue<_, People>;

enum 類(lèi)型

簡(jiǎn)單映射類(lèi)型 StorageMap

  • 用來(lái)保存鍵值對(duì)陡舅,單值類(lèi)型都可以用作key或者value。
#[pallet::storage]
#[pallet::getter(fn my_map)]
pub type MyMap<T> = StorageMap<
    _,
    Blake2_128Concat,
    u8,
    Vec<u8>,
>
  • 其中第二個(gè)參數(shù)Blake2_128Concat 是key 的哈希算法伴挚。
  • Blake2_128Concat 密碼學(xué)安全
  • Twox64Concat 非密碼學(xué)安全靶衍,但是相對(duì)較快臂寝。
  • Identity 如果一個(gè)值已經(jīng)是加密值,那么它本身就很安全摊灭,這是后Identity 可以避免無(wú)必要的計(jì)算從而讓效率更高咆贬。
  • 基礎(chǔ)操作包括

插入一個(gè)元素:MyMap::<T>::insert(key, value);
通過(guò)key獲取value:MyMap::<T>::get(key);
刪除某個(gè)key對(duì)應(yīng)的元素:MyMap::remove(key);
覆蓋或者修改某個(gè)key對(duì)應(yīng)的元素 MyMap::insert(key, new_value); MyMap::mutate(key, |old_val| old_val+1);

雙鍵映射類(lèi)型 StorageDoubleMap

  • 使用兩個(gè)key來(lái)索引value,用于快速刪除key1對(duì)應(yīng)的任意記錄帚呼,也可遍歷key1對(duì)應(yīng)的所有記錄掏缎,定義:
#[pallet::storage]
#[pallet::getter(fn my_double_map)]
pub type MyDoubleMap<T: Config> = StorageDoubleMap<
    _,
    Blake2_128Concat, // key1加密算法
    T::AccountId,   //key1
    Blake2_128Concat, // key2 加密算法
    u32,   //key2
    Vec<u8>, //存貯值。
>
  • 基礎(chǔ)用法:

插入一個(gè)元素:MyDoubleMap::<T>::insert(key1,key2,value);
獲取某一元素:MyDoubleMap::<T>::get(key1, key2);
刪除某一元素:MyDoubleMap::<T>::remove(key1, key2);
刪除 key1 對(duì)應(yīng)的所有元素煤杀,MyDoubleMap::<T>::remove_prefix(key1)

存儲(chǔ)的初始化

  • 創(chuàng)世區(qū)塊的數(shù)據(jù)初始化
#[pallet::genesis_config]
pub struct GenesisConfig {
    pub value: u8,
}

#[cfg(feature = "std")]
impl Default for GenesisConifg<T> {
    fn default() -> Self {
        Self {value: Default::default() }
    }
}

#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
    fn build(&self) {
        MyValue::<T>::put(&self.value);
    }
}

開(kāi)發(fā)中需要注意的事兒

1忌怎、最小化鏈上存儲(chǔ)。(存儲(chǔ)哈希值酪夷、設(shè)置列表容量等)
2榴啸、先校對(duì)在存儲(chǔ) Verify First, Write Last
3、事務(wù)管理 Transactional macro

結(jié)束

  • 感謝閱讀
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市坦报,隨后出現(xiàn)的幾起案子库说,更是在濱河造成了極大的恐慌,老刑警劉巖片择,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潜的,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡构回,警方通過(guò)查閱死者的電腦和手機(jī)夏块,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)疏咐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纤掸,“玉大人,你說(shuō)我怎么就攤上這事浑塞〗韫颍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵酌壕,是天一觀的道長(zhǎng)掏愁。 經(jīng)常有香客問(wèn)我歇由,道長(zhǎng),這世上最難降的妖魔是什么果港? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任沦泌,我火速辦了婚禮,結(jié)果婚禮上辛掠,老公的妹妹穿的比我還像新娘谢谦。我一直安慰自己,他們只是感情好萝衩,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布回挽。 她就那樣靜靜地躺著,像睡著了一般猩谊。 火紅的嫁衣襯著肌膚如雪千劈。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天牌捷,我揣著相機(jī)與錄音墙牌,去河邊找鬼。 笑死暗甥,一個(gè)胖子當(dāng)著我的面吹牛憔古,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淋袖,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸿市,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了即碗?” 一聲冷哼從身側(cè)響起焰情,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎剥懒,沒(méi)想到半個(gè)月后内舟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡初橘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年验游,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片保檐。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耕蝉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夜只,到底是詐尸還是另有隱情垒在,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布扔亥,位于F島的核電站场躯,受9級(jí)特大地震影響谈为,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踢关,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一伞鲫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧签舞,春花似錦榔昔、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至师妙,卻和暖如春诵肛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背默穴。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工怔檩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蓄诽。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓薛训,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親仑氛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乙埃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容