Hardhat内置了Hardhat Network,这是一个为开发而设计的本地以太坊网络。它允许你部署合约,运行测试和调试代码。
@ethereumjs/vm EVM 实现, 与ganache、Remix和Ethereum Studio 使用的相同EVM。defaultNetwork为空或设置为 hardhat时,则Hardhat 默认在启动运行实例。--network一起使用。Hardhat Network可以以独立的方式运行,以便外部客户端可以连接到它。这可以是MetaMask、Dapp前端,或一个脚本。要以这种方式运行Hardhat Network,请运行:
npx hardhat node
它将启动Hardhat Network,并作为一个公开的JSON-RPC和WebSocket服务器。
然后,只要将钱包或应用程序连接到http://localhost:8545 。
如果你想把Hardhat连接到这个节点,你只需要使用--network localhost来运行命令。
Hardhat Network 拥有一流的Solidity支持。它总是知道哪些正在运行的智能合约,具体做什么,以及为什么失败。
如果一个交易或调用失败,Hardhat Network将抛出一个异常。 这个异常将组合 JavaScript 和 Solidity 栈追踪:从 JavaScript/TypeScript 开始的堆栈追踪,直到你 到合约的调用,并继续完整的 Solidity 调用堆栈。
这是一个使用 TruffleContract 的Hardhat Network异常的示例:
Error: Transaction reverted: function selector was not recognized and there's no fallback function
at ERC721Mock.<unrecognized-selector> (contracts/mocks/ERC721Mock.sol:9)
at ERC721Mock._checkOnERC721Received (contracts/token/ERC721/ERC721.sol:334)
at ERC721Mock._safeTransferFrom (contracts/token/ERC721/ERC721.sol:196)
at ERC721Mock.safeTransferFrom (contracts/token/ERC721/ERC721.sol:179)
at ERC721Mock.safeTransferFrom (contracts/token/ERC721/ERC721.sol:162)
at TruffleContract.safeTransferFrom (node_modules/@nomiclabs/truffle-contract/lib/execute.js:157:24)
at Context.<anonymous> (test/token/ERC721/ERC721.behavior.js:321:26)
最后两行对应的是执行失败交易的JavaScript测试代码。 其余的是 Solidity 堆栈跟踪。 这样你就能清楚地知道为什么测试没有通过。
Hardhat Network 总是知道你的交易或调用失败的原因,利用这些信息调试合约将更容易。
当一个交易无故失败时,Hardhat Network会在以下情况下创建一个明确的错误信息:
附加ETH调用一个非 payable 函数
发送ETH到一个没有可支付的回退或接收功能的合约上
在没有回退函数的情况下调用一个不存在的函数
用不正确的参数调用一个函数
调用一个没有返回正确参数数量的外部函数
在一个非合约账户上调用一个外部函数
由于外部调用的参数而无法执行(例如发送过多的ETH)。
没有使用 DELEGATECALL 调用库
不正确地调用预编译的合约
试图部署一个超过EIP-170规定的字节码大小限制的合约。
console.logHardhat Network 允许在 Solidity 代码中调用 console.log() 来打印日志信息和合约变量。你可以在样本项目中看到一个例子。按照 快速启动 中的步骤来尝试。
call调用和交易中都可以使用console.log。它在 view 函数中工作,但在 pure 函数中不起作用。
无论调用或交易是失败还是成功,都可以进行打印。
要使用它,你需要导入 hardhat/console.sol.
console.log 最多支持4 个参数,支持以下类型,顺序不限:
uintstringbooladdress还有上述类型的单参数API,以及额外的bytes, bytes1...直到bytes32类型:
console.logInt(int i)console.logUint(uint i)console.logString(string memory s)console.logBool(bool b)console.logAddress(address a)console.logBytes(bytes memory b)console.logBytes1(bytes1 b)console.logBytes2(bytes2 b)console.logBytes32(bytes32 b)console.log 实现了与Node.js的console.log相同的格式化选项,后者使用了util.format。
console.log("Changing owner from %s to %s", currentOwner, newOwner)可以和任何库一起工作: ethers.js, web3.js, waffle, truffle-contract, 等等.
console.log 是用标准的Solidity实现,然后在Hardhat Network中会检测到这些输出。这使得在任何其他工具也可以编译(如Remix、Waffle或Truffle)。
console.log 调用也可以在其他网络中运行,例如mainnet、kovan、ropsten等,但在这些网络中不起作用,但会花费少量的Gas。
Hardhat网络默认是空的,除了一些有初始余额的账户。但有时,拥有一个模拟主网状态的本地网络会更有用,这就是主网forking的作用。
要分叉主网,你需要连接一个URL连接到主网节点。例如,使用Alchemy,你可以用这个命令启动一个本地节点来分叉主网:
npx hardhat node --fork https://eth-mainnet.alchemyapi.io/v2/<key>
必须用你自己的Alchemy API密钥替换命令中的<key>。
完成之后,你可以在你的节点中做任何在Hardhat网络中做的事情:查看控制台日志,获得堆栈跟踪或使用默认账户来部署新的合约。
如果你想让这成为默认行为,你可以通过修改Hardhat配置来做到这一点:
networks: {
hardhat: {
forking: {
url: "https://eth-mainnet.alchemyapi.io/v2/<key>"
}
}
}
在此配置下,如果你执行一个使用Hardhat网络的任务,该任务将启动一个分叉的节点并在其上运行。
你还可以用分叉的Hardhat网络做其他事情,请查看指南以了解更多。
Hardhat支持两种交易的挖矿模式:
Automine(自动): 发送的每笔交易都会自动包含在一个新的区块中。
Interval mining(间隔挖矿): 定期挖一个新区块,其中包括尽可能多的待处理交易。
你可以使用其中的一种,也可以两种都用,或者两种都不用。在默认情况下,只有自动模式被启用。
你可以在Hardhat网络设置下配置挖矿模式:
networks: {
hardhat: {
mining: {
auto: false,
interval: 5000
}
}
}
在这个例子中,禁用了自动挖矿,间隔挖矿被设置为每5秒产生一个新的区块每。 你也可以将间隔挖矿配置为在随机延迟后生成一个新的区块:
networks: {
hardhat: {
mining: {
auto: false,
interval: [3000, 6000]
}
}
}
在这种情况下,一个新的区块将在3至6秒的随机延迟后被开采出来。 例如,第一个区块可能在4秒后被开采,第二个区块在5.5秒后被开采,以此类推。
你可以这样禁用前两种挖矿模式:
networks: {
hardhat: {
mining: {
auto: false,
interval: 0
}
}
}
这意味着Hardhat网络将不会开采新的区块,但你可以使用 evm_mine RPC 方法手动开采新区块。这将产生一个新区块,其中将包括尽可能多的待处理交易。
当automine(自动挖矿)被禁用时,每一个发送的交易都会被添加到mempool中,mempool中包含了所有未来可以开采的交易。 Hardhat网络的mempool遵循与geth相同的规则,这意味着:
你可以通过使用 pending 区块标签来获得将包括在下一个区块中的待处理交易列表:
const pendingBlock = await network.provider.send("eth_getBlockByNumber", ["pending", false])
你可以使用两个RPC方法(evm_setAutomine 和 evm_setIntervalMining)在运行时改变挖矿模式。
例如,要禁用自动挖矿
await network.provider.send("evm_setAutomine", [false])
并启用间隔挖矿:
await network.provider.send("evm_setIntervalMining", [5000])
Hardhat Network基于其跟踪基础设施提供丰富的日志记录,这将有助于开发和调试智能合约。
例如,一个成功的交易和一个失败的调用将看起来像这样:
eth_sendTransaction
Contract deployment: Greeter
Contract address: 0x8858eeb3dfffa017d4bce9801d340d36cf895ccf
Transaction: 0x7ea2754e53f09508d42bd3074046f90595bedd61fcdf75a4764453454733add0
From: 0xc783df8a850f42e7f7e57013759c285caa701eb6
Value: 0 ETH
Gas used: 568851 of 2844255
Block: #2 - Hash: 0x4847b316b12170c576999183da927c2f2056aa7d8f49f6e87430e6654a56dab0
console.log:
Deploying a Greeter with greeting: Hello, world!
eth_call
Contract call: Greeter#greet
From: 0xc783df8a850f42e7f7e57013759c285caa701eb6
Error: VM Exception while processing transaction: revert Not feeling like it
at Greeter.greet (contracts/Greeter.sol:14)
at process._tickCallback (internal/process/next_tick.js:68:7)
当使用Hardhat Network的节点(即npx hardhat node)时,默认启用日志功能,但当在进程中使用Hardhat Network提供者时,则禁用。
参见 Hardhat Network's config 以了解更多关于如何控制日志记录。
Hardhat Network默认用此状态初始化:
"test test test test test test test test test test test junk". 地址是:
0xf39Fd6e51aad88F6F4ce6aB8827279cffFb922660x70997970C51812dc3A010C7d01b50e0d17dc79C80x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC0x90F79bf6EB2c4f870365E785982E1f101E93b9060x15d34AAf54267DB7D7c367839AAf71A00a2C6A650x9965507D1a55bcC2695C58ba16FB37d819B0A4dc0x976EA74026E726554dB657fA54763abd0C3a0aa90x14dC79964da2C08b23698B3D3cc7Ca32193d99550x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f0xa0Ee7A142d267C1f36714E4a8F75612F20a797200xBcd4042DE499D14e55001CcbB24a551F3b9540960x71bE63f3384f5fb98995898A86B02Fb2426c57880xFABB0ac9d68B0B445fB7357272Ff202C5651694a0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C70970xcd3B766CCDd6AE721141F452C550Ca635964ce710x2546BcD3c84621e976D8185a91A922aE77ECEc300xbDA5747bFD65F08deb54cb465eB87D40e51B197E0xdD2FD4581271e230360230F9337D5c0430Bf44C00x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199若要定制,请看一下配置部分。
eth_accountseth_blockNumbereth_calleth_chainIdeth_coinbaseeth_estimateGaseth_gasPriceeth_getBalanceeth_getBlockByHasheth_getBlockByNumbereth_getBlockTransactionCountByHasheth_getBlockTransactionCountByNumbereth_getCodeeth_getFilterChangeseth_getFilterLogseth_getLogseth_getStorageAteth_getTransactionByBlockHashAndIndexeth_getTransactionByBlockNumberAndIndexeth_getTransactionByHasheth_getTransactionCounteth_getTransactionReceipteth_miningeth_newBlockFiltereth_newFiltereth_newPendingTransactionFiltereth_pendingTransactionseth_sendRawTransactioneth_sendTransactioneth_signTypedDataeth_signeth_subscribeeth_syncingeth_uninstallFiltereth_unsubscribenet_listeningnet_peerCountnet_versionweb3_clientVersionweb3_sha3hardhat_addCompilationResult – 添加关于编译合约的信息hardhat_impersonateAccount – 参考 Mainnet Forking guidehardhat_stopImpersonatingAccount – 参考 Mainnet Forking guidehardhat_reset – 参考 Mainnet Forking guidehardhat_setLoggingEnabled – 启用或禁用Hardhat网络的日志记录evm_increaseTime – 和 Ganache 里一样,增加区块时间。evm_mine – 和 Ganache 里一样,出块。evm_revert – 和 Ganache 里一样。evm_snapshot – 和 Ganache 里一样,快照区块。evm_setNextBlockTimestamp - 类似 evm_increaseTime, 但是在下一个区块里使用准确的时间戳出块。eth_compileLLLeth_compileSerpenteth_compileSolidityeth_getCompilerseth_getProofeth_getUncleByBlockHashAndIndexeth_getUncleByBlockNumberAndIndexeth_getUncleCountByBlockHasheth_getUncleCountByBlockNumbereth_getWorketh_hashrateeth_protocolVersioneth_signTransactioneth_submitHashrateeth_submitWorkHardhat Network可以运行任何智能合约,但它只理解Solidity 0.5.1和更新的版本。
如果你用旧版本的 Solidity 编译,或使用其他语言,你可以使用 Hardhat Network,但Solidity 堆栈跟踪将不会生效。
Hardhat Network可以与经过编译优化的智能合约一起工作。 但这可能会导致堆栈跟踪的行数有些偏差。
我们建议在测试和调试合约时,在没有优化的情况下编译合约。
← 配置项 从 Buidler 迁移 →