- 译文出自:登链翻译计划[1]
- 译者:翻译小组[2]
- 校对:Tiny 熊[3]
Ganache 是以太坊开发领域的先驱,自 2016 年以来帮助 DApp 开发者和爱好者构建、测试和探索区块链。我们很高兴地宣布最新版本的 Ganache 发布了,分叉(fork)性能提高了 30 倍,并与 Infura 整合,允许你免费访问存档数据,重放历史交易。
也许你还不不熟悉 Ganache,Ganache 是一个用与本地开发的区块链,用于在以太坊区块链上开发去中心化的应用程序。Ganache 模拟了以太坊网络,你可以在发布到生产环境之前看到你的 DApp 将如何执行。
在以太坊网络上开发去中心化应用,通常的方式是设置一个以太坊客户端,如 Geth 或 OpenEthereum,为你提供以太坊虚拟机(EVM)[4]环境。
虽然这是一个在以太坊上开发去中心化应用的好方法,但它不是最有效和最友好的方法,因为你需要手动配置这些客户端并保持运行。维护一个自我托管的节点可能是昂贵和耗时的,你不希望在开发过程中花费宝贵的时间来排查一个失败的节点。
有了 Ganache,你所需要做的就是启动应用程序,你就有一个预先配置好的以太坊客户端,有 10 个预先存款和解锁的账户可以使用。这使你能够在整个开发周期内快速测试你的 DApp。
Ganache 7:分叉提高 30 倍速度和操作也更快
许多在以太坊上构建的 Web3 开发者已经使用 Ganache 在他们的本地环境中分叉和测试智能合约,以便在部署前获得信心。利用从以前的迭代中获得的经验,我们从头开始重写了 Ganache,任务是让这个区块链模拟器工具更加灵活、快速和稳定。
我们听到了你们关于 Ganache v6 安装缓慢,运行缓慢,并且泄露内存的反馈。它还没有使用现代语言特性和开发人员今天使用的范式,如 TypeScript 类型和 Promise 抽象。Ganache v6 的架构使得测试、修复错误和添加功能变得困难和费时。
Ganache v7 如何更好?
- 凭借最新版本的高级缓存功能,Ganache 的分叉功能(如:fork 主网 )比 v6 快 30 倍。
- 零配置的主网分叉, Ganache v7 有一个与 Infura 的原生集成[5],可以免费访问历史数据
- 你可以无限期地运行 Ganache,而不会遇到因内存问题而崩溃的情况
- 普通操作比 v6 快 3 倍左右。
安装和设置 Ganache 7
Ganache 可以用多种方式使用:包括作为命令行工具,通过 Node.js 进行编程,或在浏览器中使用。请看下面的说明,为所有这些使用情况安装和使用 Ganache 7。
A. 在命令行上使用 Ganache 7
要在命令行上运行 Ganache 7,你的电脑上必须安装 Node.js >= v12.0.0 和 NPM >= 6.4.1。参见here[6]下载适合你的操作系统的最新版本,或者使用 nvm 来管理你的Unix[7]或Windows[8]的 Node 安装。
在安装了 Node.js 和 NPM 之后,你可以通过运行npm install ganache --global
来全局安装 Ganache 7。一旦安装完毕,你可以在命令行的任何地方运行ganache
。
你的终端应该看起来像这样。
screenshot-1
默认情况下,Ganache 提供了 10 个测试账户,每个账户有 1000 个(假)以太币,以及相应的私钥和用于生成私钥的助记词。在开发过程中,你可以使用这个助记词将账户导入到MetaMask[9]等钱包。
我们可以在启动 Ganache 7 时通过指定选项来覆盖所有的默认值;例如,我们可以通过提供私钥与账户余额的映射来对账户创建进行更多的控制,就像这样:
代码语言:javascript复制ganache --wallet.accounts "0xfd485338e322f5930f7cf475f385341ec88bfc4f8a0a16f30b2fb417d1bb5427, 1000000000000000000000" "0x05bba0b9f7a251080aa23feee4eab3f75a1abee905c0271008c93e5d2e2e7541, 10000000000000000000000"
我们还可以指定一个助记词组来推导所有的初始账户,一个矿工 Gas 价格,以及区块 Gas 限制。例如:
代码语言:javascript复制ganache --miner.defaultGasPrice 200 --miner.blockGasLimit 90071 --miner.callGasLimit 898989 --wallet.mnemonic "alarm cause brave super lab glide awake hunt rose win sugar idea"
运行命令ganache --help
可以获得所有 Ganache 的可用选项的列表。
我们也可以使用npm install ganache
将 ganache 安装到本地的 Node.js 项目中,不使用--global
标志,然后将其添加到项目的 package.jsonscripts
中,例如,"scripts":{"ganache": {"ganache --mnemonic <12 words mnemonic>"}
。
B. 以编程方式使用 Ganache 7
Ganache 7 可以在你的 Node.js 项目中以编程的方式使用, 如作为:
- 一个独立的 EIP-1193 提供者。
- 一个 JSON-RPC 服务器和 EIP-1193 提供者。
- 一个 web3.js 提供者。
- 一个 ethers.js 提供者。
请看下面这些不同使用场景的代码示例。
首先,将 Ganache 7 作为 npm 包安装在你的 Node.js 项目中
代码语言:javascript复制$ npm install ganache
作为一个独立的 EIP-1193 提供者:
代码语言:javascript复制const ganache = require("ganache");
const options = {};
const provider = ganache.provider(options);
const accounts = await provider.request({ method: "eth_accounts", params: [] });
...
作为一个 JSON-RPC 网络服务器和 EIP-1193 提供者:
代码语言:javascript复制const ganache = require("ganache");
const options = {};
const server = ganache.server(options);
const PORT = 8545;
server.listen(PORT, err => {
if (err) throw err;
console.log(`ganache listening on port ${PORT}...`);
const provider = server.provider;
const accounts = await provider.request({ method: "eth_accounts", params:[] });
});
...
作为一个 Web3.js 提供者
代码语言:javascript复制const Web3 = require("web3");
const ganache = require("ganache");
const web3 = new Web3(ganache.provider());
...
作为 Ethers.js 的提供者
代码语言:javascript复制const ganache = require("ganache");
const provider = new ethers.providers.Web3Provider(ganache.provider());
C. 在浏览器中使用 Ganache 7
你可以在浏览器中使用 Ganache 7,在你的 HTML 代码中加入以下脚本标签。
代码语言:javascript复制<script src="https://cdn.jsdelivr.net/npm/ganache@7.0.0/dist/web/ganache.min.js"></script>
通过这样做,Ganache 7 就会自动在你的浏览器中供你使用。
代码语言:javascript复制const options = {};
const provider = Ganache.provider(options);
同样,请参阅这里[10],了解你可以传入的可用选项的清单。
Ganache 7 新功能
1. 零配置的主网分叉
Ganache 支持开箱即用的主网分叉,无需任何配置,允许你在本地机器上模拟拥有与以太坊主网相同的状态。
这带来了许多可能性;例如,你可以在开发过程中与真实世界的协议/合约进行本地交互,通过,并在本地调试主网交易(使用`truffle debug`[11]),允许对查看合约调用细节。
这里有[12]2016 年 Ganache 团队使用主网分叉功能来演示DAO 黑客攻击[13]。
要使用这个功能,使用ganache --fork
命令启动 Ganache 7。Ganache 默认使用Infura[14]作为其引擎的提供者,但你也可以通过传递一个 URL 来指定一个提供者;例如,你可以通过运行这个命令使用你自己的 Infura URL。
$ ganache --fork.url wss://mainnet.infura.io/ws/v3/<PROJECT ID>
Ganache 默认从最新的区块中回退五个区块,以避免因重新排序而丢失区块。
这是一个可配置的行为;你可以使用--fork.blockNumber <BLOCK NUMBER>
或者通过设置--fork.preLatestConfirmations 0
来指定你想要分叉的确切块。
2. 分叉任何以太坊测试网络,无需等待同步时间
除了能够以零配置分叉以太坊主网络外,Ganache 还允许你从任何以太坊测试网络分叉,包括 Ropsten、Kovan、Rinkeby 和 Görli。
你可以通过运行带有网络选项的 fork 命令来做到这一点:ganache -- fork.network <NETWORK NAME>
。很酷,是吗?下面是 Rinkeby 测试网的分叉情况。
screenshot-2
3. 支持大规模交易追踪(超过 10GB 以上)
Ganache 使用debug_traceTransaction
RPC 方法支持大规模交易追踪。
要使用这个功能,需要从 Mainnet(或任何测试网络)中分叉出一个比你要追踪的交易高一个区块号的参数启动 Ganache;例如,如果你想追踪一个在区块 13,886,877 内的交易,你需要在区块号 13,886,878 处启动 Ganache。
代码语言:javascript复制$ ganache --fork.network mainnet --fork.blockNumber <blockNumber>
然后使用 debug_traceTransaction 方法发送一个 curl 请求,指定交易哈希值,像这样:
代码语言:javascript复制$ curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "id": 1, "method": "debug_traceTransaction", "params": [ "<TRANSACTION HASH>" ] }' http://localhost:8545
这将返回该交易的汇总信息,用于后处理。
用一个大的交易试试,比如0x8bb8dc5c7c830bac85fa48acad2505e9300a91c3ff239c9517d0cae33b595090
(Warp Finance 黑客)。
首先,启动 ganache(用大量的额外内存)。
代码语言:javascript复制$ NODE_OPTIONS=--max-old-space-size=16384 ganache --fork --fork.blockNumber 14037983
然后执行debug_traceTransaction
并将输出发送到 trace.json。
$ curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "id": 1, "method": "debug_traceTransaction", "params": [ "0x8bb8dc5c7c830bac85fa48acad2505e9300a91c3ff239c9517d0cae33b595090" ] }' http://localhost:8545 -o trace.json
如果你真的想测试一下可能的极限(并且有很多时间--大约 1-2 小时),试试 10GB 以上的 Cream Finance 黑客交易,0x0fe2542079644e107cbf13690eb9c2c65963ccb79089ff96bfaf8dced2331c92
!
4. 快照和还原状态
在区块链术语中,快照指的是捕捉和记录区块链在某个特定区块编号的状态的行为。快照是区块链在该特定区块的完整视图,包括所有现有地址及其相关数据,包括交易、费用、余额、元数据等。
在 Ganache 中,你可以使用evm_snapshot
RPC 方法对你的开发区块链(甚至是 Mainnet 的分叉)进行快照;evm_snapshot
不需要任何参数,它返回创建的快照的 ID。
Ganache 还支持使用evm_revert
RPC 方法将状态恢复到之前的快照,尽管一旦调用并成功恢复,你就不能再使用具有相应 ID 的快照,因为你只能恢复快照一次。
如果你需要多次恢复到同一个点,你应该考虑在每次 evm_revert 之后创建一个新的快照;这里有一个在 Ganache 中拍摄快照和恢复状态的演示。
代码语言:javascript复制const provider = ganache.provider();
const [from, to] = await provider.send("eth_accounts");
const startingBalance = BigInt(await provider.send("eth_getBalance", [from] ));
// take a snapshot
const snapshotId = await provider.send("evm_snapshot");
// send value to another account (over-simplified example)
await provider.send("eth_subscribe", ["newHeads"] );
await provider.send("eth_sendTransaction", [{from, to, value: "0xffff"}] );
await provider.once("message"); // Note: `await provider.once` is non-standard
// ensure balance has updated
const newBalance = await provider.send("eth_getBalance", [from] );
assert(BigInt(newBalance) < startingBalance);
// revert the snapshot
const isReverted = await provider.send("evm_revert", [snapshotId] );
assert(isReverted);
// ensure balance has reverted
const endingBalance = await provider.send("eth_getBalance", [from] );
const isBalanceReverted = assert.strictEqual(BigInt(endingBalance), startingBalance);
console.log({isBalanceReverted: isBalanceReverted});
5. 可即时、间隔或按需出块
Ganache 允许你配置在开发过程中配置按需出块;默认配置下,区块会在收到交易后立即被开采,但你也可以选择以下选项:
- 设置间隔时间出块。你可以通过
--miner.blockTime <TIME IN SECONDS>
选项来指定 Ganache 在开采下一个交易之前应该等待的时间(秒)。设置为 0 意味着 Ganache 会立即挖掘新的交易。 - 根据需要出块。Ganache 还公开了一个
evm_mine
的 RPC 方法,该方法强制开采一个区块,无论开采是在运行还是停止。如果 mempool 中没有交易存在,这将挖掘一个空块。请看下面的代码示例。
console.log("start", await provider.send("eth_blockNumber"));
await provider.send("evm_mine", [{blocks: 5}] ); // mines 5 blocks
console.log("end", await provider.send("eth_blockNumber"));
6. 快进时间
Ganache 还提供了两个 RPC 方法,用于操纵链上时间。
一个典型的使用场景是,智能合约要求在用户采取某些行动之前必须经过特定的时间;如果你不想等待的这段时间,你可以使用evm_increaseTime
将区块链当前的时间戳增加指定的秒(以十六进制传递)。
curl -H 'Content-Type: application/json' --data' {"jsonrpc": "2.0", "id": 1, "method": "evm_increaseTime", "params": ["0x15180"] }' http://localhost:8545
这将返回调整后的总时间,单位为毫秒。此外,你可以使用evm_setTime
来设置为特定的时间戳;它接受精度为毫秒的 JavaScript 时间戳(Unix epoch),并返回给定时间戳和当前时间之间的秒数。
curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "id": 1, "method": "evm_increaseTime", "params": ["0x15180"] }' http://localhost:8545
你应该谨慎使用这个方法,因为它允许你向后移动时间,这可能导致新区块出现在旧区块之前被开采,从而使区块链状态无效。
7. 冒充任何账户
Ganache 允许你在开发过程中冒充(Impersonate)另一个账户。这在与分叉功能一起使用时更加有趣;你可以分叉 Mainnet 并冒充任何账户。
下面是一个例子,你可以分叉 Mainnet,冒充一个账户,并发送一些代币给另一个账户。
- 通过分叉 Mainnet 并冒充(解锁)一个随机账户,启动 Ganache。
ganache --fork --wallet.unlockedAccounts <Account Address Here>
。 - 获取已解锁账户的余额:
curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "id": 1, "method": "eth_getBalance", "params": ["<Account Address Here>"] }' http://localhost:8545
. 这将返回以 WEI 编码的十六进制数字的余额。 - 从解锁的账户发送一些以太币到另一个账户:
curl -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0", "id": 1, "method": "eth_sendTransaction", "params": [{"from": "UNLOCKED ACCOUNT", "to": "RECEIVING ACCOUNT", "value": "AMOUNT TO SEND"}] }' http://localhost:8545
现在验证一下,解锁账户的余额是否减少了发送的以太数量。
向另一个账户发送以太币并不是唯一的使用场景,因为你可以冒充一个账户来调用智能合约中某些只属于所有者的功能,就像我们之前看到的 convex benchmark 合约那样。
8. 待定交易(pending)
在以太坊中,每个交易都有一个 nonce。nonce 是一个给定地址发送的所有交易数量,无论何时你发送一个交易,nonce 都会增加 1。
在早期版本的 Ganache 中,如果你发送的交易的 nonce 值比上一个 nonce 值大 1,Ganache 会出错,交易会被拒绝。
在 Ganache 7 中,如果前一个交易的 nonce 是 1,而你由于某种原因发送了一个 nonce 设置为 3 的交易,那么这个 nonce 为 3 的交易将在交易池中坐等一个 nonce 为 2 的交易被发送,届时这两个交易将被挖出并添加到区块链状态。
今天就开始使用 Ganache 7,只需运行npm install ganache --global && ganache --help
,或者查看v7 发行说明[15]。
这个版本已经酝酿了多年,我们对我们所做的工作感到非常自豪。我们希望你和我们一样喜欢它。
感谢每一个参与实现这个版本的人--贡献者、指导者、审查者、问题报告者和社区参与者都对 Ganache v7 的实现起到了重要作用。我们对你们所有人表示衷心感谢。
原文:https://trufflesuite.com/blog/introducing-ganache-7/
参考资料
[1]
登链翻译计划: https://github.com/lbc-team/Pioneer
[2]
翻译小组: https://learnblockchain.cn/people/412
[3]
Tiny 熊: https://learnblockchain.cn/people/15
[4]
以太坊虚拟机(EVM): https://ethereum.org/en/developers/docs/evm/
[5]
与Infura的原生集成: https://blog.infura.io/fork-ethereum-replay-historical-transactions-with-ganache-7-archive-support/?__hstc=223080836.c9727f43b80c5b842391f55bf687c7b5.1629084054657.1643006281910.1643361864575.6&__hssc=223080836.1.1643361864575&__hsfp=2608980517
[6]
here: https://nodejs.org/en/download/
[7]
Unix: https://github.com/nvm-sh/nvm
[8]
Windows: https://github.com/coreybutler/nvm-windows
[9]
MetaMask: https://metamask.io/
[10]
这里: https://github.com/trufflesuite/ganache#readme
[11]
truffle debug
: https://trufflesuite.com/docs/truffle/getting-started/using-the-truffle-debugger
[12]
这里有: https://www.reddit.com/r/ethereum/comments/4yd1o4/testrpc_teaser_instantaneous_forking_coming_soon/
[13]
DAO黑客攻击: https://www.gemini.com/cryptopedia/the-dao-hack-makerdao
[14]
Infura: https://infura.io/docs?__hstc=223080836.c9727f43b80c5b842391f55bf687c7b5.1629084054657.1643006281910.1643361864575.6&__hssc=223080836.1.1643361864575&__hsfp=2608980517
[15]
v7发行说明: https://github.com/trufflesuite/ganache/releases/tag/v7.0.0