Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add randomness doc #441

Merged
merged 29 commits into from
Nov 8, 2023
Merged
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c391650
Add randomness doc
chasefleming Nov 8, 2023
52340fd
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
d4c854a
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
632dbba
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
29843f4
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
c133021
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
f5af7e9
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
f33192e
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
85c3019
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
0dbd254
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
59e678d
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
ad20d6f
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
fb4f52c
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
e1c6aff
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
8e9b869
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
37a79b6
Fix line breaks
chasefleming Nov 8, 2023
fd7b979
Fix line breaks
chasefleming Nov 8, 2023
8ff1e52
Fix line breaks
chasefleming Nov 8, 2023
5115b90
Fix line breaks
chasefleming Nov 8, 2023
2e48f89
Fix list formatting
chasefleming Nov 8, 2023
6d0db1f
Fix title case
chasefleming Nov 8, 2023
c693acc
Change title
chasefleming Nov 8, 2023
eccee7d
Change title
chasefleming Nov 8, 2023
5629953
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
1b546af
Update docs/build/advanced-concepts/randomness.md
chasefleming Nov 8, 2023
e862d91
Fix casing
chasefleming Nov 8, 2023
ca01103
Add suggestion
chasefleming Nov 8, 2023
dc81aa2
Remove
chasefleming Nov 8, 2023
7612939
Remove
chasefleming Nov 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions docs/build/advanced-concepts/randomness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
title: Flow's Native Onchain Randomness
sidebar_label: Native Randomness
---

# Native Onchain Randomness on Flow

Flow enhances blockchain functionality by providing native onchain randomness, eliminating reliance on external oracles in Web3. This secure, decentralized feature empowers developers to build a variety of applications with truly unpredictable, transparent, and fair outcomes, achieved with greater efficiency.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

Flow’s onchain randomness delivers immediate random values within smart contracts, bypassing the latency and complexity of oracle integration. Developers can obtain verifiably random results with a single line of Cadence code, streamlining the development process and enhancing the performance of decentralized applications.

## Use Cases of Onchain Randomness

- **Gaming:** Integrates fairness and unpredictability into gameplay, enhancing user engagement without delays.
- **NFTs:** Facilitates the creation of uniquely randomized traits in NFTs quickly, adding to their rarity and value.
- **Lotteries & Draws:** Offers instant and verifiably fair random selection for lotteries, solidifying trust in real-time.
- **DeFi Protocols:** Enables rapid and innovative random reward systems within decentralized finance.
- **DAOs:** Assists in unbiased voting and task assignments through immediate randomness.
- **Broad Applications:** Extends to any domain requiring impartial randomization, from asset distribution to security mechanisms, all with the added benefit of on-demand availability.

## History - Distributed Random Beacon
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

Within the Flow protocol, the heart of randomness generation lies in the "distributed random beacon." This module generates randomness that is distributed across the network while adhering to established safety and security standards. The output from the randomness beacon is a sequence of random bytes that are unpredictable and impartial.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

For over three years, the beacon has ensured protocol security by assigning verification nodes to oversee block computations. For those interested in a more detailed exploration of the randomness beacon and its inner workings, you can read [the technical deep dive on the Flow forum](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110).
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

chasefleming marked this conversation as resolved.
Show resolved Hide resolved
## Guidelines for Safe Usage

For usage of randomness where result abortion is not an issue, it is recommended to use the Cadence built-in function `revertibleRandom.` `revertibleRandom` returns a pseudo-random number and is also based on the safe Random Beacon.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

```cadence
// Language reference:
// https://developers.flow.com/cadence/language/built-in-functions#revertiblerandom
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
access(all) fun main(): UInt64 {
// Simple assignment using revertibleRandom - keep reading docs for safe usage!
let rand: UInt64 = revertibleRandom()
return rand
}
```

It is notable that the random number generation process is unpredictable (for miners unpredictable at block construction time and for cadence logic unpredictable at time of call), verifiable, uniform, as well as safe from bias by miners and previously-running Cadence code.

Although Cadence exposes safe randomness generated by the Flow protocol via `revertibleRandom`, there is an additional safety-relevant aspect that developers need to be mindful about.

The `revertibleRandom` function can be used safely in some applications where the transaction results are NOT deliberately reverted after the random number is revealed (i.e. a contract distributing random NFTs to registered users or onchain lucky draw). However, if applications require a non-trusted party (for instance app users) to submit a transaction calling a randomized (non-deterministic) contract, the stream of random numbers produced is potentially unsafe in the following two regards:

1. The sequence of random numbers is potentially predictable by transactions within the same block and by other smart contracts calling into your smart contract.
2. A transaction calling into your smart contract can potentially bias the sequence of random numbers which your smart contract internally generates. Currently, the block hash seeds `revertibleRandom`. Consensus nodes can *easily* bias the block hash and **influence the seed for** `revertibleRandom`.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

