VRF随机数在链上怎么用?AMA Protocol合约掷骰子实现原理
【免费下载链接】node项目地址: https://gitcode.com/GitHub_Trending/node95/node
想给链上游戏加一个公平的掷骰子功能,却担心随机数被矿工或节点操控?VRF随机数正是解决这个痛点的关键。本文以开源项目AMA Protocol(node)为例,从零拆解 VRF 随机数在链上智能合约里的使用方式,并带你读懂它的 RPG 合约掷骰子实现原理,即使是新手也能轻松理解。
为什么链上随机数这么难做?🤔
在传统程序里,Math.random()随手一调就有随机数。但在区块链上,所有节点必须对同一笔交易算出完全相同的结果,否则共识就会分叉。这就带来两个经典难题:
| 难题 | 说明 |
|---|---|
| 可预测性 | 区块内容公开,任何人可以提前算出"随机"结果 |
| 可操纵性 | 矿工可以反复尝试,直到选出一个对自己有利的随机结果 |
而VRF(Verifiable Random Function,可验证随机函数)给出了优雅的答案:它由私钥和公开输入共同生成随机数,任何人都能用公钥验证这个随机数是正确生成的,却无法在生成前预测它。不可预测 + 可验证,正好命中链上随机数的一切要求。
AMA Protocol 的 VRF 随机数藏在哪?🔑
AMA Protocol 把 VRF 直接内建在共识层:每个区块条目(Entry)都携带两个随机数相关的字段,定义在 Rust 核心源码ex/native/rdb/src/consensus/consensus_apply.rs中:
entry_vr(96 字节):区块级的 VRF 随机数,由 BLS12-381 G2 曲线签名算法生成,域分离标签(DST)定义在ex/native/rdb/src/consensus/aggsig.rs,即AMADEUS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_VRF_;entry_dr(32 字节):由 VRF 派生的更短随机摘要,方便合约直接使用。
简单说:共识层每出一个区块,就为这个区块的所有合约准备好了一份"官方认证"的 VRF 随机数,合约只需要去"取"。
合约里怎么拿到 VRF 随机数?📥
对于用 AssemblyScript 编写的智能合约,读取 VRF 极其简单。项目提供了现成的 SDK 封装,位于contract_samples/assemblyscript/sdk.ts,里面有两个关键函数:
export function entry_vr(): Uint8Array { return memory_read_bytes(2300); } export function entry_dr(): Uint8Array { return memory_read_bytes(2400); }底层原理也不神秘:节点在执行合约前,会把当前区块的 VRF 数据写入合约 WASM 内存的固定地址(2300 和 2400),这段逻辑在ex/native/rdb/src/consensus/bic/wasm.rs中完成。合约侧只需一行调用,就能拿到由区块共识保证的、不可篡改的 VRF 随机数。
拆解 RPG 合约的掷骰子实现 🎲
光说原理不够直观,项目自带了一个完整 RPG 游戏合约,就在contract_samples/assemblyscript/5_rpg/目录。它的main.ts里定义了掷骰子函数:
export function roll_dice(sides: u32): i64 { const val = Math.random(); // Returns 0.0 to 1.0 return (floor(val * sides) as i32) + 1; // Returns 1-sides }这个函数把Math.random()的 0~1 小数映射成 1~N 的骰子点数,在fight()战斗逻辑中被反复使用:
- 🧟随机遭遇怪物:掷 10 面骰,点数 ≥ 7 遇到更强的兽人(Orc),否则是哥布林(Goblin);
- ⚔️随机伤害判定:英雄与怪物每回合各自掷骰,结合武器、护甲属性结算扣血;
- 💰随机掉落:怪物死亡后按掉落表掷 100 面骰,命中概率即掉落对应 NFT 装备。
注意一个细节:这里的Math.random()在链上是确定性伪随机的——同一输入在每台节点机器上都会得出相同序列,保证共识一致。而真正"不可预测"的随机源,正是前面提到的entry_vr/entry_dr,它们可以组合进你的掷骰算法里,比如把entry_vr的字节作为种子参与计算,从而让随机结果既不可预测、又可验证、还全网一致。
三步在自己合约里用上 VRF 随机数 ✅
- 读取随机源:在合约里调用 SDK 的
sdk.entry_vr()或sdk.entry_dr(),拿到当前区块的 VRF 字节; - 混合进算法:把 VRF 字节与业务参数(如玩家地址、回合数)做哈希或取模,映射到你需要的随机范围;
- 上链验证:部署后调用合约函数,你会得到全网节点一致认可的随机结果,玩家可通过区块的 VRF 证明校验公平性。
新手避坑指南 🚧
- ❌ 不要把
Math.random()当唯一随机源用于高价值场景,它可被复现; - ✅ 公平性敏感的场景(抽奖、开盲盒、战斗结算)优先组合 VRF 随机数;
- ✅ 想让随机结果跟具体玩家绑定,记得在哈希前拼接
sdk.account_caller()等上下文数据。
总结
AMA Protocol 用一条简洁的链路解决了链上随机数难题:共识层用 BLS12-381 G2 生成可验证的 VRF 随机数 → 写入 WASM 内存 → 合约通过 SDK 一行读取。配合项目自带的 RPG 掷骰子合约示例,你完全可以照葫芦画瓢,在自己的 DApp 里实现公平、透明、可验证的链上随机功能。如果你想动手实践,克隆仓库后,参考contract_samples/assemblyscript/5_rpg/main.ts和contract_samples/GETTINGSTARTED.md的部署步骤,就能在本地测试网跑起你的第一个"公平骰子"合约了。
【免费下载链接】node项目地址: https://gitcode.com/GitHub_Trending/node95/node
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考