欢迎访问比特币快报,了解最新比特币价格行情资讯及区块链技术信息就上eBTCnews.com!
🏠 技术 使用Substrate开发区块链存证dApp

使用Substrate开发区块链存证dApp

比特王 比特王 | 2020-08-07 10:34 | 人气:43 | 赞:0 |

前面文章介绍了在Substrate上开发智能合约,包括使用原生的ink!语言开发ERC20智能合约,以及将以太坊的Solidity智能合约跑在Substrate链上,在本文将进一步学习在Substrate链上开发一个自定义的区块链存证dApp。


使用Substrate开发区块链存证dApp


本文内容参考:https://substrate.dev/docs/en/tutorials/build-a-dapp/


2 前置准备


2.1 rust安装


Substrate是由rust语言开发,首先需要安装rust环境。


2.1.1 软件安装


Rust的安装比较简单,执行如下一条命令即可,该命令将自动完成软件包的下载、安装、环境变量设置:


$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh


安装成功后,会显示如下日志


  stable installed - rustc 1.45.1 (c367798cf 2020-07-26)

Rust is installed now. Great!


安装完成后,在~/.cargo/bin目录可以看到相关命令行工具


.cargo/bin/

├── cargo

├── cargo-clippy

├── cargo-fmt

├── cargo-miri

├── clippy-driver

├── rls

├── rustc

├── rustdoc

├── rustfmt

├── rust-gdb

├── rust-lldb

└── rustup


2.1.2 环变设置


执行下面命令,即将export PATH="$HOME/.cargo/bin:$PATH",追加到~/.bashrc中

$ cat ~/.cargo/env >> ~/.bashrc


执行下面命令,使得添加的环境变量生效

$ . ~/.bashrc


可执行如下命令查看安装版本


$ rustc --version

rustc 1.45.1 (c367798cf 2020-07-26)


2.1.3 配套安装


(1) Racer安装


Racer是一个由Rust爱好者提供的Rust自动补全和语法分析工具,被用来提供基本的补全功能和自定义跳转功能。本身完全由Rust写成,补全功能比较完善。


· 安装命令


$ cargo install racer

......

    Finished release [optimized] target(s) in 2m 44s

  Installing /home/jason/.cargo/bin/racer

   Installed package `racer v2.1.36` (executable `racer`)


若安装报错:error[E0554]: #![feature] may not be used on the stable release channel


请先执行下面命令,切换到nightly版本后,再进行安装:


$ rustup install nightly

$ rustup default nightly

$ rustc --version

rustc 1.47.0-nightly (6c8927b0c 2020-07-26)


· 查看版本


$ racer -V

racer 2.1.36


(2) 源码下载


为了对Rust标准库进行补全,Racer需要获取Rust源码路径。通过rustup获取源码的好处是rustup update可以随时获取最新代码


· 获取源码


$ rustup component add rust-src

info: downloading component 'rust-src'

info: installing component 'rust-src'


· 更新源码


$ rustup update

info: checking for self-updates


   stable-x86_64-unknown-linux-gnu unchanged - rustc 1.45.2 (d3fb005a3 2020-07-31)

  nightly-x86_64-unknown-linux-gnu unchanged - rustc 1.47.0-nightly (6c8927b0c 2020-07-26)


info: cleaning up downloads & tmp directories


· 环变设置


在.bashrc中添加以下内容:


export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"


2.2 yarn安装


Substrate前端模板工程(frONT-end-template)是使用yarn进行包管理的,在此我们进行安装。


安装步骤参考:https://classic.yarnpkg.com/en/docs/install/#centos-stable


$ curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /ETC/yum.repos.d/yarn.repo

[yarn]

name=Yarn Repository

baseurl=https://dl.yarnpkg.com/rpm/

enabled=1

gpgcheck=1

gpgkey=https://dl.yarnpkg.com/rpm/pubkey.gpg


$ curl --silent --location https://rpm.nodesource.com/setup_12.x | sudo bash -


$ sudo yum install yarn


$ yarn --version

1.22.4


3 存证dApp后端节点开发


存证dApp后端节点是基于node-template来开发,它是一个基于FRAME的Substrate后端节点,可以在其基础上,进行修改以便快速搭建属于自己的Substrate网络。


3.1 node-template安装


版本

v2.0.0-rc5


下载


[Jason@RUAN:~/Blockchain]$ git clone git@github.com:substrate-developer-hub/substrate-node-template.git


[Jason@RUAN:~/Blockchain/substrate-node-template] (master)$ git checkout -b v2.0.0-rc5 v2.0.0-rc5

切换到一个新分支 'v2.0.0-rc5'

