vrf名称_如何使用VRF(可验证随机函数)在以太坊上生成随机数
Chainlink 如何解決以太坊“隨機數問題”
隨機數和區塊鏈一直很難達到“一致”(譯者注:區塊鏈要求確定性,而隨機數正相反)。到目前為止,區塊鏈上還沒有可驗證的隨機函數。
原因是:交易被曠工出塊后,需要網絡上的多個節點來確認才算真實有效。就要求每個節點驗證時都必須得出相同的結果。如果函數是隨機的(每次運行的結果不一樣),則每個節點將得出不同的結果,從而導致交易得不到確認。
有一些[解決(變通)方法](https://learnblockchain.cn/2019/02/10/securely-random)可以生成一些[ 偽隨機生成](https://ethereum.stackexchange.com/questions/62375/best-practices-for-generating-a-random-uint256),但到目前為止,已有的方法都不算是真正的隨機,或存在操控的可能。
> 登鏈社區之前也有一篇譯文:[區塊鏈上生成隨機數](https://learnblockchain.cn/article/858) 大家可以讀一讀。
## 關于 chainlink
> Chainlink網絡可以為任何區塊鏈上的復雜智能合約提供可靠的防篡改輸入和輸出。 —來自 [chain.link](https://chain.link/) 官網的介紹
區塊鏈和智能合約針對一組不可變的規則執行計算是個很棒的平臺。問題是規則只能應用于系統內部的數據。而如果要從系統外部獲取可驗證的數據則非常困難。
Chainlink想要通過[提供去中心化的預言機](https://learnblockchain.cn/article/562)來解決這個問題,使區塊鏈能夠通過Chainlink訪問生態系統之外的數據。預言機(Oracles)實質上是區塊鏈和外部世界之間的橋梁。
### 真正的隨機
在最近的一篇文章中,[Chainlink宣布發布了其新的可驗證隨機函數(VRF)](https://learnblockchain.cn/article/1041)。開發者現在可以使用該功能將其集成到多個測試網上的DApp中,從而使智能合約能夠獲得可在鏈上驗證的隨機數。
## 可驗證隨機函數是怎么實現的?
如果你想在Javascript中生成一個隨機數,代碼非常簡單:
```
Math.random();
```
每執行一次,生成一個隨機數。然而這不是**VRF的工作方式**。與Javascript不同,VRF是在一些交易實現的。
以下是 VRF 事件發生的順序:
1. 你的智能合約**通過交易**向VRF請求一個隨機數。
2. VRF會生成該隨機數字并進行驗證。
3. VRF準備響應1 的請求。
4. VRF通過**另一筆交易**將隨機數字發送回你的智能合約。
為了使第4步成功,你的合約需要實現一個確定的函數,以便VRF調用以返回結果。如何在項目中實現呢?
## 如何實現隨機性
讓我們創建一個名為`RandomGenerator`的新合約,在合約里我們將調用VRF并接收結果。
### 第 1 步: 創建消費者合約
我們將引入 Chainlink提供的`VRFConsumerBase`的合約,這是一個抽象合約,它定義了一個獲取和消耗VRF的最少實現(后面也會列出`VRFConsumerBase`的代碼),我們定義“ RandomGenerator.sol”文件開頭像這樣:
```js
pragma solidity ^0.6.2;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomGenerator is VRFConsumerBase {
constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
}
}
```
`VRFConsumerBase`的合約的源碼如下:
```javascript
pragma solidity 0.6.2;
import "./vendor/SafeMath.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";
abstract contract VRFConsumerBase is VRFRequestIDBase {
using SafeMath for uint256;
function fulfillRandomness(bytes32 requestId, uint256 randomness)
external virtual;
function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
public returns (bytes32 requestId)
{
LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
// This is the seed actually passed to the VRF in VRFCoordinator
uint256 vRFSeed = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
// nonces[_keyHash] must stay in sync with
// VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
// successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest)
nonces[_keyHash] = nonces[_keyHash].add(1);
return makeRequestId(_keyHash, vRFSeed);
}
LinkTokenInterface internal LINK;
address internal vrfCoordinator;
// Nonces for each VRF key from which randomness has been requested.
//
// Must stay in sync with VRFCoordinator[_keyHash][this]
mapping(bytes32 /* keyHash */ => uint256 /* nonce */) public nonces;
constructor(address _vrfCoordinator, address _link) public {
vrfCoordinator = _vrfCoordinator;
LINK = LinkTokenInterface(_link);
}
}
```
`VRFConsumerBase` 仍在后期測試中,因此還沒有產品軟件包對外提供。這就是為什么使用Github的HTTP URL進行導入的原因。
`VRFConsumerBase`抽象合約有兩個參數,分別代表協調器(coordinator)和LINK ERC20 代幣合約的地址。這些在每個網絡上合約地址是固定的(稍后會詳細介紹)。
### 第 2 步: 重寫函數
`VRFConsumerBase` 中有兩個對VRF流程至關重要的函數。
第一個是 `requestRandomness` ,這個函數已經實現了,我們不需要重寫。這個函數是用來對VRF進行**初始請求調用**。
另一個是 `fulfillRandomness`, 這是VRF在生成數字后,用來回調的函數。我們需要重載它,以便在獲取隨機數后執行相應的操作。
在我們合約的實現里,僅僅是把隨機數存儲在一個名為`randomNumber`的狀態變量中,以便我們可以在結束時查詢它。代碼像這樣:
```javascript
pragma solidity ^0.6.2;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomGenerator is VRFConsumerBase {
bytes32 public reqId;
uint256 public randomNumber;
constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
reqId = requestId;
randomNumber = randomness;
}
}
```
我們在`fulfillRandomness`函數上添加了[override](https://learnblockchain.cn/docs/solidity/contracts.html#overriding) 修飾符以實現重寫,在實現中,使用`reqId` 和 `randomNumber` 來保存接收變量的值。
### 第 3 步: 生成隨機數
正如在前面 第1步提到的,函數調用需要傳遞一些地址和其他值作為參數。在部署智能合約并調用構造函數時,它需要VRF協調器(coordinator)合約地址和網絡上LINK 代幣合約地址。在Ropsten測試網上,合約地址如下:
- **VRF coordinator:** `0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb`
- **LINK 代幣:** `0x20fE562d797A42Dcb3399062AE9546cd06f63280`
當調用 `requestRandomness`函數時,我們需要傳遞幾個參數:生成隨機數的key hash,生成隨機數的費用fee(使用LINK代幣)和生成隨機性的種子seed(最后一個由我們提供)。requestRandomness函數簽名如下:
```javascript
function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId)
```
在 Ropsten 網絡上,參數值如下:
- Key hash值: `0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205`
- 費用 Fee (1 LINK): `1000000000000000000`
- 種子 Seed: [我們想要的任意值]
因此我們的調用代碼如下:
```javascript
// 設置ropsten key hash
bytes32 keyHash = "0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205";// // 設置 ropsten LINK 費用
fee = 1000000000000000000;
// 設置種子
seed = 123456789;
// 請求隨機數
bytes32 reqId = rand.requestRandomness(keyHash, fee, seed);
```
當結果返回時,隨機值將存儲并且可以通過以下方法獲取:
```javascript
rand.randomNumber;
```
## 自己嘗試一下
現在我們將逐步實踐如何使用`Remix IDE`和Metamask插件從VRF獲取隨機數。在繼續之前,請確保已在瀏覽器上安裝了Metamask 插件。
- 打開 [Remix IDE](https://remix.ethereum.org/)
- 如果還沒用過 Remix,需要向下圖一樣選擇 Solidity 語言。

- 創建一個文件: `RandomGenerator` ,把第 2 步中的代碼復制過來。
- 使用左側菜單,單擊Solidity圖標,然后選擇0.6.2編譯器版本,如下圖所示。

然后單擊下面的按鈕,并在下拉列表中選擇“Injected web3”,如下圖所示。

* 這時Metamask會提示一個連接請求,我們點擊接受請求。
- 確保MetaMask 連接的是 Ropsten網絡,如下圖所示:

- 確保Metamask帳戶中有一些Ropsten 網絡的 以太幣,如果沒有,可以從[這里](https://faucet.ropsten.be/)獲取。
- 回到Remix,在同一選項卡上,應該看到橙色的“ Deploy”按鈕,單擊“ Deploy”按鈕進行部署,注意要接受Metamask彈出的合約部署請求。
- 在部署后,我們需要確保合約中存有一些LINK 代幣,以便它可以為請求隨機數支付費用。打開 Ropsten LINK的“水龍頭”,粘貼Metamask地址,就可以在Metamask中收到100 LINK。
- Metamask不知道LINK 代幣在Ropsten網絡上的地址,因此我們需要添加它。在“ Metamask”中,在帳戶名稱左側,單擊“菜單”符號,然后單擊底部的 “Add Token”。
- 在 “Custom Token(自定義代幣)”下, 添加地址: `0x20fE562d797A42Dcb3399062AE9546cd06f63280`. 剩下的信息將自動填充,提交之后可以看到賬號下有 100 個 LINK,下圖是 70 個 LINK 的賬號截圖:

- 回到 Remix, 復制部署合約地址,如下圖:

- 現在我們將向合約發送一些 LINK。回到Metamask,然后單擊100 LINK旁邊的3個點。粘貼合約地址并發送10 LINK。確認交易后,再繼續下一步。
- 在Remix中,我們現在可以請求隨機數了。在同一選項卡中,向下滾動會發現更多代表合約公有(public)函數的橙色按鈕,如下圖所示。單擊`requestRandomness`右側的箭頭以展開參數。

- 按順序復制這 3 個數:`0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205`, `1000000000000000000`, `123456789`(或者其他你想要的值)作為參數提交交易。

交易可能需要一些時間才能確定,因此需要關注一下終端輸出在Etherscan中的交易信息。

交易完成后,我們需要等待VRF生成隨機數并將其發送回我們的合約。幾分鐘后,單擊我們在Remix中發送交易的橙色按鈕下方的藍色“ randomNumber”按鈕,檢查合約是否收到了隨機數,如下圖所示。

如果一切順利,應該有一個像我這樣的隨機數,它是`30207470459964961279215818016791723193587102244018403859363363849439350753829`.
現在就大功告成了。
## 結論
使用 Chainlink 可以在智能合約中可以使用可驗證的隨機數。在文章中闡述了該機制的工作原理,以及演示了如何將代碼集成到智能合約中獲取隨機數
作者:[Alex Roan](https://medium.com/@alexroan?source=learnblockchain.cn)
原文:https://medium.com/coinmonks/how-to-generate-random-numbers-on-ethereum-using-vrf-8250839dd9e2
歡迎大家在[知乎](https://www.zhihu.com/people/xiong-li-bing),[微博](http://weibo.com/xionglb),[GitHub](https://github.com/xilibi2003)關注我
登鏈社區贊助翻譯。
隨機數和區塊鏈一直很難達到“一致”(譯者注:區塊鏈要求確定性,而隨機數正相反)。到目前為止,區塊鏈上還沒有可驗證的隨機函數。
原因是:交易被曠工出塊后,需要網絡上的多個節點來確認才算真實有效。就要求每個節點驗證時都必須得出相同的結果。如果函數是隨機的(每次運行的結果不一樣),則每個節點將得出不同的結果,從而導致交易得不到確認。
有一些解決(變通)方法可以生成一些偽隨機生成,但到目前為止,已有的方法都不算是真正的隨機,或存在操控的可能。
登鏈社區之前也有一篇譯文:區塊鏈上生成隨機數 大家可以讀一讀。
關于 chainlink
Chainlink網絡可以為任何區塊鏈上的復雜智能合約提供可靠的防篡改輸入和輸出。 —來自 chain.link 官網的介紹
區塊鏈和智能合約針對一組不可變的規則執行計算是個很棒的平臺。問題是規則只能應用于系統內部的數據。而如果要從系統外部獲取可驗證的數據則非常困難。
Chainlink想要通過提供去中心化的預言機來解決這個問題,使區塊鏈能夠通過Chainlink訪問生態系統之外的數據。預言機(Oracles)實質上是區塊鏈和外部世界之間的橋梁。
真正的隨機
在最近的一篇文章中,Chainlink宣布發布了其新的可驗證隨機函數(VRF)。開發者現在可以使用該功能將其集成到多個測試網上的DApp中,從而使智能合約能夠獲得可在鏈上驗證的隨機數。
可驗證隨機函數是怎么實現的?
如果你想在Javascript中生成一個隨機數,代碼非常簡單:
Math.random();
每執行一次,生成一個隨機數。然而這不是VRF的工作方式。與Javascript不同,VRF是在一些交易實現的。
以下是 VRF 事件發生的順序:
你的智能合約通過交易向VRF請求一個隨機數。
VRF會生成該隨機數字并進行驗證。
VRF準備響應1 的請求。
VRF通過另一筆交易將隨機數字發送回你的智能合約。
為了使第4步成功,你的合約需要實現一個確定的函數,以便VRF調用以返回結果。如何在項目中實現呢?
如何實現隨機性
讓我們創建一個名為RandomGenerator的新合約,在合約里我們將調用VRF并接收結果。
第 1 步: 創建消費者合約
我們將引入 Chainlink提供的VRFConsumerBase的合約,這是一個抽象合約,它定義了一個獲取和消耗VRF的最少實現(后面也會列出VRFConsumerBase的代碼),我們定義“ RandomGenerator.sol”文件開頭像這樣:
pragma solidity ^0.6.2;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomGenerator is VRFConsumerBase {
constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
}
}
VRFConsumerBase的合約的源碼如下:
pragma solidity 0.6.2;
import "./vendor/SafeMath.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./VRFRequestIDBase.sol";
abstract contract VRFConsumerBase is VRFRequestIDBase {
using SafeMath for uint256;
function fulfillRandomness(bytes32 requestId, uint256 randomness)
external virtual;
function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed)
public returns (bytes32 requestId)
{
LINK.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed));
// This is the seed actually passed to the VRF in VRFCoordinator
uint256 vRFSeed = makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]);
// nonces[_keyHash] must stay in sync with
// VRFCoordinator.nonces[_keyHash][this], which was incremented by the above
// successful LINK.transferAndCall (in VRFCoordinator.randomnessRequest)
nonces[_keyHash] = nonces[_keyHash].add(1);
return makeRequestId(_keyHash, vRFSeed);
}
LinkTokenInterface internal LINK;
address internal vrfCoordinator;
// Nonces for each VRF key from which randomness has been requested.
//
// Must stay in sync with VRFCoordinator[_keyHash][this]
mapping(bytes32 /* keyHash */ => uint256 /* nonce */) public nonces;
constructor(address _vrfCoordinator, address _link) public {
vrfCoordinator = _vrfCoordinator;
LINK = LinkTokenInterface(_link);
}
}
VRFConsumerBase 仍在后期測試中,因此還沒有產品軟件包對外提供。這就是為什么使用Github的HTTP URL進行導入的原因。
VRFConsumerBase抽象合約有兩個參數,分別代表協調器(coordinator)和LINK ERC20 代幣合約的地址。這些在每個網絡上合約地址是固定的(稍后會詳細介紹)。
第 2 步: 重寫函數
VRFConsumerBase 中有兩個對VRF流程至關重要的函數。
第一個是 requestRandomness ,這個函數已經實現了,我們不需要重寫。這個函數是用來對VRF進行初始請求調用。
另一個是 fulfillRandomness, 這是VRF在生成數字后,用來回調的函數。我們需要重載它,以便在獲取隨機數后執行相應的操作。
在我們合約的實現里,僅僅是把隨機數存儲在一個名為randomNumber的狀態變量中,以便我們可以在結束時查詢它。代碼像這樣:
pragma solidity ^0.6.2;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/develop/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomGenerator is VRFConsumerBase {
bytes32 public reqId;
uint256 public randomNumber;
constructor(address _vrfCoordinator, address _link) VRFConsumerBase(_vrfCoordinator, _link) public {
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) external override {
reqId = requestId;
randomNumber = randomness;
}
}
我們在fulfillRandomness函數上添加了override 修飾符以實現重寫,在實現中,使用reqId 和 randomNumber 來保存接收變量的值。
第 3 步: 生成隨機數
正如在前面 第1步提到的,函數調用需要傳遞一些地址和其他值作為參數。在部署智能合約并調用構造函數時,它需要VRF協調器(coordinator)合約地址和網絡上LINK 代幣合約地址。在Ropsten測試網上,合約地址如下:
VRF coordinator: 0xf720CF1B963e0e7bE9F58fd471EFa67e7bF00cfb
LINK 代幣: 0x20fE562d797A42Dcb3399062AE9546cd06f63280
當調用 requestRandomness函數時,我們需要傳遞幾個參數:生成隨機數的key hash,生成隨機數的費用fee(使用LINK代幣)和生成隨機性的種子seed(最后一個由我們提供)。requestRandomness函數簽名如下:
function requestRandomness(bytes32 _keyHash, uint256 _fee, uint256 _seed) public returns (bytes32 requestId)
在 Ropsten 網絡上,參數值如下:
Key hash值: 0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205
費用 Fee (1 LINK): 1000000000000000000
種子 Seed: [我們想要的任意值]
因此我們的調用代碼如下:
// 設置ropsten key hash
bytes32 keyHash = "0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205";// // 設置 ropsten LINK 費用
fee = 1000000000000000000;
// 設置種子
seed = 123456789;
// 請求隨機數
bytes32 reqId = rand.requestRandomness(keyHash, fee, seed);
當結果返回時,隨機值將存儲并且可以通過以下方法獲取:
rand.randomNumber;
自己嘗試一下
現在我們將逐步實踐如何使用Remix IDE和Metamask插件從VRF獲取隨機數。在繼續之前,請確保已在瀏覽器上安裝了Metamask 插件。
如果還沒用過 Remix,需要向下圖一樣選擇 Solidity 語言。
創建一個文件: RandomGenerator ,把第 2 步中的代碼復制過來。
使用左側菜單,單擊Solidity圖標,然后選擇0.6.2編譯器版本,如下圖所示。
然后單擊下面的按鈕,并在下拉列表中選擇“Injected web3”,如下圖所示。
這時Metamask會提示一個連接請求,我們點擊接受請求。
確保MetaMask 連接的是 Ropsten網絡,如下圖所示:
確保Metamask帳戶中有一些Ropsten 網絡的 以太幣,如果沒有,可以從這里獲取。
回到Remix,在同一選項卡上,應該看到橙色的“ Deploy”按鈕,單擊“ Deploy”按鈕進行部署,注意要接受Metamask彈出的合約部署請求。
在部署后,我們需要確保合約中存有一些LINK 代幣,以便它可以為請求隨機數支付費用。打開 Ropsten LINK的“水龍頭”,粘貼Metamask地址,就可以在Metamask中收到100 LINK。
Metamask不知道LINK 代幣在Ropsten網絡上的地址,因此我們需要添加它。在“ Metamask”中,在帳戶名稱左側,單擊“菜單”符號,然后單擊底部的 “Add Token”。
在 “Custom Token(自定義代幣)”下, 添加地址: 0x20fE562d797A42Dcb3399062AE9546cd06f63280. 剩下的信息將自動填充,提交之后可以看到賬號下有 100 個 LINK,下圖是 70 個 LINK 的賬號截圖:
回到 Remix, 復制部署合約地址,如下圖:
現在我們將向合約發送一些 LINK。回到Metamask,然后單擊100 LINK旁邊的3個點。粘貼合約地址并發送10 LINK。確認交易后,再繼續下一步。
在Remix中,我們現在可以請求隨機數了。在同一選項卡中,向下滾動會發現更多代表合約公有(public)函數的橙色按鈕,如下圖所示。單擊requestRandomness右側的箭頭以展開參數。
按順序復制這 3 個數:0xced103054e349b8dfb51352f0f8fa9b5d20dde3d06f9f43cb2b85bc64b238205, 1000000000000000000, 123456789(或者其他你想要的值)作為參數提交交易。
交易可能需要一些時間才能確定,因此需要關注一下終端輸出在Etherscan中的交易信息。
交易完成后,我們需要等待VRF生成隨機數并將其發送回我們的合約。幾分鐘后,單擊我們在Remix中發送交易的橙色按鈕下方的藍色“ randomNumber”按鈕,檢查合約是否收到了隨機數,如下圖所示。
如果一切順利,應該有一個像我這樣的隨機數,它是30207470459964961279215818016791723193587102244018403859363363849439350753829.
現在就大功告成了。
結論
使用 Chainlink 可以在智能合約中可以使用可驗證的隨機數。在文章中闡述了該機制的工作原理,以及演示了如何將代碼集成到智能合約中獲取隨機數
歡迎大家在知乎,微博,GitHub關注我
登鏈社區贊助翻譯。
本文參與登鏈社區寫作激勵計劃 ,好文好收益,歡迎正在閱讀的你也加入。
發表于 2020-05-25 15:01
閱讀 ( 871 )
學分 ( 61 )
分類:以太坊
總結
以上是生活随笔為你收集整理的vrf名称_如何使用VRF(可验证随机函数)在以太坊上生成随机数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java清除控制台_Java:清除控制台
- 下一篇: java 数组json_如何在Java中