LOADING...
LOADING...
LOADING...
当前位置: 玩币族首页 > 区块链资讯 > 【Substrate开发教程】14 - 使用polkadot-js API获取链上信息

【Substrate开发教程】14 - 使用polkadot-js API获取链上信息

2020-10-27 松果 来源:区块链网络


前几篇文章介绍了Substrate的一些理论知识和substrate-node-template的使用,这篇文章介绍polkadot.js API以及如何使用它和Substrate区块链进行交互。

安装substrate-front-end-template

这篇文章介绍的polkadot-js API的使用是基于substrate-front-end-template的,安装该项目的方法在之前的文章:《创建第一条Substrate区块链》介绍过,可按文中方法自行安装。

安装polkadot.js

polkadot.js是可以和Substrate区块链交互的JS API,使用如下命令安装JS API到React项目:

yarn add @polkadot/api

安装好后,在package.json的dependencies下可以找到已安装的依赖:


polkadot.js相关概念

1、元数据(Metadata)

当连接到节点时,@polkadot/api的接口是动态生成的,要做的第一件事就是检索元数据,并根据元数据信息装饰API,以如下形式构成接口:

api.<type>.<module>.<section>

包括如下一些分组:

consts:所有运行时常量,如api.consts.balances.existentialDeposit;query:所有链上状态信息,如api.query.system.account(<accountId>);tx:所有交易信息,如api.tx.balances.transfer(<accountId>, <value>);events:事件,如api.query.system.events();

2、链默认值(Chain Defaults)

除了元数据接口方式,polkadot.js API还提供直接的API接口,包括:

api.genesisHash:所连接的链的初始哈希;api.runtimeMetadata:从链中检索到的元数据;api.runtimeVersion:链运行时版本;api.libraryInfo:API的版本,如目前使用的是@polkadot/api v2.2.1;

创建实例

修改substrate-front-end/src/App.js的代码如下:


主要代码有:导入polkadot/api提供的组件

import { ApiPromise, WsProvider } from '@polkadot/api';

通过WebSocket Provider创建api对象

const wsProvider = new WsProvider('wss://rpc.polkadot.io'); const api = await ApiPromise.create({ provider: wsProvider });

使用api对象获取链的初始哈希(genesisHash)

api.genesisHash.toHex()

使用yarn start启动前端界面,效果如下:


这里获取的是polkadot主网的genesisHash,把ws地址换成

ws://localhost:9944

可以获取本地节点的genesisHash,前提是先启动本地node节点。

cd substrate-node-template ./target/release/node-template --dev

效果如下:


可以看到波卡主网和我本地节点的genesisHash:

波卡主网:0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3本地节点:0x5aba5001fc1aa6b5593d643c69a02272146f5cc4c0adba3d4084b70c8934d9b3

查询运行时常量(Runtime constants)

api.consts.babe.epochDuration.toNumber()

表示一个epoch占用的slot数量,每当一个新的epoch开始时,会启动一个新的会话(session)。

epochDuration是常量,可以直接获取,不需要await,修改substrate-front-end/src/App.js的代码如下:


效果如下:


查询链上状态(State queries)

查询链上状态数据使用api.query,而query后的<module>名字是当连到Substrate节点时动态创建的,取决于连接的Substrate网络加载了什么pallet。如查询指定账户的余额的代码如下:

const ADDR = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFabHE'; const now = await api.query.timestamp.now(); const { nonce, data: balance } = await api.query.system.account(ADDR); console.log(`${now}: balance of ${balance.free} and a nonce of ${nonce}`);

RPC查询(RPC queries)

api.rpc使用api.query相同的样式,如获取Substrate区块链名和最后一个区块头的编号和哈希值:

const chain = await api.rpc.system.chain(); const lastHeader = await api.rpc.chain.getHeader(); console.log(`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`);

控制台打印结果如下:

Polkadot: last block #1941646 has hash 0xe482b5b950bcbc8d41240a953bc862b9ec72a4e46cd5183a176875d174cc6757

RPC倾向于使用订阅(监听)功能,下面的代码可以跟踪新区块的出块过程:

const chain = await api.rpc.system.chain(); await api.rpc.chain.subscribeNewHeads((lastHeader) => { console.log(`${chain}: last block #${lastHeader.number} has hash ${lastHeader.hash}`); });

控制台打印数据如下:


Polkadot网络每6秒出一个新区块。

订阅(Subscriptions)

使用api.query扩展之前的api.rpc查询

const unsub = await api.query.timestamp.now((moment) => { console.log(`The last block has a timestamp of ${moment}`); });

用这种方法返回的是取消订阅的函数,当不再需要监听时就可以调用这个函数。

带参数的订阅(Subscriptions with params)

const ADDR = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFabHE'; 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}`); });

订阅后,当账户余额发生变化时会自动调用回调函数中的代码。

订阅查询多个链上数值(Multi queries)

相同数据类型

const unsub = await api.query.system.account.multi([ADDR1, ADDR2], (balances) => { const [{ data: balance1 }, { data: balance2 }] = balances; console.log(`The balances are ${balance1.free} and ${balance2.free}`); });

不同数据类型

const unsub = await api.queryMulti([ api.query.timestamp.now, [api.query.system.account, ADDR] ], ([now, { nonce, data: balance }]) => { console.log(`${now}: balance of ${balance.free} and a nonce of ${nonce}`); });

查询指定区块的状态信息

下面的例子分别查询某个账户两个相邻区块的余额,并计算它们的差值

const ADDR = '5DTestUPts3kjeXSTMyerHihn1uwMfLj8vU8sqF7qYrFabHE'; const lastHdr = await api.rpc.chain.getHeader(); const [{ data: balanceNow }, { data: balancePrev }] = await Promise.all([ api.query.system.account.at(lastHdr.hash, ADDR), api.query.system.account.at(lastHdr.parentHash, ADDR) ]); console.log(`The delta was ${balanceNow.free.sub(balancePrev.free)}`);

查询指定范围区块的状态信息

const lastHdr = await api.rpc.chain.getHeader(); const startHdr = await api.rpc.chain.getBlockHash(lastHdr.number.unwrap().subn(500)); const changes = await api.query.system.account.range([startHdr]); changes.forEach(([hash, value]) => { console.log(hash.toHex(), value.toHuman()); });

还有更多查询方式可以参考官方文档,就不一一列出了。

—-

编译者/作者:松果

玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。

LOADING...
LOADING...