<Callout type="warning">
🚨 A transaction can atomically revert all its action during its runtime and abort. Therefore, it is possible for a transaction calling into your smart contract to post-select favorable results and revert the transaction for unfavorable results.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
</Callout>

In other words, transactions submitted by a non-trusted party are able to reject their results after the random is revealed.

<Callout type="info">
💡 **Post-selection** - the ability for transactions to reject results they don't like - is inherent to any smart contract platform that allows transactions to roll back atomically. See this very similar [Ethereum example](https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/public-data/).
</Callout>

The central aspect that you as a developer have to think about is the following scenario:
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

- Imagine an adversarial user that is sending a transaction that calls your smart contract.
- The transaction includes code that runs after your smart contract returns and inspects the outcome.
- If the outcome is unfavorable (based on some criteria codified in the transaction), the transaction aborts itself.

As an example, consider a simple coin toss randomized contract where users can bet any amount of tokens against a random binary output. If the coin toss contract outputs `1`, the user doubles their bet. If the coin toss contract outputs `0`, the user loses their bet in favor of the coin toss.

Although the user (or the honest coin toss contract) cannot predict or bias the outcome, the user transaction can check the randomized result and cancel the transaction if they are losing their bet. This can be done by calling an exception causing the transaction to error. All temporary state changes are cancelled and the user can repeat the process till they double their bet.

## Commit-Reveal Scheme

The recommended way to mitigate the problems above is via a commit-reveal scheme. The scheme involves two steps: commit and reveal. During the commit phase, users submit a commitment that contains the hash of their answer along with a random seed value. The smart contract stores this commitment on the blockchain. Later, during the reveal phase, the user reveals their answer and the seed value.

There are ideas how to further optimize the developer experience further in the future. For example, a transaction could delegate part of its gas to an independent transaction it spawns. Conceptually, also this future solution would be a commit-and-reveal scheme, just immediately happening within the same block. Until we eventually get to this next level, developers may need to implement their own commit-reveal. In Cadence, it is clean and short.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

Protocol improvements (documented in [FLIP 120](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md)) expose the random beacon to the FVM and Cadence where it can be used to seed pseudo-random number generators (PRG) for smart contracts.

In simpler terms, the native secure randomness provided by the protocol can now be safely utilized within Cadence smart contracts and is available to all developers on Flow and the FVM.

While the source values are safely generated by the Random Beacon and transmitted into the execution environment via the committing transaction, using the raw values from this contract does not guarantee non-revertible randomness. In addition to the commit-reveal pattern described below, it is also recommended to use the source values with a pseudo-random number generator (PRG) to generate an arbitrarily-long sequence of random values.

Adding a safe pattern to reveal randomness without the possibility of conditional transaction reversion unlocks applications relying on randomness. By providing examples of commit-reveal implementations we hope to foster a more secure ecosystem of decentralized applications and encourage developers to build with best practices.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

## FLIP 123

On Flow, we have absorbed all security complexity into the platform.

[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes) was introduced to provide a safe pattern to use randomness in transactions so that it's not possible to revert non-favorable randomized transaction results.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
We recommend this approach as a best-practice example for implementing a commit-reveal-recover scheme in Cadence. The `RandomBeaconHistory` contract provides a convenient archive, where for each past block height (starting Nov 2023) the respective “source of randomness” can be retrieved. The `RandomBeaconHistory` contract is automatically executed by the system at each block to store the next source of randomness value.

<Callout type="info">
💡 While the commit-and-reveal scheme mitigates post-selection of results by adversarial clients, Flow’s secure randomness additionally protects against any pre-selection vulnerabilities (like biasing attacks by byzantine miners).
</Callout>

A commit-reveal scheme can be implemented as follows. The coin toss example described earlier will be used for illustration:

- When a user submits a bidding transaction, the bid amount is transferred to the coin toss contract, and the block height where the bid was made is stored. This is a commitment by the user to use the SoR at the current block. Note that the current block's `SoR_A` isn't known to the transaction execution environment, and therefore the transaction has no way to inspect the random outcome and predict the coin toss result. The current block's `SoR_A` is only available once added to the history core-contract, which only happens at the end of the block's execution. The user may also commit to using an SoR of a future block, which is still unknown at the time the bid is made.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
- The coin toss contract may grant the user a limited window of time (i.e a block height range) to reveal the results and claim any winnings. Failing to do so, the bid amount remains in the coin toss contract.
- The user can submit a second transaction to call the coin toss contract and resolve the bid. The coin toss contract looks up the committed block height of the user and checks it has already passed. The contract uses the block height to query the past-block's `SoR_A` on the core-contract `RandomBeaconHistory`.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
- The coin toss contract uses a PRG seeded by the queried `SoR_A` and diversified using a specific information to the use-case (a user ID or resource ID for instance). Diversification does not add new entropy, but it avoids generating the same outcome for different use-cases. If a diversifier (or salt) isn't used, all users that committed a bid on the same block would either win or lose.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
- The PRG is used to generate the random result and resolve the bid. Note that the user can make the transaction abort after inspecting a losing result. However, the bid amount would be lost anyway when the allocated window expires.

