工具集成
本教程重点介绍了工一些具和节点扩展,这些工具和节点扩展使你能够部署与其他系统集成的节点,以及如何使用额外的生态系统工具,让你能够访问、同步,与你自己或其他区块链的信息进行交互。
集成一个轻客户端节点
本节教程演示如何使用浏览器中运行的 WebAssembly 轻客户端连接到基于 Substrate 的区块链。在本节教程中,你将使用 Substrate Connect 浏览器扩展与区块链交互,而不使用 RPC 服务。
什么是Substrate Connect
Substrate Connect是一个基于 WebAssembly 的轻客户端,可以直接在浏览器中运行。Substrate Connect light client 的核心软件组件是 smoldot。该软件需要的资源比完整节点更少,因此它可以在资源受限的环境中运行,包括浏览器、移动端点和物联网设备。轻客户端可以通过连接到一个完整的节点来同步链中的数据,而不是作为一个运行的 peer 并直接连接到区块链,以为了生产区块或导入区块。
安全同步
软件钱包允许用户通过可信任的中间第三方节点来与区块链交互,与之不同的是,轻客户端从完整节点下载区块头,这样他们就可以使用区块头中的 Merkle trie root 来验证正在同步的信息是否被篡改。Merkle trie root 作为数据没有被修改的加密证明,而不需要轻客户端信任整个节点。
Substrate Connect作为一个浏览器扩展
因为轻客户端不参与区块生成或共识,所以它们不需要在线,也不需要与网络进行持续通信。但是,如果你将轻客户端作为浏览器扩展来运行,那么你可以同时运行多个轻客户端,并且只要浏览器保持打开状态,就可以在浏览器会话中保持同步。
运行一个轻客户端作为浏览器扩展还避免了完整节点需要的使用 Transport Layer Security(TLS)和 Secure Socket Layer(SSL)证书。使用 Substrate Connect,同步在后台进行,而不需要通过 WebSocket 端口(一些浏览器会将其作为不安全连接并阻止)。运行Substrate Connect 作为浏览器扩展还提供了更好的应用程序性能和响应更快的用户体验。
使用Substrate Connect的应用程序和用户实践
如果你使用 Substrate Connect 构建应用程序,smoldot
客户端可以检测到用户是否拥有浏览器扩展,并在浏览器扩展可用时自动使用该扩展。如果用户没有安装浏览器扩展,smoldot
会自动在你的 web 应用程序中创建一个 WebAssembly 轻客户端。虽然将 Substrate Connect 作为浏览器扩展运行是可选的,该扩展提供了以下优势:
- 更好的资源使用效率。多个浏览器 tabs 可以共享一个连接到同一条链,而不是每个浏览器 tabs 或窗口打开自己的连接。
- 更好的同步速度。只要打开一个浏览器 tabs,浏览器扩展就自动开始与链同步,保持缓存以便连接到链,对于用户打开的每个新标签或浏览器窗口,同步几乎是瞬时的。如果没有浏览器扩展,同步一个链可能需要10到30秒。
- 更好的连通性。浏览器扩展可以连接到未安装 TLS/SSL 证书的节点。
下载Substrate Connect
由于 Substrate Connect 浏览器扩展提供的优势,第一步首先需要安装浏览器扩展。
- 使用 Chrome 或 Firefox 打开链接 https://substrate.io/developers/substrate-connect/。
- 点击 Chrome 或 Firefox。
- 点击 Add to Chrome 或 Add to Firefox,然后确认你想要将扩展添加到浏览器。
连接到一个众所周知的链
在 Substrate Connect 轻客户端可以连接到网络之前,你必须有一个 web 应用程序,该应用程序指定了请客户端应该连接到的网络,用于通信的节点,以及它在初始阶段必须具有的共识临界状态。这些信息可以在网络的 chain specification 文件中获得。
Substrate Connect 预先配置为识别在 WellKnownChain 列表中定义的几个链,这些知名的链是:
- Polkadot 被识别为
polkadot
- Kusama 被识别为
ksmcc3
- Rococo 被识别为
rococo_v2_2
- Westend 被识别为
westend2
要连接到这些链之一,通过以下命令克隆 empty-webapp
模板,创建使用 Substrate Connect 的 web 应用:
git clone https://github.com/bernardoaraujor/empty-webapp
cd empty-webapp
# 通过运行以下命令安装来自 Polkadot-JS RPC 提供的依赖项
yarn add @polkadot/rpc-provider
# 通过运行以下命令安装 Polkadot-JS API 中的依赖项
yarn add @polkadot/api
安装这些依赖项之后,就可以在示例应用程序中使用它们。
在编辑器中打开 empty-webapp/index.ts
文件,复制并粘贴以下应用程序代码,使用 substrate-connect
作为提供以创建一个 Substrate Connect 实例,使用 polkadot
chain specification 文件连接到 Polkadot
中继链。
import {
ScProvider,
WellKnownChain,
} from "@polkadot/rpc-provider/substrate-connect";
import { ApiPromise } from "@polkadot/api";
window.onload = () => {
void (async () => {
try {
const provider = new ScProvider(WellKnownChain.polkadot);
await provider.connect();
const api = await ApiPromise.create({ provider });
await api.rpc.chain.subscribeNewHeads(
(lastHeader: { number: unknown; hash: unknown }) => {
console.log(
`New block #${lastHeader.number} has hash ${lastHeader.hash}`
);
}
);
} catch (error) {
console.error(<Error>error);
}
})();
};
在 Polkadot-JS API 中,你可以像这样创建一个实例:
// Import
import { ApiPromise, WsProvider } from '@polkadot/api';
// Construct
const wsProvider = new WsProvider('wss://rpc.polkadot.io');
const api = await ApiPromise.create({ provider: wsProvider });
对于 Substrate Connect,你将 WebSocket(WsProvider
)provider 替换为 Substrate Connect(ScProvider
),并指定 Polkadot 网络(WellKnownChain.polkadot
)的 chain specification,而不是 WebSocket URL 客户端地址。
通过运行以下命令安装任何剩余的依赖项:
yarn
通过运行以下命令启动 web 应用程序:
yarn dev
如果在启动本地服务器时出现编译器错误,你可能会缺少当前 yarn
配置中没有考虑到的依赖。如果缺少依赖项,可以通过运行类似以下的命令添加依赖包:
yarn add -D buffer
打开 URL http://localhost:3001/
验证浏览器。
打开浏览器控制台。打开浏览器控制台的方法取决于所使用的浏览器和操作系统,例如,在 Chrome 上,选择更多工具,开发人员工具,然后单击控制台。
验证 smoldot
进程已初始化,然后是来自 Polkadot 传入块的哈希值。例如,控制台应该显示类似如下的日志信息:
[smoldot] Smoldot v0.6.25
smoldot-light.js:41 [smoldot] Chain initialization complete for polkadot. Name: "Polkadot". Genesis hash: 0x91b1…90c3. State root hash: 0x29d0d972cd27cbc511e9589fcb7a4506d5eb6a9e8df205f00472e5ab354a4e17. Network identity: 12D3KooWRse9u6Z9ukP4C92YCCH2gXziNm8ThRch2owaaFh9H6D1. Chain specification or database starting at: 0xae3e…f81d (#11228238)
...
New block #11322769 has hash 0x464c0199ede92a89920c54c21abc741ea47daca1d62d61d7b9af78062f04c7a3 index.ts:10
New block #11322770 has hash 0xd66c61e5417249df228798f38535a6dd17b8b268c165e0a6b0e72ba74e954f9d index.ts:10
这个简单的 web 应用程序只连接到 Polkadot 检索块哈希值。此应用程序的主要目的是演示在不使用中心化的网络入口点(例如特定 RPC 节点的 URL)的情况下连接到链。但是,你可以扩展这个应用程序来做更多的事情,因为在你将 WsProvider
替换为 ScProvider
之后,你可以简单地使用现有的Polkadot-JS API 为你的应用程序编写代码。
按 Control-c 停止 smoldot
轻客户端节点。
连接到自定义chain specification
连接到自定义 chain specification 或公共可访问的平行链类似于连接到 well-known 的链之一。代码中的主要区别在于,必须显式地标识要使用的 Substrate Connect 的 chain specification。这部分教程演示如何通过连接到 Statemint 平行链来连接到自定义 chain specification。Statemint 是一个连接到 Polkadot 的通用良好的平行链,并且有一个公开的 chain specification 文件。
要连接到这个链,从 cumulus repository 下载定制 chain specification 文件。将下载的 chain specification 复制到你在连接到一个众所周知的链中创建的empty-webapp
目录。
在编辑器中打开 index.ts
文件,删除当前内容。复制并粘贴以下应用程序代码:
import { ScProvider, WellKnownChain } from "@polkadot/rpc-provider/substrate-connect";import { ApiPromise } from "@polkadot/api";
import jsonParachainSpec from "./statemint.json";
window.onload = () => {
void (async () => {
try {
const relayProvider = new ScProvider(WellKnownChain.polkadot);
const parachainSpec = JSON.stringify(jsonParachainSpec);
const provider = new ScProvider(parachainSpec, relayProvider);
await provider.connect();
const api = await ApiPromise.create({ provider });
await api.rpc.chain.subscribeNewHeads((lastHeader: { number: unknown; hash: unknown }) => {
console.log(`New block #${lastHeader.number} has hash ${lastHeader.hash}`);
});
} catch (error) {
console.error(<Error>error);
}
})();
};
正如你看到的,这段代码有一些重要的区别。
statemint.json
chain specification 文件导入到jsonParachainSpec
对象中。- chain specification 被转换为一个 JSON-encoded 的字符串,并存储在
parachainSpec
变量中,这样它就可以与 web 服务器交换。
ScProvider
provider 是为 polkadot
中继链创建的,但它被用作创建和连接到平行链 provider 的参数。Substrate Connect 需要此信息来确定与平行链通信的中继链。
运行如下命令启动 web 应用程序
yarn dev
打开 URL http://localhost:3001/
验证浏览器。在浏览器中打开控制台。
验证 smoldot
进程已初始化,然后是来自 Polkadot 传入块的哈希值。例如,控制台应该显示类似如下的日志信息:
[smoldot] Parachain initialization complete for statemint. Name: "Statemint". Genesis hash: 0x68d5…de2f. State root hash: 0xc1ef26b567de07159e4ecd415fbbb0340c56a09c4d72c82516d0f3bc2b782c80. Network identity: 12D3KooWArq3iZHdK2jtRZSJzJkkWrKm17JTa9kjwjZkq9Htx5xR. Relay chain: polkadot (id: 1000 smoldot-light.js:41
[smoldot] Smoldot v0.6.25. Current memory usage: 140 MiB. Average download: 35.4 kiB/s. Average upload: 423 B/s.
New block #1785421 has hash 0x88885ed331f94b4324c5f2eae8413cd36170808ef904b0ec0867646fa53770f7 index.ts:13
New block #1785422 has hash 0x2ad4d96e061a681e27403694f1d870bb0c4e5c77b5be232a18c7a2e0b7fb2555 index.ts:13
高级应用程序开发
本节教程中的示例使用了 @polkadot/rpc-provider/substrate-connect
,因为该 provider 可以直接创建使用 Polkadot-JS API 与链进行交互的应用程序。对于不依赖 Polkadot-JS API 的更高级应用程序开发,你可以安装并使用 @substrate-connect
。例如,如果你正在构建自己的应用程序库或编程接口,则应通过运行以下命令安装 Substrate Connect 依赖项:
yarn add @substrate/connect
访问EVM账户
本节教程演示了如何使用 Frontier 项目中的 crates 来构建一个与以太坊兼容的区块链,该区块链可以访问基于以太坊的帐户并执行基于 Solidity 的智能合约。Frontier 项目的两个主要目标是使你能够执行以下操作:
- 使用本地 Substrate 节点不加修改地运行以太坊去中心化应用。
- 从以太坊主网络导入状态
本节教程使用预定义的节点模板提供的工作环境。模板是使用 Frontier release guide 中的说明生成的。
如果需要为自己生成独立的模板,可以使用 node-template-release.sh 模板生成脚本。如果你使用 frontier 仓库或模板生成脚本构建自己的节点,请注意 frontier 使用自己版本的 Substrate crates,你可能需要更新 Cargo
文件中的依赖,以匹配项目中的依赖。
创世配置
frontier-node-template
中的开发 chain specification 定义了一个创世块,该块已经为 alice
帐户预配置了一个 EVM 帐户。当你在开发模式中启动该节点时,alice
的 EVM 帐户将使用默认的 Ether 资金额度。你将使用该帐户查看 EVM 帐户详细信息并调用以太坊智能合约。启动节点后,你将能够使用 Polkadot-JS application 查看` 的 EVM 帐户的详细信息。
编译一个Frontier节点
要编译 Frontier node template,通过运行一下命令克隆 node template 仓库,并编译 node template:
git clone https://github.com/substrate-developer-hub/frontier-node-template.git
cd frontier-node-template
cargo build --release
连接到节点
在节点编译后,必须启动该节点才能开始研究预先配置的 EVM 帐户。
要启动本地 Substrate 节点,在 frontier-node-template
目录下,运行一下命令:
./target/release/frontier-template-node --dev
--dev
命令行选项指定节点使用预定义的 development
chain specification 运行,该 chain specification 包括 alice
预定义的 EVM 帐户和用于测试的其他帐户。
通过检查终端中显示的输出,验证你的节点已成功启动并运行,终端应该显示类似这样的输出:
2022-07-08 10:06:42 Frontier Node
2022-07-08 10:06:42 ✌️ version 0.0.0-1b6bff4-x86_64-macos
2022-07-08 10:06:42 ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2021-2022
2022-07-08 10:06:42 📋 Chain specification: Development
2022-07-08 10:06:42 🏷 Node name: flippant-boat-0444
2022-07-08 10:06:42 👤 Role: AUTHORITY
...
使用 Polkadot-JS application 连接本地节点。
点击 Settings,然后点击 Developer
定义以下帐户信息来创建一个 EVM Account
类型,并允许该帐户发送交易和检查区块。要发送交易,你必须定义 Address
和 LookupSource
的值。要检查区块,你必须定义 Transaction
和 Signature
的值。
{
"Address": "MultiAddress",
"LookupSource": "MultiAddress",
"Account": {
"nonce": "U256",
"balance": "U256"
},
"Transaction": {
"nonce": "U256",
"action": "String",
"gas_price": "u64",
"gas_limit": "u64",
"value": "U256",
"input": "Vec<u8>",
"signature": "Signature"
},
"Signature": {
"v": "u64",
"r": "H256",
"s": "H256"
}
}
点击保存
使用RPC查询余额
在为 EVM 帐户配置对应的设置后,可以使用 Polkadot-JS 应用程序查看 alice
的 EVM 帐户信息。
- 验证你的节点仍在运行,并且 Polkadot-JS 应用程序已连接到该节点。
- 点击 Developer,然后选择 RPC calls。
- 在 Submission 选项卡上,选择 eth 作为要调用的端点。
- 从要调用的函数列表中选择 getBalance(address, number)。
- 为
alice
帐户的地址指定 EVM 帐户标识符。 预定义账户地址为0xd43593c715fdd31c61141abd04a99fd6822c8558
。帐户的地址是使用 Substrate EVM utilities 从alice
帐户的公钥计算出来的。 - 点击 Submit RPC call,该调用应该返回如下类似的输出:
2: eth.getBalance: U256
340,282,366,920,938,463,463,374,607,431,768,210,955
部署一个智能合约
现在你已经了解了如何查询以太坊地址的余额,你可能还想探索如何部署和调用以太坊智能合约并测试相关功能。这部分内容会使用一个 Truffle 示例合约来定义 ERC-20 token。你也可以使用 Polkadot JS SDK 和 Typescript 创建一个 ERC-20 token 合约。
创建 ERC-20 合约。为了方便起见,你可以使用 MyToken.json 中的 token 合约编译的 bytecode
,然后将合约部署到 Substrate 区块链上。
验证你的节点仍在运行,并且 Polkadot-JS application 已连接到该节点。
点击 Developer,然后选择 Extrinsics。
选择 ALICE 开发帐户作为用于提交交易的帐户。
选择 evm。
选择 create 函数。
配置该函数的参数:
|For this|Specify this|
|:-----|:-----|
|source
|0xd43593c715fdd31c61141abd04a99fd6822c8558|
|init
|MyToken.json
中的原始 bytecode
十六进制值|
|value
|0|
|gasLimit
|4294967295|
|maxFeePerGas
|100000000|
你可以将可选参数保留为空,nonce
的值将增加源帐户的已知 nonce 值,并从 0x0
开始。根据所选函数的不同,你可能需要删除未使用的参数。
点击 Submit Transaction。
点击 Sign and Submit 对交易进行授权。
查看智能合约
提交交易后,合约将部署到网络上,你可以使用 Polkadot-JS application 查看有关它的信息。
验证你的节点仍在运行,并且 Polkadot-JS application 已连接到该节点。
点击 Network,然后选择 Explorer。
点击 evm.Created 事件以验证新创建的合约的地址为 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
。
您还可以使用浏览器的开发人员工具中的控制台查看有关事务的详细信息。因为EVM合同地址是由帐户标识符和合同创建者的nonce决定的,所以部署合同的地址是使用众所周知的帐户标识符0xd43593c715fdd31c61141abd04a99fd6822c8558和alice帐户的nonce 0x0计算的。
点击 Developer,然后选择 Chain State。
选择 evm 作为查询和 accountCodes 的状态。
为 alice
帐户指定帐户标识符 0xd43593c715fdd31c61141abd04a99fd6822c8558
,注意帐户代码为空(0x
)。
为你使用 alice
开发帐户部署的合约指定合约地址 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
,注意合约帐户代码是来自 Solidity 合约的字节码。
查看账户存储
你部署的 ERC-20 合约是基于 OpenZeppelin ERC-20 implementation。该合约包括一个构造函数,该构造函数生成最大数量的 tokens,并将它们存储在与合约创建者关联的帐户中。
要查询智能合约关联的账户存储信息:
在以 evm 作为要查询状态的 Chain State 中,选择 accountStorages。
指定 ERC-20 合约地址 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
作为第一个参数。
将要读取的存储插槽指定为第二个参数 0x045c0350b9cf0df39c4b40400c965118df2dca5ce0fbcf0de4aafc099aea4a14
。地址的存储槽是使用基于槽位 0 和帐户标识符 0xd43593c715fdd31c61141abd04a99fd6822c8558
的 Substrate EVM utilities 计算得到的。该值应该返回的是 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
。如果你在部署合同之后检查 alice
帐户的余额,你会看到从帐户中提取了一笔费用,并且 getBalance(address, number)
调用返回一个类似于下面的值:
340,282,366,920,938,463,463,374,603,530,233,757,803
转移代币
到目前为止,你只使用了 alice
开发帐户。接下来是使用部署的合约将 tokens 转移到另一个帐户。
验证你的节点仍在运行,并且 Polkadot-JS application 已连接到该节点。
点击 Developer,然后选择 Extrinsics。
选择 ALICE 开发帐户作为用于提交交易的帐户。
选择 evm。
选择 call 调用 ERC-20 合约上的 transfer(address, uint256)
函数。
配置该函数的参数:
|For this|Specify this|
|:-----|:-----|
|source
|0xd43593c715fdd31c61141abd04a99fd6822c8558|
|target
|0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f|
|input
|0xa9059cbb0000000000000000000000008eaf04151687736326c9fea17e25fc528761369300000000000000000000000000000000000000000000000000000000000000dd|
|value
|0|
|gasLimit
|4294967295|
|maxFeePerGas
|100000000|
source
表示持有 tokens 的帐户。在本例中,source
是合约创建者 alice
的 EVM 帐户。target
是将 tokens 从 alice
转移到 bob
的合约地址。input
参数是一个 EVM ABI-encoded 的函数调用,它指定执行转移的函数调用(0xa9059cbb
)和函数所需的参数。对于这个函数,参数是 bob
EVM 帐户标识符(0x8eaf04151687736326c9fea17e25fc5287613693
)和要转移的 tokens
数量(221 或 0xdd
十六进制)。本节教程中的 input 值是使用 Remix web IDE 计算得到的。
点击 Submit Transaction。
点击 Sign and Submit 对交易进行授权。
验证代币转移
提交交易后,合约将部署到网络上,你可以使用 Polkadot-JS application 查看有关它的信息。
验证你的节点仍在运行,并且 Polkadot-JS application 已连接到该节点。
点击 Network,然后选择 Explorer。
点击 evm.Executed 事件来验证已执行的合约地址为 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
。
点击 Developer,然后选择 Chain State。
选择 evm 作为要查询的状态和 accountStorages。
查看存储合约地址 0x8a50db1e0f9452cfd91be8dc004ceb11cb08832f
和存储槽 0x045c0350b9cf0df39c4b40400c965118df2dca5ce0fbcf0de4aafc099aea4a14
。
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff22
如果你在部署合约之后检查 alice
帐户的余额,你会看到从帐户中提取了一笔费用,getBalance(address, number)
调用返回一个类似于下面的值:
340,282,366,920,938,463,463,374,603,530,233,366,411
以太坊集成
通过使用 Frontier 项目的 crates,并将 EVM 和 Ethereum pallets 添加到你的运行时中,你可以构建一个基于 Substrate 的区块链,它支持 Ethereum-based 的账户,并允许执行 Solidity-based 的智能合约。
以太坊虚拟机(EVM)是一种虚拟计算机,其组件使以太坊网络参与者能够存储数据并就数据的状态达成一致。对于一个基于 Substrate 的区块链,EVM 的核心职责在 EVM pallet 中实现的。EVM pallet 负责执行以太坊合约字节码,这些智能合约是用像 Solidity 这样的高级语言编写的,然后编译为 EVM 字节码。下面的图表提供了一个简单的概述,以说明如何将 EVM pallet 和以太坊 RPC 调用集成到你的 Substrate 运行时中。
除了 EVM pallet,Ethereum pallet 还负责存储 Ethereum-formatted 的块、交易收据和交易状态。当用户提交原始以太坊交易时,通过在运行时调用 pallet_ethereum
中的 transact
函数,该交易首先会被转换为一个 Substrate transaction。
请注意,使用单独一个私钥不能使以太坊账户和 Substrate 账户直接兼容。关于以太坊帐户、密钥映射到 Substrate 帐户、密钥的信息,请参见 Moonbeam 文档中的 Unified Accounts。
以太坊指定的运行时APIs和RPCs
运行时存储所有可以查询的 Ethereum-formatted 的信息。你可以调用运行时并使用节点 RPC 服务器、运行时 API 和 RPC 客户端调用检索该信息。