owned this note
owned this note
Published
Linked with GitHub
# PoE - 1.5
[TOC]
## Glossary
- **PoE** --> Proof-of-Efficiency model, consensus mechanism
- **bridge** --> contract that handles asset transfers between networks
- **GlobalExitRootManager** --> contract responsible for managing exit roots across multiple networks
- **GlobalExitRootManagerL2** --> contract responsible for managing global exit root in zkEVM, this contract will be managed by the circuit
## Motivation
For the implementation of the zk-EVM, a consensus mechanism for a decentralized L2 protocol is necessary.
This consensus mechanism defines a two-step model where:
- Permissionless Sequencers as benefited participants in the protocol
- The computation of a "virtual" state from the data availability and a "final" state based on the validity proofs
- Space for permissionless Aggregators as the agents to perform the specialized task of cryptographic proof generation
## Specification
This protocol separates batch sent and validated. Therefore, we find two parts:
- **Sequencers**: collect L2 transactions from users. They select and create L2 batch in the network (sending ethereum transaction (encoded as RLP) with data of all selected L2 txs)
- collect L2 txs and propose batches
- pay MATIC to SC to propose a new batch
- 1 sequencer / 1 chainID
> The sequencer needs to register to get a chainID (Users needs to chose a chainID to sign. There's a default chainID valid for all sequencers. A sequencer can only send transactions with his chainID the default one
- **Aggregators**: create validity ZK proof of a new state of the L2 (for one or multiple batches)
- they have specialized hardware to create ZKP
- the first aggregator that sends a valid proof wins the race and get rewarded (MATIC sent by the sequencer)
- invalid transactions are skipped
- The proof must process all the transactions, or either proof that the transactions are invalid.
Then, the two steps are done one for each part:
- `sendBatch`: the **sequencer** sends a group of L2 transactions
- `validateBatch`: the **aggregator** validates de batch
![](https://i.imgur.com/dzDt6Zd.png)
There are two state types:
- **Virtual state**: state calculated from all pending batches of transactions
- **Validated state**: state confirmed by zpk
## Smart contract
### Actions
- registerSequencer
- sendBatch
- validateBatch
#### registerSequencer
- Parameters:
- sequencer RPC URL
- Smart Contract Actions:
- `mapping[address => Sequencer]` --> `Sequencer = {sequencerURL,chainID}`
```
registerSequencer(sequencerURL) {
mappingSeq[address] = { sequencerURL, chainID }
}
```
#### sendBatch
- Parameters:
- transactions `bytes` --> The transactions should be encoded in the following format:[$tx_0$ # $tx_1$ # $tx_2$ # ... # $tx_n$ ] where a tx should be encoded as following:
- `tx = rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s `
- matic max amount --> `uint256`
- Smart contract Actions:
- Compute sequencer collateral (could be changed)
```
function calculateSequencerCollateral() public view returns (uint256) {
return 1 ether * (1 + lastBatchSent - lastVerifiedBatch);
}
```
- Get bridge global exit root
```
bytes32 lastGlobalExitRoot = bridge.getLastGlobalExitRoot();
```
- Set chainID: default if the sequencer is not registered.
- State updates --> `mapping[numBatch]`
- batchHashData = `{ H(txs, lastGlobalExitRoot, block.timestamp, msg.sender (sequencer address), batchChainID, numBatch)}`
- maticCollateral
- Emit `sendBatch` event:
```
emit SendBatch(lastBatchSent, msg.sender, batchChainID, lastGlobalExitRoot);
```
```
sendBatch(bytes l2TxsData, uint256 maticAmount){
maticCollateral = calculateMaticCollateral
transfer(maticCollateral)
lastBatchSent++
currentGlobalExitRoot = bridge.currentGlobalExitRoot();
mappingSentBatches[lastBatchSent] = batchHashData, maticCollateral})
emit event SendBatch
}
```
> invalid L2 tx are selected as NOP
#### verifyBatch
- Parameters:
- `newLocalExitRoot`
- `newStateRoot`
- `numBatch` (sanity check)
- `proofA`, `proofB`, `proofC`
- Smart contract Actions:
- input:
- `currentStateRoot`: current state root
- `currentLocalExitRoot`: current local (rollup) exit root
- `newStateRoot`: new state root
- `newLocalExitRoot`: new local (rollup) exit root
- `batchHashData`
```
**Buffer bytes notation**
[ 256 bits ] currentStateRoot
[ 256 bits ] currentLocalExitRoot
[ 256 bits ] newStateRoot
[ 256 bits ] newLocalExitRoot
[ 256 bits ] batchHashData
```
- verify proof
- update state
- Communicate with bridge
- push newLocalExitRoot
- Get MATIC reward
- Emit verify Batch event
```
emit VerifyBatch(numBatch, msg.sender);
```
```
verifyBatch(newLocalExitRoot, newStateRoot, batchNum, proofA, proofB, proofC) {
require(batchNum == lastConfirmedBatch + 1)
input = calculateInput()
require(verifyProof)
lastVerifiedBatch++
currentStateRoot = newStateRoot;
currentLocalExitRoot = newLocalExitRoot;
bridge.updateRollupExitRoot(currentLocalExitRoot);
matic.transfer()
emit event VerifyBatch
}
```