原文作者:PaperMoon团队
Chopsticks 由 Acala Foundation 开发,是一款面向 Polkadot SDK(Substrate)生态链开发者的多功能工具。借助 Chopsticks,你可以在本地直接 分叉(fork)线上运行的链,并在不部署到真实网络的前提下完成一系列高效的调试与实验,例如:
• 在本地复刻某条主网/测试网的状态(Fork live chains locally)
• 回放区块(replay blocks)并分析区块内的 extrinsics(交易/调用)
• 模拟复杂场景,比如 XCM 跨链交互(无需上链实测)
本指南将带你完成 Chopsticks 的安装,并说明如何配置本地 fork 环境。通过"本地分叉 + 可控回放 + 可编排场景",Chopsticks 能显著提升测试效率,帮助你在 Polkadot 生态中更快迭代链上功能。
如需更多支持与信息,可通过 GitHub Issues 进行反馈和提问。
重要提示(Warning)
Chopsticks 底层使用 Smoldot 轻客户端(light client),而 Smoldot 只支持原生 Polkadot SDK API。因此,基于 Chopsticks 运行的 fork 环境 不支持 Ethereum JSON-RPC 调用。
这意味着:
• 你无法用 Chopsticks fork 一条链后,再用 Metamask 去连接它(因为 Metamask 依赖以太坊 JSON-RPC)。
如果你的使用场景依赖 EVM JSON-RPC(如 Metamask、Hardhat、ethers.js 直接连 RPC),需要使用其他方案或额外的 RPC 层,而不是单纯依赖 Chopsticks fork。
前置条件
开始之前,请确保你的环境已安装:
• Node.js
• 包管理器:npm(默认随 Node.js 安装)或 Yarn
安装 Chopsticks
你可以选择 全局安装或在项目中 本地安装。请根据你的开发习惯选择:
本文档说明的是 Chopsticks 1.2.5 版本的功能与用法。请确保你使用的版本与本文一致,以免出现参数或行为差异。
1)全局安装(Global Installation)
全局安装后,你可以在任何项目中直接使用 chopsticks 命令:
npm i -g @acala-network/chopsticks@1.2.5
安装完成后,你应该能在终端直接运行 chopsticks。
2)本地安装(Local Installation)
如果你只希望在某一个项目中使用 Chopsticks,推荐采用本地安装方式:
1)创建目录并初始化 Node.js 项目:
mkdir my-chopsticks-project
cd my-chopsticks-project
npm init -y
2)安装 Chopsticks 依赖:
npm i @acala-network/chopsticks@1.2.5
3)使用 npx 运行 Chopsticks,并查看帮助信息:
Go
npx @acala-network/chopsticks --help
配置 Chopsticks
运行 Chopsticks 之前,需要配置一些关键参数。你可以通过以下两种方式提供配置:
• 配置文件(Configuration File)
• 命令行参数(CLI Flags)
Chopsticks 支持的可配置参数包括:
• genesis:用于构建 fork 的平行链 raw genesis 文件链接(用于替代 endpoint)
• timestamp:从哪个时间点对应的区块开始 fork
• endpoint:要 fork 的平行链节点 endpoint(通常为 WebSocket)
• block:指定从哪个区块高度或区块哈希开始回放/构建 fork
• wasm-override:指定要使用的 runtime Wasm 路径(替代 endpoint 提供的 runtime)
• db:本地数据库文件路径(用于存储 fork 的链状态)
• config:配置文件的路径或 URL
• port:对外暴露服务的端口
• build-block-mode:fork 环境下区块的构建模式:batch / manual / instant
• import-storage:预定义 JSON/YAML 存储覆盖文件,用于覆盖 fork 链上的 storage
• allow-unresolved-imports:使用 Wasm 构建链时,是否允许存在未解析的 imports
• html:生成区块之间 storage diff 的 HTML 预览
• mock-signature-host:启用签名 mock:任何以 0xdeadbeef 开头且用 0xcd 填充的签名都视为合法
实际使用中,最常用的是:endpoint / block / db / build-block-mode / import-storage / mock-signature-host。
配置文件方式
Chopsticks 的源码仓库提供了一组可复用的 YAML 配置文件,可用于在本地快速启动多种 Polkadot SDK 链的 fork。你可以从仓库的 configs 目录下载这些配置文件。
以下是一个 Polkadot 的配置文件示例:
Go
endpoint:
- wss://rpc.ibp.network/polkadot
- wss://polkadot-rpc.dwellir.com
mock-signature-host: true
block: ${env.POLKADOT_BLOCK_NUMBER}
db: ./db.sqlite
runtime-log-level: 5
import-storage:
System:
Account:
- - - 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY
- providers: 1
data:
free: '10000000000000000000'
ParasDisputes:
$removePrefix: ['disputes'] # those can makes block building super slow
配置文件的能力说明
• 配置文件允许你通过"重写 storage"的方式修改 fork 网络的状态,即指定:
• Pallet 名称
• 存储项(storage item)路径
• 目标值
• 上述示例将 Alice 的 System.Account 存储修改为:free 余额为 10000000000000000000。
• 同时示例还通过 ParasDisputes 的 $removePrefix 移除部分争议数据(disputes),避免这些数据导致区块构建非常慢(这是一个典型的性能优化手段)。
简而言之:你不仅能 fork 线上状态,还能在 fork 的基础上"定制链状态",用于复现实验条件。
命令行参数方式(CLI Flags)
如果你更倾向于命令行操作,Chopsticks 也支持通过 CLI flags 配置所有参数(genesis 与 timestamp 除外)。
这种方式适用于:
• 临时试验、快速切换 endpoint 或区块高度
• 脚本化自动执行(CI / 本地脚本)
WebSocket 控制命令
Chopsticks 内置了一个 WebSocket 服务,提供一组特殊的 RPC 方法,用于直接操控本地 fork 的链行为(例如造块、改 storage、时间旅行等)。
下面是常用方法与参数说明。
1)dev_newBlock (newBlockParams):生成新区块
用于生成一个或多个新区块。
参数:newBlockParams: NewBlockParams
其中 NewBlockParams 包含:
• count(number):要生成的区块数量
• dmp({ msg: string, sentAt: number }[]):要包含的 downward message
• hrmp(Record<string | number, { data: string, sentAt: number }[]>):要包含的 horizontal message
• to(number):指定生成到哪个区块高度
• transactions(string[]):要包含在新区块中的交易(extrinsics)
• ump(Record<number, string[]>):要包含的 upward message
• unsafeBlockHeight(number):用指定高度构建区块(不安全选项)
2)dev_setBlockBuildMode (buildBlockMode):设置造块模式
用于设置本地 fork 的造块模式。
BuildBlockMode 可选值:
Go
export enum BuildBlockMode {
Batch = 'Batch', /** 默认:每批生成一个区块 */
Instant = 'Instant', /** 每笔交易立刻生成一个区块 */
Manual = 'Manual', /** 仅在手动触发时生成 */
}
3)dev_setHead (hashOrNumber):设置链头(Head)
将本地链的 head 设置为指定的区块哈希或高度。
参数:
• hashOrNumber:string | number(区块 hash 或区块高度)
4)dev_setRuntimeLogLevel (runtimeLogLevel):设置 Runtime 日志级别
用于调整 runtime 的 log level,便于调试 runtime 内部行为。
参数:
• runtimeLogLevel:number
5)dev_setStorage (values, blockHash):创建或覆盖任意存储值
可以在本地 fork 中直接修改 storage(非常适合快速构造测试场景)。
参数:
• values:object,JSON 对象,结构类似 storage 路径
• blockHash:string,在哪个区块 hash 上设置该 storage
6)dev_timeTravel (date):时间旅行(修改区块时间)
将当前区块时间设置为指定日期/时间点。之后产生的区块时间会从该时间点开始顺序推进。
参数:
• date:string,可以是时间戳或日期字符串
• 例如:2030-08-15T00:00:00
WebSocket 调用示例(Examples)
下面是文档给出的示例代码(保持原样,便于复制使用)。
示例 1:生成 1 个新区块(dev_newBlock)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
await api.rpc('dev_newBlock', { count: 1 });
}
main();
示例 2:设置造块模式为 Instant(dev_setBlockBuildMode)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
await api.rpc('dev_setBlockBuildMode', 'Instant');
}
main();
示例 3:将 Head 设置到区块高度 500(dev_setHead)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
await api.rpc('dev_setHead', 500);
}
main();
示例 4:设置 Runtime 日志级别(dev_setRuntimeLogLevel)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
await api.rpc('dev_setRuntimeLogLevel', 1);
}
main();
示例 5:修改账户 storage(dev_setStorage)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
import { Keyring } from '@polkadot/keyring';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
const keyring = new Keyring({ type: 'ed25519' });
const bob = keyring.addFromUri('//Bob');
const storage = {
System: {
Account: [[[bob.address], { data: { free: 100000 }, nonce: 1 }]],
},
};
await api.rpc('dev_setStorage', storage);
}
main();
示例 6:时间旅行到 2030-08-15(dev_timeTravel)
Go
import { ApiPromise, WsProvider } from '@polkadot/api';
async function main() {
const wsProvider = new WsProvider('ws://localhost:8000');
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;
await api.rpc('dev_timeTravel', '2030-08-15T00:00:00');
}
main();
总结
通过 Chopsticks,你可以在本地复刻线上链状态,并通过内置 WebSocket 控制接口实现:
• 快速造块与回放
• 直接修改 storage 构造测试条件
• 调整 runtime 日志
• 控制时间推进以复现时间相关逻辑
• 为 XCM 等复杂场景提供可控实验环境
需要再次强调:由于 Chopsticks 基于 Smoldot,仅支持原生 Polkadot SDK API,不支持 Ethereum JSON-RPC,因此不能直接用于 Metamask 连接场景。
原文链接:https://docs.polkadot.com/parachains/testing/fork-a-parachain/