When writing smart contracts in NEAR you have access to a random seed
that enables you to create random numbers/strings
within your contract.
This random seed
is deterministic and verifiable: it comes from the validator that produced the block signing the previous
block-hash with their private key.
The way the random seed is created implies two things:
-
Only the validator mining the transaction can predict which random number will come out. No one else could predict it because nobody knows the validator’s private key (except the validator itself).
-
The validator cannot interfere with the random number being created. This is because they need to sign the previous block, over which (with a high probability) they had no control.
However, notice that this still leaves room for three types of attacks from the validator:
- Frontrunning, which we cover in another page
- Gaming the input
- Refusing to mine the block.
Gaming the Input
Imagine you have a method that takes an input and gives a reward based on it. For example, you ask the user to choose a number,
and if it the same as your random seed
you give them money.
Since the validator knows which random seed
will come out, it can create a transaction with that specific input and win the prize.
Refusing to Mine the Block
One way to fix the "gaming the input" problem is to force the user to send the input first, and then decide the result on a different block.
Let’s call these two stages: "bet" and "resolve".
In this way, a validator cannot game the input, since the random
number against which it will be compared is computed in a different block.
However, something that the validator can still do to increase their chance of winning is:
- Create a "bet" transaction with an account.
- When it’s their turn to validate, decide if they want to "resolve" or not.
If the validator, on their turn, sees that generating a random number makes them win, they can add the transaction to the block. And if they
see that they will not, they can skip the transaction.
While this does not ensure that the validator will win (other good validators could mine the transaction), it can improve their chance of winning.
Imagine a flip-coin game, where you choose heads
or tails
in the "bet" stage, and later resolve if you won or not. If you are a validator
you can send a first transaction choosing either input.
Then, on your turn to validate, you can check if your chosen input came out. If not, you can simply skip the transaction. This brings your
probability of winning from 1/2
to 3/4
, that’s a 25% increase!
These odds, of course, dilute in games with more possible outcomes.
How does the math work here?
Imagine you always bet for `heads`.
In a fair coin-flip game you have 50-50 percent chance of winning, this is because after the coin is flipped there are two possible outcomes:
`H` and `T`, and you only win in one (`H`).
However, if you can choose to flip again if `tails` comes out, now there are 4 scenarios: `H H` `T H` `H T` `T T`, and in 3 of those
you win (all the ones including an `H`)!!!.