智能合约中使用更安全的随机数(代码实战篇)

 空投币   2020-06-08  来源:互联网  0 条评论
优质活动 币圈快讯 平台公告 行情分析
最新羊毛 最新空投 链圈挖矿 活动线报
新币上市 币圈空投 国外项目 币链屋
提醒:本站内容均转自网络,仅用于开发者下载测试,请明辨风险,若涉资金安全及隐私,请谨慎!谨慎!再谨慎!一切风险自担,涉及资金交易及个人隐私务必小心并远离,切记千万别投资,勿上当受骗。《本站免责申明》


mkdir vrf; cd vrf truffle init npm install @chainlink/contracts --save

pragma solidity 0.6.2; import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol";

abstract contract VRFConsumerBase is VRFRequestIDBase { ... function fulfillRandomness(bytes32 requestId, uint256 randomness) external virtual; function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId) { ... } ... }

上面列出了 VRFConsumerBase 合约的两个基本方法,一个是 requestRandomness 方法,它是用来发起一个 VRF 请求的方法,在调用的时候呢,需要传入三个参数:

· _keyHash: 节点的公钥哈希。因为随机数及其证明的生成,是通过椭圆曲线密码学来完成的,所以需要一对公钥和私钥。公钥是节点公开的密钥,目前可用的 VRF 节点公钥及 VRF 节点的其他相关信息,可用在 Chainlink 官方文档上查到。

· _fee: 用户发起一次 VRF 请求所需要花费的费用,这个费用也可以在节点公布的相关信息中查阅到。如果费用没有达到节点的最低要求,那么 VRF 请求无法完成。费用是以 LINK token 形式支付,所以用户合约需要持有足够的 LINK token。

· _seed: 用户提供的种子,用于生成随机数。用户需要给出高质量的种子。这里我们需要解释一下 VRF 的特点,VRF 是通过种子与节点私钥做椭圆曲线中的计算得来的,同一个种子对应的随机数也是相同的,所以用户需要每次都给出不一样的且不可预测的种子。这很重要。因为任何可以左右用户种子的因素,都可以与链下的节点勾结作恶,生成他们想要的随机数,从而损害用户的利益。区块链中,我们很容易就找到这么一个随机源就是区块哈希,但是区块哈希是可以被矿工控制的(虽然很难),所以建议不能仅使用区块链哈希,还需要与其他随机源一起使用生成种子。比如下面就是一个例子。


function makeRequest(uint256 userProvidedSeed) public returns (bytes32 requestId) { uint256 seed = uint256(keccak256(abi.encode(userProvidedSeed, blockhash(block.number)))); // Hash user seed and block hash return requestRandomness(keyHash, fee, seed); }

constructor(address _vrfCoordinator, address _link) public { vrfCoordinator = _vrfCoordinator; LINK = LinkTokenInterface(_link); }

constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public { // 其他一些初始化参数 }

bytes32 internal constant keyHash = 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205; uint256 internal constant fee = 10 ** 18; function getRandomness(uint256 userProvidedSeed) public returns (bytes32 requestId) { require(LINK.balanceOf(address(this)) > fee, "Not enough LINK - fill contract with faucet"); uint256 seed = uint256(keccak256(abi.encode(userProvidedSeed, blockhash(block.number)))); // Hash user seed and blockhash bytes32 _requestId = requestRandomness(keyHash, fee, seed); return _requestId; }

在这个请求函数中,我们把用户合约和区块哈希共同作为种子。keyHash 和 fee 就作为常量直接写在合约里,也可以写到 setter 方法中或者构造函数中。

接下来就是复写接收方法。

uint256 public random; function fulfillRandomness(bytes32 requestId, uint256 randomness) external override { random = randomness.mod(100).add(1); }

pragma solidity 0.6.2; import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol"; // import this if you are using remix // import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol"; contract MyVRFContract is VRFConsumerBase { constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public { } bytes32 internal constant keyHash = 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205; uint256 internal constant fee = 10 ** 18; function getRandomness(uint256 userProvidedSeed) public returns (bytes32 requestId) { require(LINK.balanceOf(address(this)) > fee, "Not enough LINK - fill contract with faucet"); uint256 seed = uint256(keccak256(abi.encode(userProvidedSeed, blockhash(block.number)))); bytes32 _requestId = requestRandomness(keyHash, fee, seed); return _requestId; } uint256 public random; function fulfillRandomness(bytes32 requestId, uint256 randomness) external override { random = randomness.mod(100).add(1); } }

本文地址:http://bilianwu.com/53780.html
版权声明:项目均采集于互联网, 空投币 无法审核全面,且希望大家能赚钱,请谨慎切勿上当受骗!
温馨提示:★★★天上真会掉馅饼!天道酬勤,都是机会!不错过每个空投糖果!真假难以辨认,尽量0撸!
重要提醒:本站内容均转自互联网,请明辨各个项目风险,不构成投资建议,如涉及资金交易,请谨慎操作与自担风险!
《新人必看》 《本站免责申明》

评论已关闭!