# StakeManager

In Autonomy, executors execute `Request`s in exchange for a fee. If anyone could execute any `Request` at any time, then the Nash equilibrium would be that, for a given `Request` that paid a $1 fee, executors are willing to spend up to $1 collectively in order to compete for that profit. That means that, overall, nobody is making any money, and results in a very fragile ecosystem of executors that cannot be relied upon and is dominated by very few actors who could censor `Request`s. For example, if an executor could send more transactions that attempt to execute a given `Request`, that resulted in a 25% chance of success for a $1 profit, they'd be willing to spend up to $0.25 out their own pocket to maximize their chance of success. If 4 people in total do that, everyone spends $1 in total, and makes $1 in total. These kind of mempool games were infamously described as [the dark forest](https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest/).

In order to solve this problem, Autonomy implements a lightweight Proof of Stake algorithm in the `StakeManager` contract that stakes the platform token, AUTO. Instead of 'winning' the ability to mine a block, stakers instead receive the exclusive right to execute `Request`s on the network for an `epoch` (100 blocks on Ethereum). The more stake that a user stakes, the higher chance they have of 'winning' this right. This essentially gives them to right to perform work and receive the fees without competition for the `epoch`. This economic incentive essentially guarantees that a `Request` will be executed. It is similar to Proof of Work and Proof of Stake in the sense that the incentive for the staker is to execute as many `Request`s as possible while they can in order to maximize profit, in the same way that PoW/PoS miners want to include as many transactions in their block as possible in order to maximize their profit. It is true that an executor could censor a `Request`, but the next executor will have an incentive to execute all `Request`s, and aslong as there is atleast 1 purely economically incentivized executor, every `Request` will eventually be executed. The same is true for PoW/PoS - miners can censor some transactions from being in their block, but eventually another miner will include that transaction. Therefore, if the ability for an entity to censor a `Request` is of concern to someone, then they shouldn't use a blockchain in the first place, because even if executors couldn't censor `Requests`, the transaction to execute that `Request` could still be censored by a miner, and therefore, Autonomy doesn't increase the ability for that to happen.

## Staking

### Problematic Approach

In order to stake, stakers can call `stake` in the `StakeManager`. In Autonomy, you cannot stake any arbitrary amount of AUTO - this is basically down to gas and block gas limit constraints. For example if stakers could stake any amount and 3 stakers staked 3, 69, and 420 AUTO tokens each, resulting in `[3, 69, 420]`, the algorithm for selecting a 'winner', given a random number, would need to have knowledge of up to every element in this array. Iterating over an arbitrarily large array is prohibitively expensive, and could 'brick' the contract if the array gets so large that iterating it takes more than the block gas limit. For example, if a random number was obtained, and converted to a fraction of its maximum possible value, such as 0.415, then the algorithm would need to convert that to a proportion of the total. Assuming the total stake was cached (in this case, 492), this number would be 492 \* 0.415 = 204. The algorithm would need to iterate through the array, calculating the cumulative total and checking whether that cumulative total is more than 204 as it goes.

### Pragmatic Solution

In order to solve this gas problem, Autonomy uses constant sized stakes - `STAN_STAKE` - which is 10,000 AUTO. This means that the array of stakes is an array of staker's addresses, each element representing a single time they staked `SNAN_STAKE` amount of AUTO. Someone that stakes 20,000 AUTO tokens would therefore have 2 entries in this array, rather than having an array or mapping where each staker only has a single entry as in the 'Problematic Approach' case. For example, the stake array would look like `[addrA, addrB, addrB, addrC]` if `addrA` staked 10k, `addrB` staked 20k, and `addrC` staked 10k. This allows the fraction (0.415) to be multiplied by the length of the array and instantly obtain and index of the winner: 0.415 \* 4 = 1 = `addrB` (in Solidity, all decimals are dropped, as everything is an integer). Stakers are forced to stake in increments of `STAN_STAKE`, but the tradeoff is that selecting a 'winner' is constant time and very low gas, which is important since this happens every `epoch`.

## Epochs

The `epoch` as a number is basically defined as the starting block number of an epoch. For Ethereum, since the number of blocks in each `epoch` (`EPOCH_LENGTH`) is 100, the `epoch` for block 420 is 400. The `epoch` for block 39487969 is 39487900. This means that `epoch`s increase in increments of `EPOCH_LENGTH` rather than in increments of 1.

Randomness is obtained using the blockhash of the block just before the start of the `epoch`. For example, for `epoch` 400, the blockhash used is from block 399, and for `epoch` 39487900, the blockhash used is from block 39487899. This is done so that the randomness used for a given `epoch` cannot be manipulated from within that `epoch`. It is true that blockhashes can be manipulated by miners, but this is expensive to do in PoW, and does not affect the security of Autonomy, since the only benefit to manipulating the randomness is to be able to be selected as the executor more often than otherwise and therefore be able to receive fees from a larger number of `Request`s. Once Ethereum moves to PoS itself, this mechanism will be changed to a randomness source more secure.

It's a bit annoying that `epoch`s go up in increments of 100 instead of 1, but the reason for this is because of how randomness is obtained. Since the blockhash for block `epoch - 1` is the source of the randomness, an `epoch` that increments by 1 would be 4 for block 420. Solidity is [constrained](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties) to only be able to lookup information about the previous 256 blocks. Therefore from block 420, it is impossible to look up information about block 3 from within the smart contract. This necessitates the source of randomness to be within the last 256 blocks, so that's why the `epoch` number needs to be within 256 of the current block number.

## Caching The Current Executor

Once the current executor is selected, their address is stored in `StakeManager`, along with the current `epoch` , partly because of gas savings from using it as a cache, but mainly so that it cannot be changed within the epoch. For example if someone updated the executor for the first time in the `epoch` at block 420, and someone came and staked some AUTO at block 421, then the result of selecting the executor might change because the array and its length has changed. Certainty of who is executing at what time, without that being able to be manipulated, is necessary. For that reason, every time someone stakes or unstakes, the executor for that epoch is selected (if they haven't been selected for the `epoch` already) **before** any changes are made to the stake array. This guarantees that nobody can unfairly manipulate who is selected as the executor, essentially making the executor for that `epoch` deterministic from the start of that `epoch`.

The way that execution of `Request`s actually interacts with the `StakeManager` is by all executions calling `isUpdatedExec` before doing anything else. If the executor is already set for this epoch, this checks whether the current executor is the set executor - if not, revert. If the executor for this epoch hasn't been set, then set it, and check whether the current executor is the new set executor - revert if not.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.autonomynetwork.io/autonomy-docs/autonomy-network/system-components/staking.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
