Substrate入门指南(一)


Substrate入门指南(一)

  1. 安装运行环境
    跟随下列步骤安装substrate的运行环境(也可以参考这个链接):

    1. 安装Rust

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

      随后选择

      2) Customize installation

      在随后的 Default toolchain? (stable/beta/nightly/none)
      输入 nightly
      再选择1) 开始安装
      安装完成后,运行 source $HOME/.cargo/env 添加rust的环境变量
      安装完成后,输入 rustc –version,此时应该有版本号输出

    2. 下载substrate代码

      git clone -b v2.0.0 --depth 1 https://github.com/substrate-developer-hub/substrate-node-template
    3. 安装编译工具

      source ~/.cargo/env
      
      rustup update nightly
      rustup update stable
      
      rustup target add wasm32-unknown-unknown --toolchain nightly
  1. 运行你的第一个区块链
    进入刚才clone的代码目录,随后执行编译命令

    cd substrate-node-template/
    cargo build --release

    如果遇到更新crates.io index缓慢的问题,可以参考这个链接换源。
    换源后,需要注意添加环境变量 CARGO_HTTP_MULTIPLEXING=false 否则下载会失败。
    其它镜像可以参考这个链接

    如果遇到error: linker cc not found的错误,可以通过运行yum groupinstall “Development Tools” 安装Linux的开发组件来解决。

    如果遇到Unable to find libclang的错误,运行下列命令安装clang(clang必须6.0以上)
    yum install centos-release-scl
    yum install llvm-toolset-7.0
    scl enable llvm-toolset-7.0 ‘bash’
    clang –version

    如果发生其它编译错误,可以用命令dmesg | egrep -i ‘killed process’查看是否是内存不够导致的。

    启动区块链

    ./target/release/node-template --dev --tmp

    控制台如果输出Warning: Low open file descriptor limit configured for the process,可以通过ulimit -n 10000来解决。

    如果看到如下输出,恭喜你,你创建了你人生的第一个区块链了。

  2. 让别人加入到你的区块链

    1. 安装密钥工具

      cargo install --force subkey --git https://github.com/paritytech/substrate --version 2.0.0
    2. 生成sr25519

      subkey generate --scheme sr25519

      随后复制生成的secret phrase文本

    3. 生成ed25519

      subkey inspect --scheme ed25519 "之前复制的secret phrase"
    4. 创建配置文件

      ./target/release/node-template build-spec --disable-default-bootnode --chain local > customSpec.json

      随后打开customSpec.json,找到Aura和Grandpa部分

      将之前我们生成的sr25519的Address替换Aura的authorities列表,将ed25519的Address替换Grandpa的authorities列表

      最后,生成加密的配置文件customSpecRaw.json,用于分发配置给其它节点

      ./target/release/node-template build-spec --chain=customSpec.json --raw --disable-default-bootnode > customSpecRaw.json
    5. 启动根节点

      ./target/release/node-template \
      --base-path /tmp/node01 \
      --chain ./customSpecRaw.json \
      --port 30333 \
      --ws-port 9944 \
      --rpc-port 9933 \
      --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \
      --validator \
      --rpc-methods=Unsafe \
      --name MyNode01 \
      --rpc-cors all

      这里需要注意的几点:
      –base-path 指向数据文件存放路径
      –chain 参数指向刚刚生成的配置文件
      –name 自定义节点名
      –rpc-cors all 允许跨域访问

    6. 通过https://polkadot.js.org/apps/访问自己的节点

      在custom endpoint中输入域名(注意如果不是localhost的话,那么必须用wss协议,否则浏览器会限时访问)。
      但是使用wss就要求域名配置ssl证书,这里不推荐用自注册的证书,有可能会连接拒绝。下面是nginx的配置参考。

      可以看到当接受外部443的连接请求后,nginx会转发到localhost的9944,也即之前启动命令里的–ws-port所指定的端口号。

      配置成功后,我们就能看到如下界面:

      如果想要重新配置,或者配置过程中发生错误,我们也可以用如下命令清除之前生成的数据
      ./target/release/node-template purge-chain –base-path 数据路径

    7. 添加密钥
      通过菜单页面的Developer > RPC Calls,打开RPC Calls页面,选择author > insertKey,提交AURAGRANDPA的secret phrase和public key

      这时我们再看Explorer页面,应该能看到这个节点不断生成的Block了

    8. 添加子节点
      将customSpecRaw.json分发给子节点的电脑,随后执行下列代码:

      ./target/debug/node-template \
      --base-path /tmp/node02 \
      --chain ./customSpecRaw.json \
      --port 30334 \
      --ws-port 9945 \
      --rpc-port 9934 \
      --telemetry-url 'wss://telemetry.polkadot.io/submit/ 0' \
      --validator \
      --rpc-methods=Unsafe \
      --name MyNode02 \
      --bootnodes /ip4/<IP Address>/tcp/<Port>/p2p/<Peer ID>

      需要注意–bootnodes的参数,IP Address是根节点的IP地址,Peer ID是根节点在启动时的,Local node identity

      此外,如果发现block一直没有finalized的话,那是因为在插入GRANDPA Key后,要生效需要重启boot节点。

      这时当我们打开Explorer的Node Info页面时,如果你看到如下页面中的total peers为1时,恭喜你,分发节点成功了,你创建了属于你的区块链。

  3. 搭建自己的前端
    前面我们用的是polkadot的前端系统,在实际应用中,肯定会有很多定制化的需求,可以参考这个官方项目,或者如果你更熟悉Vue,可以参考如下示例。

    1. 克隆一个你喜欢的Vue框架,例如vue-element-admin

    2. 在package.json中的dependencies节点,添加对polkadot的类库依赖

      "@polkadot/api": "^2.2.1",
      "@polkadot/extension-dapp": "^0.34.1",
      "@polkadot/types": "^1.34.1",
      "@polkadot/ui-keyring": "^0.58.1",
      "@polkadot/ui-settings": "^0.58.1",
      "@polkadot/util": "^3.4.1",
      "@polkadot/util-crypto": "^3.4.1",
    3. 运行npm install

    4. 添加config.js文件和connection.js文件在src根目录下

      config.js

      export const default_endpoint = "wss://区块链地址";

      connection.js

      import { default_endpoint } from "./config.js";
      
      const endpoint = localStorage.getItem("endpoint");
      if (!endpoint || typeof endpoint !== "string" || endpoint.indexOf("ws") !== 0) {
      localStorage.setItem("endpoint", default_endpoint);
      }
      
      const { ApiPromise, WsProvider } = require("@polkadot/api");
      const wsProvider = new WsProvider(localStorage.getItem("endpoint"));
      
      let api = ApiPromise.create({
      provider: wsProvider,
      types: {
       // mapping the actual specified address format
       Address: 'AccountId',
       // mapping the lookup
       LookupSource: 'AccountId'
      }
      });
      
      export default api;
    5. 添加api接口文件,里面可以写各种对Substrate的接口调用

