我有一个本地的硬汉节点,简单地呈现为:
npx hardhat节点
我有一个智能合约代码,我想测试,该代码以简单的循环测试100个NFT。该代码基本上将地址添加到地图中,并以相当标准的方式调用openzeppelin的 _safemint
函数。
但是,在我的测试中,运行此功能需要几秒钟的时间,对于循环而言,这有点太多了。我已经尝试从Hardhat配置启用/禁用自动启动,但似乎并没有改变任何内容。
我需要在测试中为许多迭代(10000)运行此功能,因此呼叫的持续时间是不可接受的。我也使用M1 Max,所以我怀疑是我的CPU是100次循环的瓶颈,这可能需要一些纳秒。
如何使HardHat更快地执行合同代码?
(固体 ^0.8.0,HardHat 2.8.2)
I have a local hardhat node spawned simply as:
npx hardhat node
I have a smart contract code that I want to test that mints 100 NFTs with a simple loop. The code basically adds the address to a map and calls OpenZeppelin's _safeMint
function in a pretty standard manner.
However, in my tests it takes a few seconds to run this function, which is a bit too much for 100-iteration for loop. I've tried enabling/disabling autominting from Hardhat config but doesn't seem to change anything.
I will need to run this function for many iterations (10000) in my tests, so the duration of the call is unacceptable. I'm also on M1 Max so I doubt it's my CPU that's the bottleneck for a 100-iteration for loop which should probably take a few nanoseconds.
How can I make hardhat execute contract code faster?
(Solidity ^0.8.0, hardhat 2.8.2)
发布评论
评论(2)
下面的解决方案是一个黑客攻击,但是我在测试中大量使用了它的循环,最多可以进行5000次迭代,并且可以运行良好(仅需几分钟而不是使用自动化时)。它的要旨是禁用自动化和间隔开采,而是按需手动挖掘块。
The solution below is a hack, but I've used it extensively in my tests with for loops up to 5000 iterations and it can run just fine (takes only a couple minutes instead of hours when using automining). The gist of it is to disable automining and interval mining and instead manually mine the blocks on demand.
我将尝试以广义的方式回答您的问题,但是以与您的要求相关的顺序列出了这些方法。这是有关如何加快硬汉测试运行的指南:
1。使用更快的本地以太坊节点
hardhat提供的默认本地节点使用Ethereumjs EVM,这可以相对较慢。考虑切换到更快的本地节点以提高性能。
Anvil:高性能本地节点
anvil”> anvil 是本地为开发设计的以太坊节点。值得注意的是,它使用 revm ,一种在Rust中实现的EVM,以其性能而闻名。请参阅 ziyadedher/evm-bench 有关不同EVM实现的性能比较。
要将Anvil与Hardhat集成,有一个名为。建议设置
启动:false
和spawnanvil
在单独的外壳中手动使用以下命令进行操作:对于所有
Anvil 选项请参见: https://book.get.get.getfoundry.sh/reference/reference/anvil/anvil/#options
此外,您可以通过使用
eth_sendunsignedtransaction
方法来节省一些时间,该方法接受与eth_call
:2。 peaverally parallel test测试 相同的参数。执行
执行。并行运行测试可以大大减少总体执行时间,尤其是如果您拥有多核CPU。
步骤:
- 并行
标志:在
并行:true
。Mocha的并行执行同时在单独的文件中运行测试。因此,为了最大化此功能,如果您对给定的测试功能有多个测试用例(例如,基于属性的测试),则可以在多个文件上分发/划分这些测试用例。
步骤:
创建多个重复测试文件,命名
test-foo- {i} .spec.ts
其中{i}
是文件编号。在这些文件中平均将测试用例划分。为此自动化:
确保您的测试用例得到了优化:
NB:如果您使用的是hardhat local节点(例如
Anvil
)以外的本地节点单独的帐户集,以避免非CE碰撞。当使用hardhat -parallel
时,这不是问题,而硬窃是配置的网络,因为HardHat可能会为每个测试脚本催生多个硬式节点,或者可能不检查交易nonces。3。将测试逻辑卸载到坚固性:
而不是在打字稿中实现复杂的测试逻辑,而是考虑使用Helper Solidity合同来封装和执行该逻辑。
:
步骤 创建助手合同:编写固体测试合同,以模拟您要测试的操作。例如,如果您要测试令牌传输,则测试合同可以在一个功能中管理多个转移。
b。 与助手相互作用:在您的打字稿测试中,与此助手合同进行部署和互动,而不是发送多个单独的交易。
c。 批处理操作:使用助手合同将多个操作分解为单个交易。
好处:
4。指定
Gaslimit
和GASPRICE
:通过手动指定这些值,您可以避免
eth_estimategas
和eth_gas_gasprice
呼叫。为了避免由于太低而导致的交易失败,请谨慎设置这些值足够高。用法:
您也可以考虑在 hardhat网络config 中使用
BlockGaslimit
,gas
和gasprice
字段。5。快照&还原(并使用固定装置):
快照和还原可让您在给定点捕获整个区块链的状态,并随意恢复到该状态。
用法:
如何实施:
福利:
具有固定装置的自动快照:
使用 loadfixture 自动化和恢复快照的过程。
6.优化打字稿代码:
编写打字稿测试的方式可能会影响测试执行时间。以下是一些优化
:批处理交易:
如果交易顺序并不关键,请同时发送它们。您也可以为
eth_call
请求执行此操作,当调用view> view
函数或静态函数的状态函数。b。缓存结果:
如果您反复从区块链中获取相同的数据,请考虑在变量中缓存。
c。限制链查询:
将不必要的查询减少到链条。如果可能,请计算或推断结果,而无需其他链查询。
7。连续集成(CI)改进
如果您使用诸如GitHub Action之类的CI/CD系统,请确保:
I'm going to try to answer your question in a generalised manner, however listing the methods in descending order of relevance to your requirement. Here's a guide on how to speed up your Hardhat test runs:
1. Use a Faster Local Ethereum Node
The default local node provided by Hardhat uses the ethereumjs EVM, which can be relatively slow. Consider switching to a faster local node for improved performance.
Anvil: A High-Performance Local Node
Anvil is a local Ethereum node designed for development. Notably, it uses the revm, an EVM implemented in Rust, which is known for its performance. See ziyadedher/evm-bench for a performance comparison of different EVM implementations.
To integrate Anvil with Hardhat, there's a plugin named hardhat-anvil. It's recommended to set
launch: false
and spawnanvil
manually in a separate shell which you can do using the following command:For a complete list of all
anvil
options see: https://book.getfoundry.sh/reference/anvil/#optionsAdditionally, you can save some time by disabling transaction signature verification using the
eth_sendUnsignedTransaction
method that accepts the same parameters aseth_call
:2. Leverage Parallel Test Execution
Hardhat supports Mocha's parallel test execution. Running tests in parallel can considerably reduce the overall execution time, especially if you have a multi-core CPU.
Steps:
--parallel
flag:parallel: true
in the Mocha section of your Hardhat config.Mocha's parallel execution runs tests in separate files concurrently. Therefore, to maximize this feature, if you have multiple test cases(e.g. for a kind of property-based test) for a given test function you can distribute/partition these test cases across multiple files.
Steps:
Create multiple duplicate test files, for example, named
test-foo-{i}.spec.ts
where{i}
is the file number.Partition your test cases equally among these files. To automate this:
Ensure that your test cases are optimized:
NB: If you're using a local node other than the hardhat local node(e.g.
anvil
) then when usinghardhat --parallel
you must ensure that each file is using a separate set of accounts to avoid nonce collisions. This isn't an issue when usinghardhat --parallel
with hardhat being the configured network as hardhat likely spawns multiple hardhat nodes for each test script or maybe doesn't check the transaction nonces.3. Offloading Test Logic to Solidity:
Instead of implementing complex test logic in TypeScript, consider using helper Solidity contracts to encapsulate and execute that logic.
Steps:
a. Create Helper Contract: Write Solidity test contract/s that mimics the operations you want to test. For example, if you're testing token transfers, the test contract could manage multiple transfers in one function.
b. Interact with Helper: In your TypeScript tests, deploy and interact with this helper contract instead of sending multiple individual transactions.
c. Batch Operations: Use the helper contract to batch multiple operations into single transactions.
Benefits:
4. Specifying
gasLimit
andgasPrice
:By manually specifying these values, you can avoid the overhead of
eth_estimateGas
andeth_gasPrice
calls. To avoid transactions failing due to a too low override be careful to set these values sufficiently high.Usage:
You could also consider setting this globally in the hardhat network config using the
blockGasLimit
,gas
andgasPrice
fields.5. Snapshotting & Restoring (and Using Fixtures):
Snapshotting and restoring allow you to capture the entire state of the blockchain at a given point and revert to that state at will.
Usage:
How to Implement:
Benefits:
Automate Snapshots with Fixtures:
Use loadFixture to automate the process of taking and restoring a snapshot.
6. Optimize TypeScript Code:
The way your TypeScript tests are written can impact the test execution time. Here are some optimizations:
a. Batch Transactions:
If the order of transactions isn't critical, send them simultaneously. You can also do this for
eth_call
requests when callingview
functions or staticcalls to stateful functions.b. Cache Results:
If you're repeatedly fetching the same data from the blockchain, consider caching it in a variable.
c. Limit Chain Queries:
Reduce unnecessary queries to the chain. If possible, calculate or infer results without additional chain queries.
7. Continuous Integration (CI) Improvements
If you use a CI/CD system like GitHub Actions, ensure: