github.com/diadata-org/diadata@v1.4.593/documentation/oracle-documentation/randomness-oracle.md (about)

     1  ---
     2  description: >-
     3    This article describes usage and deployment addresses of the DIA randomness
     4    oracle.
     5  ---
     6  
     7  # Randomness Oracle
     8  
     9  ### What is randomness?
    10  
    11  Randomness is the property of lacking any sensible predictability. It is very difficult to create random events on-chain due to the deterministic nature of any EVM or EVM-like environment.
    12  
    13  Centralized randomness is suspectible for attacks by the randomness source, as a single non-random outcome cannot be distinguished from a random one. Thus, having a single RNG provide randomness via an oracle is not enough.
    14  
    15  DIA provides randomness as a guest oracle using the distributed random beacon provided by [drand.love](https://drand.love). It is generated by a network of participants (the League of Entropy) and updated in discrete rounds.
    16  
    17  ### Who needs randomness?
    18  
    19  Random numbers can be very relevant for on-chain applications such as games, lotteries, prediction markets, or NFT launches.
    20  
    21  Relying on pseudo-random values like the last blockhash can be manipulated by miners and is not advisable.
    22  
    23  Drand run distributed nodes to produce their randomness beacon. Drand uses [Pedersen's DKG (Distributed Key Generation) protocol](https://drand.love/docs/cryptography/#distributed-key-generation-dkg) to create collective private/public key. Participants in their Leagure of Entropy then generate randomness in rounds and broadcast it together with its signature.
    24  
    25  ### Using the DIA Randomness Oracle
    26  
    27  DIA uses the drand.love public randomness beacon, and updates its oracle with round number, randomness and signature. Anyone can access published random values via round ID.
    28  
    29  ```
    30  {
    31  	"round": 1597683,
    32  	"randomness": "24138936fcbf7fc3951c928158be6998cee3af622142d0790333608d17a5c5f6",
    33  	"signature": "8c04905c0adf34f1fb007915d9ccc7d07b97305fc63952726f9367c87f36ab687c5e190c151f6ac4d760a9e009fc54230adb8513885449d649a229bc727be9ff347bdbce1c609cebf993b6ae57133fbcf23f96b15dbd3510cb5f2ade6b30b647",
    34  	"previous_signature": "ada42197a2db89866da4c44348f77f7868e41e961ec32e636b912d43c625386afae9e54944ac573047dbd227ee495b52059586c8d8cd0edfe18cc15ca0666a66651da1d62b12af2d0fac19735bed9298690a593571965c3ad7c7b11947e76ec0"
    35  }
    36  ```
    37  
    38  The DIA randomness smart contract is structured as follows
    39  
    40  ```
    41  pragma solidity ^0.8.0;
    42  
    43  contract DIARandomOracle {
    44  
    45    struct Random { 
    46      string randomness;
    47      string signature;
    48      string previousSignature;
    49    }
    50  
    51    mapping (uint256 => Random) public values;
    52    uint256 public lastRound = 0;
    53  
    54    address public oracleUpdater;
    55  
    56    event OracleUpdate(string key, uint128 value, uint128 timestamp);
    57    event UpdaterAddressChange(address newUpdater);
    58  
    59    constructor() {
    60      oracleUpdater = msg.sender;
    61    }
    62  
    63    function setRandomValue(uint256 _round, string memory _randomness, string memory _signature, string memory _previousSignature) public {
    64      require(msg.sender == oracleUpdater,"not a updater");
    65      require(lastRound<_round, "old round");
    66      lastRound = _round;
    67      values[_round] = Random(_randomness, _signature, _previousSignature);
    68    }
    69  
    70    function getValue(uint256 _round) external view returns (Random memory) {
    71      return values[_round];
    72    }
    73  
    74    function updateOracleUpdaterAddress(address newOracleUpdaterAddress) public {
    75      require(msg.sender == oracleUpdater,"not a updater");
    76      oracleUpdater = newOracleUpdaterAddress;
    77      emit UpdaterAddressChange(newOracleUpdaterAddress);
    78    }
    79  
    80    function getRandomValueFromRound(uint256 _round) external view returns (string memory) {
    81      return values[_round].randomness;
    82    }
    83  
    84    function getRandomValueFromRoundWithSignature(uint256 _round) external view returns (Random memory) {
    85      return values[_round];
    86    }
    87  
    88    function getLastRound() public view returns(uint256) {
    89      return lastRound;
    90    }
    91  }
    92  ```
    93  
    94  Users can call `getLastRound()`to obtain the ID of the latest published round. To obtain the randomness of a certain round, users can call `getRandomValueFromRound(uint256 _round)`using the obtaines round ID.
    95  
    96  The signature can also be requested by calling `getRandomValueFromRoundWithSignature(uint256 _round)`.&#x20;
    97  
    98  Please be aware that you should always let all inputs commit before any randomness is used in a later round. For example, if you build a lottery, only call randomness after the last participant has committed their stake. To show this in an example, we will build a simple dice game.
    99  
   100  ### Example: Dice Game
   101  
   102  Imagine a simple game where two players play against each other. Both throw a dice and the user with the higher rolled number wins. In case of a draw, nobody wins. Both players need to "seed" the game with an initial number between 1 and 6, that will be added to the randomness (modulo 6). It is a fair game where everyone has a 50% chance of winning.
   103  
   104  ```
   105  pragma solidity ^0.8.0;
   106    
   107  
   108  import "../DIARandomOracle.sol";
   109  
   110  contract DiceGame {
   111    address public randomOracle;
   112    uint256 seed1 = 0;
   113    uint256 seed2 = 0;
   114    uint256 latestRoundId = 0;
   115    
   116    constructor(address oracle) {
   117      randomOracle = oracle;
   118    }
   119  
   120    function getRandomValue(uint256 _round) public view returns (string memory) {
   121      return DIARandomOracle(randomOracle).getRandomValueFromRound(_round);
   122    }
   123    
   124    function commitPlayer1(uint256 seed) external {
   125      require(seed > 0, "Seed must be between 1 and 6");
   126      require(seed < 7, "Seed must be between 1 and 6");
   127      
   128      seed1 = seed;
   129      latestRoundId = DIARandomOracle(randomOracle).getLastRound();
   130    }
   131    
   132    function commitPlayer2(uint256 seed) external {
   133      require(seed > 0, "Seed must be between 1 and 6");
   134      require(seed < 7, "Seed must be between 1 and 6");
   135      
   136      seed2 = seed;
   137      latestRoundId = DIARandomOracle(randomOracle).getLastRound();
   138    }
   139    
   140    function rollDice() public view returns (uint) {
   141      require(seed1 > 0, "Player 1 needs to commit their seed!");
   142      require(seed2 > 0, "Player 2 needs to commit their seed!");
   143      
   144      uint _round = latestRoundId + 10;
   145      
   146      require(DIARandomOracle(randomOracle).getLastRound() >= _round, "Wait for the randmoness round to roll your dice.");
   147      
   148      string memory rand = getRandomValue(_round);
   149      uint256 player1result = (uint256(keccak256(abi.encodePacked(rand))) + seed1) % 6;
   150      uint256 player2result = (uint256(keccak256(abi.encodePacked(rand))) + seed2) % 6;
   151      
   152      seed1 = 0;
   153      seed2 = 0;
   154      
   155      if (player1result > player2result) {
   156        return 1;
   157      } else if (player2result > player1result) {
   158        return 2;
   159      } else {
   160        return 0;
   161      }
   162    }
   163  }
   164  ```
   165  
   166  Both players need to commit their seeds. The latest published roundID is stored for the duration of the game. When both committed their values and the wait time of 10 rounds has passed, the dice can be rolled and the player ID of the winner is returned (or 0 in case of a draw).
   167  
   168  {% hint style="info" %}
   169  Make sure to never directly query the latest randomness value, otherwise the miner and the randomness oracle can interfere with the result. Always commit values before the randomness is used in a later round.
   170  {% endhint %}
   171  
   172  ### Deployed Randomness Oracles
   173  
   174  Currently, the randomness oracle is deployed on the Aurora EVM.
   175  
   176  | Blockchain     | Smart Contract Address                                                                                               |
   177  | -------------- | -------------------------------------------------------------------------------------------------------------------- |
   178  | Aurora         | [0x9055...4b22](https://explorer.mainnet.aurora.dev/address/0x905506f6dA815e73CA13547B45d1998867104b22/transactions) |
   179  | Moonbeam Alpha | [0x48d3....6cec](https://moonbase.moonscan.io/address/0x48d351ab7f8646239bbade95c3cc6de3ef4a6cec)                    |
   180  
   181  ### Risk Mitigation
   182  
   183  It is important to understand the risks of the randomness oracle before using it and to be able to mitigate them.
   184  
   185  An extensive risk evaluation of the underlying [drand.love](https://drand.lo) protocol can be found [in their documentation](https://drand.love/docs/security-model/#notations). All risks listed there also affect the randomness guest oracle, as it serves as a underlying data provider.
   186  
   187  Additionally, there are new risks introduced by using the oracle.
   188  
   189  | Risk                                   | Possible Mitigation                                                                               |
   190  | -------------------------------------- | ------------------------------------------------------------------------------------------------- |
   191  | Oracle stops serving data              | Check that the oracle has recent updates in its history.                                          |
   192  | Specific Round is missed by the oracle | Have your dApp use the next round if a certain round is unavailable (but later ones exist).       |
   193  | Oracle serves compromised data         | Check the associated BLS signature provided by drand (Note: Currently not availabe on most EVMs). |