Hardhat本地测试Chainlink VRFV2:fulfillRandomWords未触发问题排查
问题解答
1. 本地测试Chainlink VRF完全支持
通过官方提供的VRFCoordinatorV2Mock合约,就能在Hardhat本地环境模拟VRF协调器的完整行为,无需连接主网或测试网。
2. 你可能遗漏的关键细节
- 未手动触发mock的回调:本地mock不会自动执行
fulfillRandomWords回调,必须在测试代码里主动调用该方法,模拟链上协调器的触发逻辑。 - 订阅流程不完整:没创建VRF订阅、未将NFT合约添加为订阅消费者、未给订阅充值LINK(mock中可直接调用
fundSubscription模拟)就发起随机数请求。 - 参数或权限错误:请求随机数时传入的keyHash/subscriptionId等参数不符合要求,或者NFT合约未正确继承
VRFConsumerBaseV2,导致fulfillRandomWords被权限修饰符拦截。 - 未捕获请求ID:测试中没正确获取请求随机数时返回的requestId,导致后续无法调用mock的
fulfillRandomWords。
3. 正确的本地测试步骤
第一步:部署并初始化mock与订阅
在测试代码中完成以下操作:
// 1. 部署VRFCoordinatorV2Mock,baseFee和gasPriceLink设为0即可 const VRFCoordinatorV2Mock = await ethers.getContractFactory("VRFCoordinatorV2Mock"); const vrfCoordinatorMock = await VRFCoordinatorV2Mock.deploy(0, 0); await vrfCoordinatorMock.deployed(); // 2. 创建VRF订阅 const createTx = await vrfCoordinatorMock.createSubscription(); const createReceipt = await createTx.wait(); const subscriptionId = createReceipt.events[0].args.subId; // 3. 将你的NFT合约添加为订阅消费者 await vrfCoordinatorMock.addConsumer(subscriptionId, nftContract.address); // 4. 给订阅充值LINK(本地mock无需真实转账,直接调用fundSubscription) await vrfCoordinatorMock.fundSubscription(subscriptionId, ethers.utils.parseEther("10"));
第二步:发起请求并触发回调
// 1. 调用NFT合约的随机数请求方法,获取requestId const requestTx = await nftContract.requestRandomWords(); // 假设你的合约封装了该逻辑 const requestReceipt = await requestTx.wait(); const requestId = requestReceipt.events[0].args.requestId; // 从事件中提取requestId // 2. 手动触发mock的回调,这是本地测试的核心 await vrfCoordinatorMock.fulfillRandomWords(requestId, nftContract.address); // 3. 验证结果:检查合约状态或控制台日志,确认fulfillRandomWords已执行
合约代码注意事项
- 确保NFT合约正确继承
VRFConsumerBaseV2,且fulfillRandomWords函数带有override关键字 fulfillRandomWords仅保留基类的onlyCoordinator修饰符,不要额外添加不必要的权限限制- 本地测试时keyHash可使用任意合法bytes32值(如
0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15),mock不会校验该值的有效性
内容的提问来源于stack exchange,提问作者user20313416
相关产品推荐
相关产品推荐