[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$


编译


安装依赖,避免后续编译错误:


[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ rustup target add wasm32-unknown-unknown --toolchain nightly

[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ yum install -y llvm-devel clang-devel


[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ cargo build --release


编译错误及处理


编译错误1


· 错误描述


      Finished release [optimized] target(s) in 2m 51s

       Running `/root/Yikuai/substrate-node-template/target/release/wbuild-runner/node-template-runtime3424067592371620269/target/x86_64-unknown-linux-gnu/release/wasm-build-runner-impl`

  Rust WASM toolchain not installed, please install it!

warning: build failed, waiting for other jobs to finish...

error: build failed


· 解决办法


$ rustup target add wasm32-unknown-unknown --toolchain nightly

info: downloading component 'rust-std' for 'wasm32-unknown-unknown'

info: installing component 'rust-std' for 'wasm32-unknown-unknown'

info: Defaulting to 500.0 MiB unpack ram


编译错误2


· 错误描述


warning: couldn't execute `llvm-config --prefix` (error: No such file or directory (os error 2))

warning: set the LLVM_CONFIG_PATH environment variable to the full path to a valid `llvm-config` executable (including the executable itself)


error: failed to run custom build command for `librocksdb-sys v6.7.4`


· 解决办法

$ yum install -y llvm-devel


编译错误3


· 错误描述


   Compiling librocksdb-sys v6.7.4

error: failed to run custom build command for `librocksdb-sys v6.7.4`


Caused by:

  process didn't exit successfully: `/root/Yikuai/substrate-node-template/target/release/build/librocksdb-sys-1bb53efdfd682ab6/build-script-build` (exit code: 101)

  --- stdout

  cargo:rerun-if-changed=build.rs


  --- stderr

  thread 'main' panicked at 'Unable to find libclang: "couldn\'t find any valid shared libraries matching: [\'libclang.so\', \'libclang-*.so\', \'libclang.so.*\', \'libclang-*.so.*\'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [])"', /root/.cargo/registry/src/github.com-1ecc6299db9ec823/bindgen-0.53.3/src/lib.rs:1956:31


· 解决办法

$ yum install -y clang-devel


3.2 存证pallet开发


Substrate运行时由FRAME pallets组成。这些pallets可以被认为是定义你的区块链能够做什么的一个个独立的逻辑单元。


Substrate已经提供了许多预置pallets,用于基于FRAME的运行时。如下图所示:


使用Substrate开发区块链存证dApp


例如,FRAME中包含一个balances的pallet,这个pallet通过管理系统中所有账户余额来控制你的区块链系统中的基础货币。如果你想向你的区块链系统中添加智能合约功能,你只需要包含**合约pallet**即可。


本节我们就是要开发一个存证pallet,并将其添加到我们自定义的区块链中。


3.2.1 创建poe pallet工程目录


pos => Proof Of Existence


[Jason@RUAN:~/Blockchain/substrate-node-template/pallets] (v2.0.0-rc5)$ cargo new --lib poe

[Jason@RUAN:~/Blockchain/substrate-node-template/pallets/poe] (v2.0.0-rc5)$ tree

.

├── Cargo.toml

└── src

    └── lib.rs


3.2.2 代码框架


在新生成lib.rs文件中,填写以下代码框架,这也是从宏观角度来讲,Substrate pallet可以拆分成的6个部分:


// 1. Imports

use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch};

use frame_system::{self as system, ensure_signed};


// 2. Pallet Configuration

pub trait Trait: system::Trait { /* --snip-- */ }


// 3. Pallet Storage Items

decl_storage! { /* --snip-- */ }


// 4. Pallet Events

decl_event! { /* --snip-- */ }


// 5. Pallet Errors

decl_error! { /* --snip-- */ }


// 6. Callable Pallet Functions

decl_module! { /* --snip-- */ }


3.2.3 添加依赖


(1)完善引用


#![cfg_attr(not(feature = "std"), no_std)]


use frame_support::{

    decl_module, decl_storage, decl_event, decl_error, ensure, StorageMap

};

use frame_system::{self as system, ensure_signed};

use sp_std::vec::Vec;

(2)完善Cargo.toml文件


将pallets/template/Cargo.toml拷贝至pallets/poe目录,并增加以下内容:


# 增加段

[dependencies.sp-std]

git = 'https://github.com/paritytech/substrate.git'

default-features = false

tag = 'v2.0.0-rc5'

version = '2.0.0-rc5'


[features]

default = ['std']

std = [

    'codec/std',

    'frame-support/std',

    'frame-system/std',

    'sp-std/std',                      # <-- 增加行

]


3.2.4 配置pallet


每一个pallet都有一个配置trait


// 2. Pallet Configuration

pub trait Trait: system::Trait {

    /// The overarching event type.

    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;

}


3.2.5 定义事件


事件:可以展示pallet成功被调用的时间和信息。


// 4. Pallet Events 

decl_event! {       

    pub enum Event<T> where AccountId = <T as system::Trait>::AccountId {

        /// Event emitted when a proof has been claimed.

        ClaimCreated(AccountId, Vec<u8>),

        /// Event emitted when a claim is revoked by the owner.

        ClaimRevoked(AccountId, Vec<u8>),

    }

}


我们的存证palet,包含了以下事件:


ClaimCreated:存证创建

ClaimRevoked:存证撤销


事件可以包含一些附加数据,例如:


AccountId:谁触发了事件

Vec<u8>:存储或撤销的存证数据


3.2.6 定义错误


错误:可以展示pallet调用失败的时间,及失败原因。


// 5. Pallet Errors

decl_error! {

    pub enum Error for Module<T: Trait> {

        /// This proof has already been claimed

        ProofAlreadyClaimed,

        /// The proof does not exist, so it cannot be revoked

        NoSuchProof,                                                                                                    

        /// The proof is claimed by another account, so caller can't revoke it

        NotProofOwner,

    }

}


3.2.7 定义存储


要添加一个新的存证到我们的区块链上,就是要将其存储到我们的pallet的存储里面。在这里创建我们的存储结构。


// 3. Pallet Storage Items

decl_storage! { 

    trait Store for Module<T: Trait> as TemplateModule {

        /// The storage item for our proofs.

        /// It maps a proof to the user who made the claim and when they made it.

        Proofs: map hasher(blake2_128_concat) Vec<u8> => (T::AccountId, T::BlockNumber);                                                                                          

    }   

}


3.2.8 实现接口


// 6. Callable Pallet Functions

decl_module! {

    /// The module declaration.

    pub struct Module<T: Trait> for enum Call where origin: T::Origin {

        // Initializing errors

        // this includes information about your errors in the node's metADAta.

        // it is needed only if you are using errors in your pallet

        type Error = Error<T>;


        // A default function for depositing events

        fn deposit_event() = default;


        /// Allow a user to claim ownership of an unclaimed proof

        #[weight = 10_000]

        fn create_claim(origin, proof: Vec<u8>) {

            // Verify that the incoming transaction is signed and store who the

            // caller of this function is.

            let sender = ensure_signed(origin)?;


            // Verify that the specified proof has not been claimed yet or error with the message

            ensure!(!Proofs::<T>::contains_key(&proof), Error::<T>::ProofAlreadyClaimed);


            // Call the `system` pallet to get the current block number

            let current_block = <system::Module<T>>::block_number();


            // Store the proof with the sender and the current block number

            Proofs::<T>::insert(&proof, (&sender, current_block));


            // Emit an event that the claim was created

            Self::deposit_event(RawEvent::ClaimCreated(sender, proof));

        }


        /// Allow the owner to revoke their claim

        #[weight = 10_000]

        fn revoke_claim(origin, proof: Vec<u8>) {

            // Determine who is calling the function

            let sender = ensure_signed(origin)?;


            // Verify that the specified proof has been claimed

            ensure!(Proofs::<T>::contains_key(&proof), Error::<T>::NoSuchProof);


            // Get owner of the claim

            let (owner, _) = Proofs::<T>::get(&proof);


            // Verify that sender of the current call is the claim owner

            ensure!(sender == owner, Error::<T>::NotProofOwner);


            // Remove claim from storage

            Proofs::<T>::remove(&proof);


            // Emit an event that the claim was erased

            Self::deposit_event(RawEvent::ClaimRevoked(sender, proof));

        }

    }

}


3.2.9 完善runtime配置


· 修改runtime/Cargo.toml


# 增加段

[dependencies.poe]  

default-features = false

package = 'pallet-poe'

path = '../pallets/poe'                                                                                                                                                           

version = '2.0.0-rc5'


[features]         

default = ['std']  

std = [    

    'aura/std',    

    'balances/std',

    'codec/std',   

    'frame-executive/std',

    'frame-support/std',

    'grandpa/std', 

    'randomness-collective-flip/std',

    'serde',       

    'sp-api/std',  

    'sp-block-builder/std',

    'sp-consensus-aura/std',

    'sp-core/std', 

    'sp-inherents/std',

    'sp-io/std',   

    'sp-offchain/std',

    'sp-runtime/std',

    'sp-session/std',

    'sp-std/std',  

    'sp-transaction-pool/std',

    'sp-version/std',

    'sudo/std',

    'system/std',

    'timestamp/std',

    'transaction-payment/std',

    'template/std',

    'poe/std',                                                                           # <-- 增加行                                                                                          

]


· 修改runtime/src/lib.rs


//  增加代码块

impl poe::Trait for Runtime {

        type Event = Event;

}           

   

construct_runtime!(

        pub enum Runtime where

                Block = Block,

                NodeBlock = opaque::Block,

                UncheckedExtrinsic = UncheckedExtrinsic

        {   

                System: system::{Module, Call, Config, Storage, Event<T>},

                RandomnessCollectiveFlip: randomness_collective_flip::{Module, Call, Storage},

                Timestamp: timestamp::{Module, Call, Storage, Inherent},

                Aura: aura::{Module, Config<T>, Inherent},

                Grandpa: grandpa::{Module, Call, Storage, Config, Event},

                Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},

                TransactionPayment: transaction_payment::{Module, Storage},

                Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},

                TemplateModule: template::{Module, Call, Storage, Event<T>},

                PoeModule: poe::{Module, Call, Storage, Event<T>},   // <-- 增加代码行

        }                                                                                                                                                                         

);


3.3 node-template节点编译


完成存证pallet的开发后,需要重新编译节点。


[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ cargo build --release

   Compiling node-template-runtime v2.0.0-rc5 (/root/Blockchain/substrate-node-template/runtime)

   Compiling pallet-poe v2.0.0-rc5 (/root/Blockchain/substrate-node-template/pallets/poe)

   Compiling node-template v2.0.0-rc5 (/root/Blockchain/substrate-node-template/node)

    Finished release [optimized] target(s) in 12m 18s


3.4 node-template节点启动


[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ ./target/release/node-template purge-chain --dev

Are you sure to remove "/root/.local/share/node-template/chains/dev/db"? [y/N]: y

"/root/.local/share/node-template/chains/dev/db" removed.


[Jason@RUAN:~/Blockchain/substrate-node-template] (v2.0.0-rc5)$ ./target/release/node-template --dev --ws-external --rpc-external --rpc-cors=all

2020-08-04 22:23:44 Substrate Node

2020-08-04 22:23:44  version 2.0.0-rc5-8f769db-x86_64-linux-gnu

2020-08-04 22:23:44   by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2020

2020-08-04 22:23:44  Chain specification: Development

2020-08-04 22:23:44   Node name: gray-island-3707

2020-08-04 22:23:44  Role: AUTHORITY

2020-08-04 22:23:44  Database: RocksDb at /root/.local/share/node-template/chains/dev/db

2020-08-04 22:23:44   Native runtime: node-template-1 (node-template-1.tx1.au1)

2020-08-04 22:23:44  Initializing Genesis block/state (state: 0x5ea9…1904, header-hash: 0x6dac…f18d)

2020-08-04 22:23:44  Loading GRANDPA authority set from genesis on what appears to be first startup.

2020-08-04 22:23:44   Loaded block-time = 6000 milliseconds from genesis on first-launch

2020-08-04 22:23:44 Highest known block at #0

2020-08-04 22:23:44 Using default protocol ID "sup" because none is configured in the chain specs

2020-08-04 22:23:44  Local node identity is: 12D3KooWBSKitzNNzfSszWXRggcMe44bv6WfyKy9kyM2DwjcjJNr (legacy representation: QmX77kaM8ydN99qjyRTRznRqkHahzi5jX286MnQTqUp3UR)

2020-08-04 22:23:44  PromETHeus server started at 127.0.0.1:9615

2020-08-04 22:23:48  Starting consensus session on top of parent 0x6dac7f7bfbd9cbc4e91be19069d230c9b044ef6080d781e6717a9c99e442f18d

2020-08-04 22:23:48  Prepared block for proposing at 1 [hash: 0xd129eea95a079183db3dd87947194add22643588a1fec10e778b93a867d0f161; parent_hash: 0x6dac…f18d; extrinsics (1): [0xc502…67b6]]

2020-08-04 22:23:48  Pre-sealed block for proposal at 1. Hash now 0x2305ab1c8aee785cb991c993e849b79d7231ad8206b0e7e9b75ef17c3ee90b64, previously 0xd129eea95a079183db3dd87947194add22643588a1fec10e778b93a867d0f161.

2020-08-04 22:23:48  Imported #1 (0x2305…0b64)

2020-08-04 22:23:49  Idle (0 peers), best: #1 (0x2305…0b64), finalized #0 (0x6dac…f18d),  0  0

2020-08-04 22:23:54  Starting consensus session on top of parent 0x2305ab1c8aee785cb991c993e849b7

关键词:区块链 Substrate dApp

原标题:使用Substrate开发区块链存证dApp

0

【版权说明】文章为作者独立观点,不代表《比特币快报》立场。如有侵权,请联系我们。

共0条评论 你可以在 登录注册 后对本文发表评论