售罄锁定票位
系统确认本期有效票位数量,得到 drawTotal,并生成票号快照。
本页展示本期夺宝的开奖依据:随机数从哪里来,中奖票位怎么算出,链上交易如何核对。
本期开奖不是后台手动挑选中奖人。中奖位置由链上随机数和公开公式算出,任何人都可以用页面里的公开数据重新核对。
本期开奖分为锁定票号、获取链上随机数、按公式计算中奖票位、映射中奖票号四个环节。
从售罄到用户看到中奖结果,中间只有这 5 步。每一步都有对应的公开字段或校验项。
系统确认本期有效票位数量,得到 drawTotal,并生成票号快照。
票号快照根 ticketRoot 进入开奖请求,后续用来证明票池没有被替换。
合约请求 Chainlink VRF,产生 requestTxHash,等待随机数回调。
callbackTxHash 里会有 DrawFulfilled,包含 randomWord 和中奖计算字段。
用 randomWord % drawTotal + 1 得到 winningIndex,再从快照映射到中奖票号。
可信点不是“平台说通过”,而是用户能拿公开数据做同一套计算。
randomWord 来自 VRF fulfillment,不是平台开奖接口临时生成的数。
中奖票位只由 randomWord 和 drawTotal 决定,公式简单且可复算。
ticketRoot 对应售罄时的票号快照,避免随机数出来后再换票。
callbackTxHash 能在区块浏览器里找到 DrawFulfilled 事件。
复制验证包后,不登录平台的人也能核对公式和链上交易。
如果展示的 winningIndex 和公式结果不一致,页面校验会失败。
不需要会写代码,按这条路线看就够了;看不懂 Raw Logs 时再往下看高级排查。
先看这 4 个值就够了:3 个数负责复算中奖票位,交易 hash 负责证明随机数来自链上。
VRF 回调给出的原始随机数,平台不能提前知道,用它来算中奖位置。
售罄时封存的有效票位数量,本期只会在 1 到 drawTotal 之间抽一个位置。
公式算出的第几个票位中奖,不一定等于票号,后面还要通过票号快照映射到 winningTicket。
链上开奖回调交易 hash,用它在区块浏览器里找到 DrawFulfilled 事件。
链上验证不是重新生成随机数,而是确认官方开奖合约确实公开发出了这些事件和值。
本期要打开的是下面这个完整 Sepolia Etherscan 地址,它对应 callbackTxHash 回调交易,不是 Ethereum 主网浏览器,也不是 requestTxHash 请求交易。
优先看浏览器已经解码出的事件字段。字段顺序以合约事件为准:DrawFulfilled(bytes32 indexed roundKey, uint256 indexed requestId, uint256 randomWord, uint256 winningIndex, uint256 drawTotal, bytes32 ticketRoot)。
event name = DrawFulfilled
确认这是开奖完成事件,不是 DrawRequested 或其他合约的同名/相似日志。
address = drawCoordinator
事件发出地址要等于下方“官方开奖合约地址”。
roundKey
本期唯一开奖键,要和高级详情里的 roundKey 完全一致。
randomWord
链上 VRF 随机数,要和本页 randomWord 完全一致。
winningIndex
链上算出的中奖票位,要等于本页 winningIndex,也要等于公式复算结果。
drawTotal
开奖时锁定的总票位,要和本页 drawTotal 一致。
ticketRoot
售罄时封存的票号快照根,要和本页 ticketRoot 一致。
requestId
链上 VRF 请求编号,主要用于把请求交易和回调事件串起来。
同一笔回调交易里可能同时出现 Chainlink VRF Coordinator 的 RandomWordsFulfilled 和平台开奖合约的 DrawFulfilled。看到 outputSeed、payment、nativePayment、success、onlyPremium 时,说明你看到的是 Chainlink 的 fulfillment 事件;它证明 VRF 回调成功并记录扣费,不是最终开奖证明字段。
randomWord。
true 表示用原生币支付费用,例如 Sepolia ETH;false 通常表示用 LINK。
true 表示 Chainlink 回调 consumer 合约成功。
DrawCoordinator 合约,地址要等于本页的 drawCoordinator。
randomWord % drawTotal + 1 得到的中奖票位。
outputSeed/payment/nativePayment/success/onlyPremium,继续往下找,不要在这里停。DrawFulfilled,并确认事件发出地址等于官方 drawCoordinator。DrawFulfilled 里的 randomWord、winningIndex、drawTotal、ticketRoot。开奖链上会留下两笔关键交易和一个官方合约地址。普通用户重点看“回调交易”;“请求交易”和“开奖合约”用来证明流程前后能串起来。
先区分两个合约:DrawCoordinator 是平台自己的开奖合约,不是 Chainlink 的合约;Chainlink VRF Coordinator 才是 Chainlink 的随机数服务合约。核对开奖结果时,要看平台 DrawCoordinator 发出的 DrawFulfilled。
这是平台开奖合约向 Chainlink VRF 发起随机数请求的交易,表示本轮开奖在链上登记了“我要随机数”。
主要核对:交易成功、发出事件是 DrawRequested 或 VRF 请求相关事件,里面的 requestId 要能和回调交易里的 requestId 对上。
这是 Chainlink VRF 把随机数回传给平台开奖合约的交易,也是核对开奖结果最重要的一笔。
主要核对:在 Logs / Events 里找到平台合约发出的 DrawFulfilled,确认 randomWord、winningIndex、drawTotal、ticketRoot 与本页一致。
这是官方 DrawCoordinator 合约地址,不是一笔交易,也不是 Chainlink 地址。它用来确认事件确实由平台公开的开奖合约发出。
主要核对:回调交易里的 DrawFulfilled 事件发出地址,要等于这里的合约地址;不要把 Chainlink Coordinator 地址当成平台开奖合约。
如果浏览器没有合约 ABI,只显示 Topics 和 Data,也能核对。看不到 randomWord 字段名是正常的;它藏在 data 的第一段 32-byte 数据里。
这是 EVM Event 的标准编码规则,不是平台故意把字段切开。带 indexed 的字段会进入 topics,没有 indexed 的字段会按 ABI 顺序进入 data。
0x6fd04d048ef95eaca3a3264e7ee31b2107559ecaceab3f85c585b60f5810732a,代表 DrawFulfilled(bytes32,uint256,uint256,uint256,uint256,bytes32)。
roundKey,应等于本页 roundKey。
requestId,链上 VRF 请求编号。
0x 后面的内容每 64 个十六进制字符切一段。第 1 段是 randomWord,第 2 段是 winningIndex,第 3 段是 drawTotal,第 4 段是 ticketRoot。
randomWord 很大,不能用普通 JavaScript Number;要用 BigInt 或链上工具按 uint256 转。
接口字段名是 drawCoordinator。它是平台自己的 DrawCoordinator 开奖合约,不是 Chainlink VRF Coordinator。它用来确认 DrawFulfilled 是由平台公开的开奖合约发出,不是其他合约。
把这些公开值发给别人,对方不登录平台也能复核计算和链上交易。
把 randomWord、drawTotal、winningIndex 放在一起,就能看到中奖票位是怎么算出来的。
本期一共有 2 个有效票位。链上随机数除以 2 的余数是 0,按公式加 1 后得到第 1 个票位,票号快照显示第 1 个票位对应票号 1。
从锁定票号到产生中奖票号,每一步都有可以核对的公开信息。
系统把所有有效票位封存成快照,并生成 ticketRoot。后面不能随意换票。
randomWord 来自 VRF 回调,接口同时给出 requestTxHash 和 callbackTxHash。
winningIndex = randomWord % drawTotal + 1。本期算出来是第 1 个票位。
第 1 个票位在封存快照里对应票号 1,并且归属用户 63***95。
这些校验项全部通过,才表示本期开奖证明完整成立。
下面解释每个关键字段代表什么,以及它在页面中对应哪一类信息。
| 接口字段 | 含义 | 页面展示 |
|---|
这些值用于进一步复核链上事件、票号快照和交易记录。
页面会读取本期开奖证明数据;如果网络暂时不可用,会显示内置样例。
完整 JSON 可用于核对页面展示值和接口返回值是否一致。