VestingWallet智能合约单元测试报‘header not found’错误求助
VestingWallet合约测试‘header not found’错误排查与解决
问题描述
基于OpenZeppelin实现自定义VestingContract合约,使用Truffle编写单元测试时,最后一个测试用例执行抛出header not found错误,需排查原因并解决。
合约代码
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; import "@openzeppelin/contracts/finance/VestingWallet.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract VestingContract is VestingWallet { constructor( address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds ) public VestingWallet(beneficiaryAddress, startTimestamp, durationSeconds) {} function getBalance() public view returns (uint256) { return address(this).balance; } function getBalanceFromToken(address _token) public view returns (uint256) { return IERC20(_token).balanceOf(address(this)); } }
测试代码
const VestingContract = artifacts.require("VestingContract"); const IoraContract = artifacts.require("Iora"); contract("VestingContract", function (accounts) { it("should assert true", async function () { await VestingContract.deployed(); return assert.isTrue(true); }); it("beneficiary and accounts[0] should be the same", async function () { const wallet = accounts[0]; const vestingInstance = await VestingContract.deployed(); const walletFromSmartContract = await vestingInstance.beneficiary(); return assert.isTrue(wallet === walletFromSmartContract) }); it("actual timestamp should be the high or the same when it was deployed", async function () { const vestingInstance = await VestingContract.deployed(); const vestingStarted = await vestingInstance.start(); const startTimestamp = Math.floor(Date.now() / 1000); return assert.isTrue(startTimestamp >= vestingStarted.toNumber()) }); it("balance from erc20 token should be the same on this contract balance", async function () { const vestingInstance = await VestingContract.deployed(); const ioraInstance = await IoraContract.deployed(); await ioraInstance.transfer(vestingInstance.address, 150); const ioraBalance = await ioraInstance.balanceOf(vestingInstance.address); const ioraTokenBalance = await vestingInstance.getBalanceFromToken(ioraInstance.address); return assert.isTrue(ioraBalance.toNumber() === ioraTokenBalance.toNumber()) }); it("total released should be the same as we transfered", async function () { const amount = 3000; const vestingInstance = await VestingContract.deployed(); const ioraInstance = await IoraContract.deployed(); await ioraInstance.transfer(vestingInstance.address, amount); await vestingInstance.release(ioraInstance.address); const releasedVesting = await vestingInstance.released(vestingInstance.address); return assert.isTrue(amount === releasedVesting.toNumber()) }); });
报错信息
1) Contract: VestingContract total released should be the same as we transfered: Error: Returned error: header not found at Context.<anonymous> (test/vesting_contract.js:47:51) at processTicksAndRejections (internal/process/task_queues.js:95:5)
错误原因分析
- 函数参数错误:最后一个测试用例中,
vestingInstance.released(vestingInstance.address)传入了错误参数。OpenZeppelin的VestingWallet合约中,released函数参数应为ERC20代币地址,而非vesting合约自身地址,参数错误会触发合约调用逻辑异常。 - 时间条件不满足:VestingWallet的释放逻辑依赖vesting周期,若测试时未快进时间至周期结束,
release操作无法释放全部代币,不仅断言会失败,还可能引发连锁调用异常。 - 测试环境问题:Truffle与Ganache版本不兼容、Ganache服务未正常启动,或
truffle-config.js网络配置错误,也会导致header not found这类通信错误。
解决方法
1. 修正函数参数
将released函数的参数改为代币实例地址:
const releasedVesting = await vestingInstance.released(ioraInstance.address);
2. 模拟vesting时间到期
使用Truffle时间工具快进时间至vesting周期结束,确保可全额释放代币:
const { time } = require("@openzeppelin/test-helpers"); it("total released should be the same as we transfered", async function () { const amount = 3000; const vestingInstance = await VestingContract.deployed(); const ioraInstance = await IoraContract.deployed(); // 获取vesting结束时间 const start = await vestingInstance.start(); const duration = await vestingInstance.duration(); const endTime = start.add(duration); await ioraInstance.transfer(vestingInstance.address, amount); // 快进时间至vesting结束 await time.increaseTo(endTime); await vestingInstance.release(ioraInstance.address); const releasedVesting = await vestingInstance.released(ioraInstance.address); return assert.isTrue(amount === releasedVesting.toNumber()) });
3. 确保测试环境正常
- 检查Ganache是否正常运行,端口与
truffle-config.js配置一致; - 升级Truffle和Ganache至兼容版本(推荐Truffle v5.x + Ganache v7.x);
- 每个测试用例使用全新合约实例,避免状态污染:
const vestingInstance = await VestingContract.new(accounts[0], Math.floor(Date.now()/1000), 3600);
内容的提问来源于stack exchange,提问作者Pedro Magalhaes
相关产品推荐
相关产品推荐

