前面文章介绍了在Substrate上开发*jasonruan 2020.08.05* # 1 前言 前面文章介绍了在`Substrate`上开发,追加到~/.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来开发,它是一个基于FRAMESubstrate后端节点,可以在其基础上,进行修改以便快速搭建属于自己的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可以被认为是定义你的

例如,FRAME中包含一个balancespallet,这个pallet通过管理系统中所有账户余额来控制你的

(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 定义存储

要添加一个新的存证到我们的

4 存证dApp前端界面开发

存证dApp前端界面是基于front-end-template开发,它是Substrate前端应用开发模板,可以通过其连接Substrate后端节点。

4.1 front-end-template安装

  • 版本

    v2.0.0-rc5

  • 下载

[Jason@RUAN:~/Blockchain]$ git clone git@github.com:substrate-developer-hub/substrate-front-end-template.git  [Jason@RUAN:~/Blockchain/substrate-front-end-template] (master)$ git checkout -b v2.0.0-rc5 v2.0.0-rc5 切换到一个新分支 'v2.0.0-rc5' [Jason@RUAN:~/Blockchain/substrate-front-end-template] (v2.0.0-rc5)$
  • 安装

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

$ yum instally -y libusbx-devel libusb-devel libudev-devel
[Jason@RUAN:~/Blockchain/substrate-front-end-template] (v2.0.0-rc5)$ yarn install yarn install v1.22.4
  • 安装错误及处理
  • 安装错误1

    • 错误描述
    Package libusb-1.0 was not found in the pkg-config search path. Perhaps you should add the directory containing `libusb-1.0.pc' to the PKG_CONFIG_PATH environment variable No package 'libusb-1.0' found
    • 解决办法
    $ yum install libusbx-devel libusb-devel -y
  • 安装错误2

    • 错误描述
    libudev.h:没有那个文件或目录
    • 解决办法
    $ yum install libudev-devel
  • 启动命令
[Jason@RUAN:~/Blockchain/substrate-front-end-template] (v2.0.0-rc5)$ yarn start Compiled successfully!  You can now view substrate-front-end-template in the browser.    Local:            http://localhost:8000/   On Your Network:  http://172.29.0.4:8000/  Note that the development build is not optimized. To create a production build, use yarn build.

4.2 存证React组件开发

4.2.1 实现存证组件

substrate-front-end-template/src目录下创建PoeModule.js,代码如下:

 React and Semantic UI elements. import React, { useState, useEffect } from 'react'; import { Form, Input, Grid, Message } from 'semantic-ui-react'; // Pre-built Substrate front-end utilities for connecting to a node // and making a transaction. import { useSubstrate } from './substrate-lib'; import { TxButton } from './substrate-lib/components'; // Polkadot-JS utilities for hashing data. import { blake2AsHex } from '@polkadot/util-crypto';  // Our main Proof Of Existence Component which is exported. export function Main (props) {     // Establish an API to talk to our Substrate node.     const { api } = useSubstrate();     // Get the 'selected user' from the `AccountSelector` component.     const { accountPair } = props;     // React hooks for all the state variables we track.     // Learn more at: https://reactjs.org/docs/hooks-intro.html     const [status, setStatus] = useState('');     const [digest, setDigest] = useState('');     const [owner, setOwner] = useState('');     const [block, setBlock] = useState(0);      // Our `FileReader()` which is accessible from our functions below.     let fileReader;      // Takes our file, and creates a digest using the Blake2 256 hash function.     const bufferToDigest = () => {         // Turns the file content to a hexadecimal representation.         const content = Array.from(new Uint8Array(fileReader.result))             .map((b) => b.toString(16).padStart(2, '0'))             .join('');          const hash = blake2AsHex(content, 256);         setDigest(hash);     };      // Callback function for when a new file is selected.     const handleFileChosen = (file) => {         fileReader = new FileReader();         fileReader.onloadend = bufferToDigest;         fileReader.readAsArrayBuffer(file);     };      // React hook to update the 'Owner' and 'Block Number' information for a file.     useEffect(() => {         let unsubscribe;          // Polkadot-JS API query to the `proofs` storage item in our pallet.         // This is a subscription, so it will always get the latest value,         // even if it changes.         api.query.poeModule             .proofs(digest, (result) => {                 // Our storage item returns a tuple, which is represented as an array.                 setOwner(result[0].toString());                 setBlock(result[1].toNumber());             })             .then((unsub) => {                 unsubscribe = unsub;             });          return () => unsubscribe && unsubscribe();         // This tells the React hook to update whenever the file digest changes         // (when a new file is chosen), or when the storage subscription says the         // value of the storage item has updated.     }, [digest, api.query.poeModule]);      // We can say a file digest is claimed if the stored block number is not 0.     function isClaimed () {         return block !== 0;     }      // The actual UI elements which are returned from our component.     return (         <Grid.Column>         <h1>Proof Of Existence</h1>         {/* Show warning or success message if the file is or is not claimed. */}         <Form success={!!digest && !isClaimed()} warning={isClaimed()}>         <Form.Field>         {/* File selector with a callback to `handleFileChosen`. */}         <Input         type='file'         id='file'         label='Your File'         onChange={(e) => handleFileChosen(e.target.files[0])}         />         {/* Show this message if the file is available to be claimed */}         <Message success header='File Digest Unclaimed' content={digest} />         {/* Show this message if the file is already claimed. */}         <Message         warning         header='File Digest Claimed'         list={[digest, `Owner: ${owner}`, `Block: ${block}`]}         />         </Form.Field>         {/* Buttons for interacting with the component. */}         <Form.Field>         {/* Button to create a claim. Only active if a file is selected,           and not already claimed. Updates the `status`. */}         <TxButton         accountPair={accountPair}         label={'Create Claim'}         setStatus={setStatus}         type='SIGNED-TX'         disabled={isClaimed() || !digest}         attrs={{             palletRpc: 'poeModule',                 callable: 'createClaim',                 inputParams: [digest],                 paramFields: [true]         }}         />         {/* Button to revoke a claim. Only active if a file is selected,           and is already claimed. Updates the `status`. */}         <TxButton         accountPair={accountPair}         label='Revoke Claim'         setStatus={setStatus}         type='SIGNED-TX'         disabled={!isClaimed() || owner !== accountPair.address}         attrs={{             palletRpc: 'poeModule',                 callable: 'revokeClaim',                 inputParams: [digest],                 paramFields: [true]         }}         />         </Form.Field>         {/* Status message about the transaction. */}         <div style={{ overflowWrap: 'break-word' }}>{status}</div>         </Form>         </Grid.Column>     ); }  export default function PoeModule (props) {     const { api } = useSubstrate();     return (api.query.poeModule && api.query.poeModule.proofs         ? <Main {...props} /> : null); }

4.2.2 添加存证组件

substrate-front-end-template/src/App.js中添加存证组件,代码如下:

import PoeModule from './PoeModule';    return (        <div ref={contextRef}>       <Sticky context={contextRef}>         <AccountSelector setAccountAddress={setAccountAddress} />       </Sticky>       <Container>         <Grid stackable columns='equal'>           ......           <Grid.Row>             <PoeModule accountPair={accountPair} />                                                                                                                                          </Grid.Row>         </Grid>         <DeveloperConsole />       </Container>     </div>      );         

4.2.3 修改连接配置

配置文件:substrate-front-end-template/src/config/development.json

    "PROVIDER_SOCKET": "ws://119.28.233.229:9944"

4.3 front-end-template启动

$ yarn start Compiled successfully!  You can now view substrate-front-end-template in the browser.    Local:            http://localhost:8000/   On Your Network:  http://172.29.0.6:8000/  Note that the development build is not optimized. To create a production build, use yarn build.

4.4 存证界面展示

使用Substrate开发区块链存证dApp

5 存证dApp使用展示

5.1 提交存证

  • 选择文件

使用Substrate开发区块链存证dApp

  • 提交存证

    • 存证入块

使用Substrate开发区块链存证dApp

  • 存证入块确认

使用Substrate开发区块链存证dApp

5.2 撤销存证

撤销存证的按钮,只对创建对应存证的用户可见,例如Alice创建的存证,在切换到Bob账号后,撤销存证的按钮会灰掉:

使用Substrate开发区块链存证dApp

使用Substrate开发区块链存证dApp

5.3 事件查看

可以查看到提交存证和撤销存证接口调用后触发的事件。

使用Substrate开发区块链存证dApp

6 参考资料

https://substrate.dev/docs/en/tutorials/build-a-dapp/

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注