A validator ensures that SP nodes have submitted valid proofs each period where the smart contract required a proof to be submitted for slots filled by the SP node.
The diagram below depicts the lifecycle of a storage request:

## Client Role
A node implementing the client role mediates the persistence of data within the Codex network.
A client has two primary responsibilities:
- Requesting storage from the network by sending a storage request to the smart contract.
- Withdrawing funds from the storage requests previously created by the client.
### Creating Storage Requests
When a user prompts the client node to create a storage request, the client node SHOULD receive the input parameters for the storage request from the user.
| `expiry` | `uint256` | Timeout in seconds during which all the slots have to be filled, otherwise request will get cancelled. The final deadline timestamp is calculated at the moment the transaction is mined. |
| `reward` | `uint256` | Amount of tokens that will be awarded to SP nodes for finishing the storage request. It MUST be an amount of tokens offered per slot per second. The Ethereum address that submits the `requestStorage()` transaction MUST have [approval](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-approve-address-uint256-) for the transfer of at least an equivalent amount in tokens. |
| `collateral` | `uint256` | The amount of tokens that SP nodes MUST submit when they fill slots. Collateral is then slashed or forfeited if SP nodes fail to provide the service requested by the storage request (more information in the [Slashing](#slashing) section). The Ethereum address that submits the `fillSlot()` transaction MUST have [approval](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-approve-address-uint256-) for the transfer of at least an amount required for collateral. |
| `proofProbability` | `uint256` | Determines the average frequency that a proof is required within a period: $\frac{1}{proofProbability}$. SP nodes are required to provide proofs of storage to the marketplace smart contract when challenged by the smart contract. To prevent hosts from only coming online when proofs are required, the frequency at which proofs are requested from SP nodes is stochastic and is influenced by the `proofProbability` parameter. |
| `cid` | `string` | An identifier used to locate the Manifest representing the dataset. It MUST be a [CIDv1](https://github.com/multiformats/cid#cidv1), SHA-256 [multihash](https://github.com/multiformats/multihash) and the data it represents SHOULD be discoverable in the network, otherwise the request will be eventually canceled. |
It should be noted that the marketplace does not support extending requests. It is REQUIRED that if the user wants to extend the duration of a request, a new request with the same CID must be [created](#creating-storage-requests) **before the original request completes**.
This ensures that the data will continue to persist in the network at the time when the new (or existing) SP nodes need to retrieve the complete dataset to fill the slots of the new request.
- The request is considered `Cancelled` if no `requestFulfilled(requestId)` event is observed during the timeout specified by the value returned from the `requestExpiresAt(requestId)` function.
- The request is considered `Failed` when the `RequestFailed(requestId)` event is observed.
- The request is considered `Finished` after the interval specified by the value returned from the `getRequestEnd(requestId)` function.
-`ask` - the specification of the request parameters. For details, see the definition of the `Request` type in the [Creating Storage Requests](#creating-storage-requests) section above.
An SP node MUST decide which slot, specified by the slot index, it wants to fill. The SP node MAY attempt to fill more than one slot. To fill a slot, the SP node MUST first download the slot data using the CID of the manifest (**TODO: Manifest RFC**) and the slot index. The CID is specified in `request.content.cid`, which can be retrieved from the smart contract using `getRequest(requestId)`. Then, the node MUST generate a proof over the downloaded data (**TODO: Proving RFC**).
The Ethereum address, of the SP node from which the transaction originates, MUST have [approval](https://docs.openzeppelin.com/contracts/2.x/api/token/erc20#IERC20-approve-address-uint256-) for the transfer of at least the amount of required tokens.
If the proof delivered by the SP node is invalid or the slot was already filled by another SP node,
then the transaction will revert. Otherwise, a `SlotFilled(requestId, slotIndex)` event is emitted. If the transaction is successful, the SP node SHOULD transition into the __proving__ state, where it will need to submit proof of data possession when challenged by the smart contract.
Once an SP node fills a slot, it MUST submit proofs to the smart contract when a challenge is issued by the contract. SP nodes SHOULD detect that a proof is required for the current period using the `isProofRequired(slotId)` function,
or that it will be required using the `willProofBeRequired(slotId)` function in the case that the [pointer is in downtime](https://github.com/codex-storage/codex-research/blob/41c4b4409d2092d0a5475aca0f28995034e58d14/design/storage-proof-timing.md).
There is a slashing scheme orchestrated by the smart contract to incentivize correct behavior and proper proof submissions by SP nodes. This scheme is configured at the smart contract level and applies uniformly to all participants in the network. The configuration of the slashing scheme can be obtained via the `getConfig()` contract call.
- If the number of slashes exceeds `config.collateral.maxNumberOfSlashes`, the slot is freed, the remaining collateral is burned, and the slot is offered to other nodes for repair. The smart contract also emits the `SlotFreed(requestId, slotIndex)` event.
If, at any time, the number of freed slots exceeds the value specified by the `request.ask.maxSlotLoss` parameter, the dataset is considered lost, and the request is deemed _failed_. The collateral of all SP nodes that hosted the slots associated with the storage request is burned, and the `RequestFailed(requestId)` event is emitted.
When a slot is freed due to too many missed proofs, which SHOULD be detected by listening to the `SlotFreed(requestId, slotIndex)` event, an SP node can decide whether to participate in repairing the slot. Similar to filling a slot, the node SHOULD consider the operator's configuration when making this decision. The SP node that originally hosted the slot but failed to comply with proving requirements MAY also participate in the repair. However, by refilling the slot, the SP node **will not** recover its original collateral and must submit new collateral using the `fillSlot()` call.
The repair process is similar to filling slots. If the original slot dataset is no longer present in the network, the SP node MAY use erasure coding to reconstruct the dataset. Reconstructing the original slot dataset requires retrieving other pieces of the dataset stored in other slots belonging to the request. For this reason, the node that successfully repairs a slot is entitled to an additional reward. (**TODO: Implementation**)
1. The SP node observes the `SlotFreed` event and decides to repair the slot.
2. The SP node MUST download the chunks of data required to reconstruct the freed slot's data. The node MUST use the [Reed-Solomon algorithm](https://hackmd.io/FB58eZQoTNm-dnhu0Y1XnA) to reconstruct the missing data.
3. The SP node MUST generate proof over the reconstructed data.
4. The SP node MUST call the `fillSlot()` smart contract function with the same parameters and collateral allowance as described in the [Filling Slots](#filling-slots) section.
An SP node SHOULD monitor the requests and the associated slots it hosts.
When a storage request enters the `Cancelled`, `Finished`, or `Failed` state, the SP node SHOULD call the `freeSlot(slotId)` smart contract function.
The aforementioned storage request states (`Cancelled`, `Finished`, and `Failed`) can be detected as follows:
- A storage request is considered `Cancelled` if no `RequestFulfilled(requestId)` event is observed within the time indicated by the `expiry` request parameter. Note that a `RequestCancelled` event may also be emitted, but the node SHOULD NOT rely on this event to assert the request expiration, as the `RequestCancelled` event is not guaranteed to be emitted at the time of expiry.
- A storage request is considered `Finished` when the time indicated by the value returned from the `getRequestEnd(requestId)` function has elapsed.
- A node concludes that a storage request has `Failed` upon observing the `RequestFailed(requestId)` event.
For each of the states listed above, different funds are handled as follows:
- In the `Cancelled` state, the collateral is returned along with a proportional payout based on the time the node actually hosted the dataset before the expiry was reached.
- In the `Finished` state, the full reward for hosting the slot, along with the collateral, is collected.
- In the `Failed` state, no funds are collected. The reward is returned to the client, and the collateral is burned. The slot is removed from the list of slots and is no longer included in the list of slots returned by the `mySlots()` function.
In a blockchain, a contract cannot change its state without a transaction and gas initiating the state change. Therefore, our smart contract requires an external trigger to periodically check and confirm that a storage proof has been delivered by the SP node. This is where the validator role is essential.
It is the smart contract that checks if the proof requested from an SP node has been delivered. The validator only triggers the decision-making function in the smart contract. To incentivize validators, they receive a reward each time they correctly mark a proof as missing.
Each time a validator observes the `SlotFilled` event, it SHOULD add the slot reported in the `SlotFilled` event to the validator's list of watched slots. Then, after the end of each period, a validator has up to `config.proofs.timeout` seconds (a configuration parameter retrievable with `getConfig()`) to validate all the slots. If a slot lacks the required proof, the validator SHOULD call the `markProofAsMissing(slotId, period)` function on the smart contract. This function validates the correctness of the claim, and if right, will send a reward to the validator.
If validating all the slots observed by the validator is not feasible within the specified `timeout`, the validator MAY choose to validate only a subset of the observed slots.
## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).