```
export async function getBlockNumber(api) {
    const block = await api.rpc.chain.getBlock();
    return block.block.header.number.toNumber();
}

export async function getAccountInfo(api) {
    const ADDR = '5CB7ZJioWA1EBibJKoQbxkyCupnEB1oQ2MFrRFvDxFLqTVMa';
    const now = await api.query.timestamp.now();

    // Retrieve the account balance & nonce via the system module
    const { nonce, data: balance } = await api.query.system.account(ADDR);

    console.log(`${now}: balance of ${balance.free} and a nonce of ${nonce}`);

    // Subscribe to balance changes for our account
    const unsub = await api.query.system.account(ADDR, ({ nonce, data: balance }) => {
        console.log(`free balance is ${balance.free} with ${balance.reserved} reserved and a nonce of ${nonce}`);
    });
}
```

6) 最后,我们可以在页面中直接调用接口,获取相应数据,例如

```
import api from "@/connection.js";

import { getBlockNumber, getAccountInfo, getChainInfo } from "@/api/polkadot";

export default {
  name: 'Dashboard',
  computed: {
    ...mapGetters(['name'])
  },
  created() {
    api.then((api) => {
      getBlockNumber(api).then((blockNumber) => {
        this.blocknumber = blockNumber;
      });
      getAccountInfo(api);
    });
  }
}
```

7) 关于详细的Substrate API介绍,可以查看[官网链接](https://polkadot.js.org/docs/api)

Author: Kevin Gu
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Kevin Gu !
  TOC