# Randomness Precompile Spec We are planning to initially offer the following sources of randomness: 1. Simple Randomness, block author VRF output which also signs `Parent_Block_Hash + Relay_Block_Hash` (updated every block) 1. Slow Randomness Two Epochs Ago, relay chain BABE randomness (`RandomnessFromTwoEpochsAgo` updated every epoch) 1. Slow Randomness One Epoch Ago, relay chain BABE randomness (`RandomnessFromOneEpochAgo` updated every epoch) The randomness precompile exposes a request-response API wherein responses can be triggered by any signed origin after the required data has been updated. Solidity contracts that want to use the API to get randomness must implement this callback interface: ```javascript interface Randomness { refundAddress(address); function fulfillRandomness(bytes32 _requestId, uint256 _randomness) internal virtual; } ``` * `_requestId`: unique ID for request * `_randomness`: randomness output The moonbeam dev team will provide a solidity library to verify the caller origin is the precompile address. Our EVM will expose a separate precompile interface: ```javascript interface RandomnessPrecompile { function requestRandomness(bytes32 _sourceId, bytes32 _salt, uint256 _fee) public returns (bytes32 requestId); function executeFulfillment(bytes32 _requestId); function updateRandomnessFee(bytes32 _requestId, uint256 _newFee); function instantRawRandomness(bytes32 _sourceId) public returns (uint256 randomness); function instantRandomness(bytes32 _sourceId, bytes32 _salt) public returns (uint256 randomness); } ``` ## Request API The request API is: ```javascript function requestRandomness(bytes32 _sourceId, bytes32 _salt, uint256 _fee) public returns (bytes32 requestId) ``` * `_sourceId` corresponds to sources of randomness offered * `_salt`: unique input, to be concatenated with randmness and hashed to ensure unique final output * `_fee`: funds reserved to execute the fulfillment request when the source of randomness is next updated There is a deposit for every randomness request. This will likely be expressed as a balances `reserve`. The deposit will be returned when the request is executed or removed from storage. ## Response API To fulfill a randomness request, any account can call the precompile method `executeFulfillment` with the `_requestId` associated with the request. ```javascript // calls fulfillRandomness if randomness is ready (has been updated to new unknown since request was made) function executeFulfillment(bytes32 _requestId); ``` The `_fee` originally input by the requester is used to pay the costs of executing the fulfillment. The excess of fee less execution costs goes to the caller of `executeFulfillment` as an additional incentive. Internally, `executeFulfillment` gets the most recent randomness value if updated, concatenates it with the `_salt` input, and hashes it to get the random output which the precompile provides by calling `fulfillRandomness`. There is also a function to update the `_fee` for a request: ```javascript function updateRandomnessFee(bytes32 _sourceId, uint256 _newFee); ``` This function replaces the existing `_fee` with the `_newFee` iff `_newFee > _fee` and can be called by anyone. The fee pays for the execution of the randomness fulfillment once the source of randomness is sufficiently updated. ## Instant Randomness API To get the most recent raw randomness: ```javascript function instantRawRandomness(bytes32 _sourceId) public returns (uint256 randomness); ``` To use the most recent raw randomness with a salt input: ```javascript function instantRandomness(bytes32 _sourceId, bytes32 _salt) public returns (uint256 randomness); ``` The `_sourceId` corresponds to the source of randomness: 1. Simple Randomness, block author VRF output which also signs `Parent_Block_Hash + Relay_Block_Hash`(updated every block) 1. Slow Randomness, relay chain BABE randomness (at least `RandomnessFromTwoEpochsAgo` updated every epoch) 1. Slow Randomness One Epoch Ago, relay chain BABE randomness (`RandomnessFromOneEpochAgo` updated every epoch) ### Substrate Pallet Implementation Details Set new epoch randomness in on_initialize Set new per block randomness via inherent in runtime digest Map Epoch => (option(rand), num_requests, expiration_date) Map Requests => (enum(epoch(epoch_to_fulfill)|block_number), contract_address, bytes32 salt) We are considering * exposing extrinsic index via precompile to provide another input that would ensure uniqueness of salt (to ensure unique output that used the randomness) * refunding the difference between `fee` and actual cost of `executeFulfillment` to the original requester, burning it, paying it to the treasury, paying it to the caller of `executeFulfillment` * encouraging using `contract_address + nonce` as the `_salt` in the docs for implementations ## SECURITY ASSUMPTIONS FOR EACH SOURCE OF RANDOMNESS ### Slow Random There is a new `RandomnessFromTwoEpochsAgo` every epoch, but each BABE randomness request must wait X epochs (where 2 < X <= 3) for the next random number. > Epochs are [4 hours on average in Polkadot](https://wiki.polkadot.network/docs/maintain-polkadot-parameters) ### Simple Random It can be easily withheld by malicious collators (at the cost of not producing the block and not receiving that reward). #### EXTRA: Get CurrentRandomness from Relay Chain The BABE randomness actually provides a VRF output by the block author per block. Ideally we would also provide this randomness to users.