The following lines of code illustrate a random coin toss, that cannot be gamed or biased. The reveal-and-commit scheme prevent clients from post-selecting favorable outcomes.

It proceeds with two phases: first commit using the hash of the values and in a later phase revealing the values.
chasefleming marked this conversation as resolved.
Show resolved Hide resolved

```cadence
/// --- Commit ---
chasefleming marked this conversation as resolved.
Show resolved Hide resolved
/// In this method, the caller commits a bet. The contract takes note of the
/// block height and bet amount, returning a Receipt resource which is used
/// by the better to reveal the coin toss result and determine their winnings.
access(all) fun commitCoinToss(bet: @FungibleToken.Vault): @Receipt {
let receipt <- create Receipt(
betAmount: bet.balance
)
// commit the bet
// `self.reserve` is a `@FungibleToken.Vault` field defined on the app contract
// and represents a pool of funds
self.reserve.deposit(from: <-bet)

emit CoinTossBet(betAmount: receipt.betAmount, commitBlock: receipt.commitBlock, receiptID: receipt.uuid)

return <- receipt
}

/// --- Reveal ---
/// Here the caller provides the Receipt given to them at commitment. The contract
/// then "flips a coin" with randomCoin(), providing the committed block height
/// and salting with the Receipts unique identifier.
/// If result is 1, user loses, if it's 0 the user doubles their bet.
/// Note that the caller could condition the revealing transaction, but they've
/// already provided their bet amount so there's no loss for the contract if
/// they do
access(all) fun revealCoinToss(receipt: @Receipt): @FungibleToken.Vault {
pre {
receipt.commitBlock <= getCurrentBlock().height: "Cannot reveal before commit block"
}

let betAmount = receipt.betAmount
let commitBlock = receipt.commitBlock
let receiptID = receipt.uuid
// self.randomCoin() errors if commitBlock <= current block height in call to
// RandomBeaconHistory.sourceOfRandomness()
let coin = self.randomCoin(atBlockHeight: receipt.commitBlock, salt: receipt.uuid)

destroy receipt

if coin == 1 {
emit CoinTossReveal(betAmount: betAmount, winningAmount: 0.0, commitBlock: commitBlock, receiptID: receiptID)
return <- FlowToken.createEmptyVault()
}

let reward <- self.reserve.withdraw(amount: betAmount * 2.0)

emit CoinTossReveal(betAmount: betAmount, winningAmount: reward.balance, commitBlock: commitBlock, receiptID: receiptID)

return <- reward
}
```

## An Invitation to Build

Flow's onchain randomness opens new doors for innovation in web3, offering developers the tools to create fair and transparent decentralized applications. With this feature, new possibilities emerge—from enhancing gameplay in decentralized gaming to ensuring the integrity of smart contract-driven lotteries or introducing novel mechanisms in DeFi.

This is an invitation for builders and creators: leverage Flow's onchain randomness to distinguish your projects and push the boundaries of what's possible. Your imagination and code have the potential to forge new paths in the web3 landscape. So go ahead and build; the community awaits the next big thing that springs from true randomness.

## Learn More

If you’d like to dive deeper into Flow’s onchain randomness, here’s a list of resources:

- To learn more about how randomness works under the hood, see [the forum post](https://forum.flow.com/t/secure-random-number-generator-for-flow-s-smart-contracts/5110).
- These documents provide a more in-depth technical understanding of the updates and enhancements to the Flow blockchain.
- **[FLIP 120: Update unsafeRandom function](https://github.com/onflow/flips/blob/main/cadence/20230713-random-function.md#flip-120-update-unsaferandom-function)**
- **[FLIP 123: On-chain Random beacon history for commit-reveal schemes](https://github.com/onflow/flips/blob/main/protocol/20230728-commit-reveal.md#flip-123-on-chain-random-beacon-history-for-commit-reveal-schemes)**
- To see working Cadence code, explore the [coin toss example on GitHub](https://github.com/onflow/random-coin-toss/tree/update-prg-impl).
- Read the blog post announcing Flow’s native randomness.
- [https://www.notion.so/6f5ddb29d11c4a3aae1bbf4746bf780c?pvs=25](https://www.notion.so/On-chain-Randomness-On-Flow-6f5ddb29d11c4a3aae1bbf4746bf780c?pvs=21)