Chainlink VRF 提供了一种安全、透明、可验证的随机数生成方案,为区块链应用的公平性和可信度提供了强有力的支持。通过其订阅模型和密码学证明,开发者可以轻松集成随机性,满足游戏、NFT、抽奖等多种场景的需求。
<!--StartFragment-->
在区块链的去中心化应用中,随机性是一个常见但难以实现的需求。例如,区块链游戏需要随机决定战斗结果,NFT 项目需要随机分配稀有属性,去中心化抽奖需要公平选择获奖者。然而,传统的链上随机数生成方法(如使用 block.timestamp 或 blockhash)存在严重缺陷:这些值可被矿工或恶意节点预测和操纵,导致随机性不可靠,容易引发不公平或安全问题。此外,链上生成随机数的计算成本高,且无法提供可验证的公平性。
为解决这些问题,Chainlink 推出了 VRF(Verifiable Random Function,可验证随机函数)。Chainlink VRF 通过链下生成随机数并结合密码学证明,确保随机性既安全又可公开验证,同时避免了链上随机性生成的高成本和潜在攻击风险。这使得 VRF 成为区块链应用中实现公平、透明随机性的标准解决方案。
Chainlink VRF(Verifiable Random Function,可验证随机函数)是一种为区块链应用设计的可证明公平且防篡改的随机数生成器。它通过密码学手段确保随机数的生成过程安全、可验证且不可预测。Chainlink VRF 是区块链游戏、NFT 铸造、抽奖系统以及其他需要随机逻辑的去中心化应用的理想选择。
与传统的伪随机数生成器不同,这些方法容易受到矿工操纵,Chainlink VRF 提供了更安全、透明的随机数解决方案,广泛应用于区块链网络。
Chainlink VRF 的核心是一个两步流程:
Chainlink VRF 的应用场景非常广泛,以下是一些典型案例:
以下是如何在 Arbitrum Sepolia(或其他 EVM 兼容链)上集成 Chainlink VRF v2.5 的详细步骤:
安装环境:
准备 LINK 代币:用于支付 VRF 请求费用
创建订阅(部署的时候我会给出详细步骤图解 ):
以下官方展示如何使用 Chainlink VRF v2.5 生成随机数,获取家族名称的案例:
<!--EndFragment-->
pragma solidity 0.8.19;
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts@1.4.0/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts@1.4.0/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
// 使用随机数模拟掷20面骰子的Chainlink VRF消费者合约
contract VRFD20 is VRFConsumerBaseV2Plus {
// 表示骰子正在掷的状态
uint256 private constant ROLL_IN_PROGRESS = 42;
// 你的订阅ID
uint256 public s_subscriptionId;
// arbitrum-sepolia 网络的VRF协调者地址
address public vrfCoordinator = 0x5CE8D5A2BC84beb22a398CCA51996F7930313D61;
// 使用的gas通道,指定最大gas价格
bytes32 public s_keyHash =
0x1770bdc7eec7771f7ba4ffd640f34260d7f095b79c92d34a5b2551d6f6cfd2be;
// 回调函数的gas限制,存储每个随机数约需20000 gas
uint32 public callbackGasLimit = 40000;
// 请求确认数,默认为3
uint16 public requestConfirmations = 3;
// 请求的随机数数量,最大不超过 VRFCoordinatorV2_5.MAX_NUM_WORDS
uint32 public numWords = 1;
// 映射:请求ID到掷骰者地址
mapping(uint256 => address) private s_rollers;
// 映射:掷骰者地址到VRF结果
mapping(address => uint256) private s_results;
// 事件:骰子已掷出
event DiceRolled(uint256 indexed requestId, address indexed roller);
// 事件:骰子结果已返回
event DiceLanded(uint256 indexed requestId, uint256 indexed result);
// 构造函数,继承VRFConsumerBaseV2Plus
constructor(uint256 subscriptionId) VRFConsumerBaseV2Plus(vrfCoordinator) {
s_subscriptionId = subscriptionId;
}
// 请求随机数,模拟掷骰子
function rollDice(
address roller
) public onlyOwner returns (uint256 requestId) {
// 确保未掷过骰子
require(s_results[roller] == 0, "Already rolled");
// 请求随机数
requestId = s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: s_keyHash,
subId: s_subscriptionId,
requestConfirmations: requestConfirmations,
callbackGasLimit: callbackGasLimit,
numWords: numWords,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
);
s_rollers[requestId] = roller;
s_results[roller] = ROLL_IN_PROGRESS;
emit DiceRolled(requestId, roller);
}
// VRF协调者回调函数,返回随机数
function fulfillRandomWords(
uint256 requestId,
uint256[] calldata randomWords
) internal override {
// 计算20面骰子结果
uint256 d20Value = (randomWords[0] % 20) + 1;
s_results[s_rollers[requestId]] = d20Value;
emit DiceLanded(requestId, d20Value);
}
// 获取玩家的家族名称
function house(address player) public view returns (string memory) {
// 确保已掷骰子
require(s_results[player] != 0, "Dice not rolled");
// 确保掷骰完成
require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress");
return _getHouseName(s_results[player]);
}
// 根据ID获取家族名称
function _getHouseName(uint256 id) private pure returns (string memory) {
string[20] memory houseNames = [
"Targaryen",
"Lannister",
"Stark",
"Tyrell",
"Baratheon",
"Martell",
"Tully",
"Bolton",
"Greyjoy",
"Arryn",
"Frey",
"Mormont",
"Tarley",
"Dayne",
"Umber",
"Valeryon",
"Manderly",
"Clegane",
"Glover",
"Karstark"
];
return houseNames[id - 1];
}
}
访问 Chainlink VRF 订阅页面:
创建一个订阅账户的第一步(点击Create Subscription):交易请求
创建一个订阅账户的最后一步(自动弹出):请求签名
订阅账户创建成功可以看到:
点击进入你的订阅账户:复制 Subscription ID,部署合约要用到
部署合约:填入 Subscription ID
部署成功之后, 在你的订阅账户添加一个消费者:复制你的合约地址,然后点击 Add consumer ,确认交易请求
成功之后,添加 Link 代币做为费用支出,(因为每次请求随机数都要消耗 Link 代币) 点击 Fund subscription 后确认交易:
做完之后,你会看到消费者界面:
我们来掷色子,请求一下随机数:
OK,我们来验证结果,可以看到已经获取到了家族名称,证明随机数请求成功!
<!--StartFragment-->
合约继承:合约继承 VRFConsumerBaseV2Plus,这是 Chainlink 提供的基合约,用于处理 VRF 请求和回调
构造函数:初始化 VRF 协调器地址和订阅 ID
请求随机数:requestRandomNumber 函数向 VRF 协调器发送请求,指定 keyHash、订阅 ID、gas 限制等参数
接收随机数:fulfillRandomWords 是回调函数,由 VRF 协调器调用,将生成的随机数存储在 randomWords 变量中
参数说明:
<!--EndFragment--> <!--StartFragment-->
<!--EndFragment--> <!--StartFragment-->
以下是一个简单的 NFT 合约,展示如何使用 Chainlink VRF 为 NFT 分配随机属性:
<!--EndFragment-->
pragma solidity ^0.8.20;
import {VRFConsumerBaseV2Plus} from "@chainlink/contracts@1.4.0/src/v0.8/vrf/dev/VRFConsumerBaseV2Plus.sol";
import {VRFV2PlusClient} from "@chainlink/contracts@1.4.0/src/v0.8/vrf/dev/libraries/VRFV2PlusClient.sol";
import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract RandomNFT is ERC721, VRFConsumerBaseV2Plus {
address vrfCoordinator = 0x5CE8D5A2BC84beb22a398CCA51996F7930313D61;
uint256 s_subscriptionId;
uint32 callbackGasLimit = 200000;
uint16 requestConfirmations = 3;
uint32 numWords = 1;
bytes32 keyHash =
0x1770bdc7eec7771f7ba4ffd640f34260d7f095b79c92d34a5b2551d6f6cfd2be;
uint256 public tokenId;
mapping(uint256 => uint256) public tokenToAttribute;
constructor(
uint256 subscriptionId
) ERC721("RandomNFT", "RNFT") VRFConsumerBaseV2Plus(vrfCoordinator) {
s_subscriptionId = subscriptionId;
}
function mintNFT() external {
s_vrfCoordinator.requestRandomWords(
VRFV2PlusClient.RandomWordsRequest({
keyHash: keyHash,
subId: s_subscriptionId,
requestConfirmations: requestConfirmations,
callbackGasLimit: callbackGasLimit,
numWords: numWords,
extraArgs: VRFV2PlusClient._argsToBytes(
VRFV2PlusClient.ExtraArgsV1({nativePayment: false})
)
})
);
_safeMint(msg.sender, tokenId);
tokenId++;
}
function fulfillRandomWords(
uint256 /* requestId */,
uint256[] calldata randomWords
) internal override {
uint256 attribute = randomWords[0] % 100; // 生成 0-99 的随机属性
tokenToAttribute[tokenId - 1] = attribute;
}
}
<!--StartFragment-->
这里的合约我就不带着大家去操作了, 我已经私下操作成功,留给大家自由发挥,步骤跟前面是一样的,这里展示的是简单版本的NFT,如果你的NFT是有元数据的,那就随机元数据,利用好 requestId,使用基本是一样的,请大家灵活使用 <!--EndFragment--> <!--StartFragment-->
Chainlink VRF 提供了一种安全、透明、可验证的随机数生成方案,为区块链应用的公平性和可信度提供了强有力的支持。通过其订阅模型和密码学证明,开发者可以轻松集成随机性,满足游戏、NFT、抽奖等多种场景的需求。
截至 2025 年,Chainlink VRF 已在区块链生态中取得了显著成就。根据 Chainlink 官方数据,VRF 已处理超过 数百万次随机数请求,支持了数百个去中心化应用,涵盖 NFT 项目、区块链游戏和 DeFi 协议。这些应用利用 VRF 的公平性吸引了大量用户,推动了区块链生态的增长。例如,NFT 项目通过 VRF 实现的随机属性分配显著提升了用户信任和参与度。此外,Chainlink VRF 的多链支持使其成为跨链应用的首选随机性解决方案,覆盖以太坊、Arbitrum、Polygon、BNB Chain 等主流网络。
Chainlink VRF 的影响不仅体现在技术层面,还推动了区块链行业的标准化。它的可验证性和防篡改特性为去中心化应用的公平性树立了标杆,特别是在高价值的 NFT 和游戏领域。未来,随着区块链技术的进一步普及,Chainlink VRF 有望在更多领域(如元宇宙、去中心化治理、预测市场)发挥作用。Chainlink 团队也在不断优化 VRF 的性能,例如降低 gas 成本、支持更多链上场景,将进一步扩大其应用范围和影响力。
<!--EndFragment--> 官方文档: https://docs.chain.link/vrf/v2-5/getting-started
订阅VRF: https://vrf.chain.link/
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!