## Voting on GRAM In ETH2, we have two parameters for deciding on the ETH1 chain for inclusion of deposits in the deposit contract. | Parameter | Mainnet Value | |-----------|-------| | `ETH1_FOLLOW_DISTANCE` | 1024 ETH1 blocks | | `SLOTS_PER_ETH1_VOTING_PERIOD` (aka `ETH1_DATA_VOTING_PERIOD`) | 1024 ETH2 slots | Every `SLOTS_PER_ETH1_VOTING_PERIOD`, the validators undergo a round of voting on the GRAM chain. `ETH1_FOLLOW_DISTANCE` exists to provide some additional security / finality in the ETH1 deposit contract. With the ETH1 follow distance we ensure that deposits have been present in ETH1 for at least 1024 blocks before being considered for inclusion. - A voting period starts when `slot % SLOTS_PER_ETH1_VOTING_PERIOD == 0`. - If consensus is not reached within the voting period, all votes are discarded and a new round of voting starts. - Once any distinct ETH1Data vote reaches `SLOTS_PER_ETH1_VOTING_PERIOD/2` votes, the state ETH1Data is updated and new deposits can be included. A quick look at the ETH1Data datastructure: ```python class Eth1Data(Container): deposit_root: Hash # Deposit trie root of latest deposit in deposit contract for the given block hash. deposit_count: uint64 # Total number of deposits in contract for this block hash. block_hash: Hash # ETH1 block hash determined for consensus. ``` ## Simple Voting Algorithm Given an honest majority assumption, we can determine our vote about the ETH1 chain as follows: 1. Determine the voting period start slot. `period_start_slot = slot - (slot%SLOTS_PER_ETH1_VOTING_PERIOD)`. 1. Determine timestamp of `period_start_slot`. 1. Determine the highest ETH1 block before that timestamp. 1. Determine the `ETH1_FOLLOW_DISTANCE`th ancestor of that block. (`block.number - ETH1_FOLLOW_DISTANCE`). 1. Use this block to read the deposits in the deposit contract. 1. Package the ETH1Data object and include into a block. ### Example ```graphviz digraph G { rankdir=LR; subgraph eth2 { node [shape="box"]; before_eth2[label="ETH2" shape=none] before_eth2->51200[dir="back",minlen=6,style="dotted"]; 51200->51201[dir="back"]; 51201->51202[dir="back"]; 51202->51203[dir="back"]; 51203->51204[dir="back"]; } subgraph eth1 { node [shape="box"]; before_eth1[label="ETH1" shape=none] before_eth1->7999999[dir="back",style="dotted"]; 7999999[shape="record" label="<number>7999999|<hash>Hash=0xB3DF|<root>Deposit Trie Root=0x0B|<deposits>Deposits=553"]; 8000000[shape="record" label="<number>8000000|<hash>Hash=0x54AC|<root>Deposit Trie Root=0x0A|<deposits>Deposits=555"]; 7999999->8000000[dir="back" minlen=1]; 8000000->8001024[dir="back" style="dotted" minlen=4]; 8001024->8001025[dir="back" minlen=2]; 8001025->8001026[dir="back" minlen=2]; } { rank=same; 51200; 8001024;} 51200 -> 8001024 [label="Highest block up to timestamp t" minlen=2 arrowhead=none]; } ``` Given the graph above and the current slot being 51205, we can start fulfill the process as follows: 1. The period start slot would be `51205 - (51205 % 1024)` which comes out to be `51200`. 2. The start time of slot `51200` is determined to be `t`. 3. The highest block observed with a timestamp less than `t` is block `8001024`. 4. The `ETH1_FOLLOW_DISTANCE`th ancestor is block at height `8001024 - 1024 = 8000000`. 5. Using this block, we read the deposit contract data and package our ETH1 data vote. ```python eth1data = { deposit_root = 0x0A, deposit_count = 555, block_hash = 0x54AC, } ``` 6. Propose the beacon block. ## Voting With The Majority Block production in ETH1 is probabilistic and typically generates blocks every 14 seconds, on average. Due to the probabilistic nature of block production in ETH1, blocks could be generated in quick succession and lead to high disparity in validators ETH1 votes to the degree that consensus is difficult to reach. In the previous example, imagine that ETH1 block `8001024` and `8001025` are timestamped within 100ms of each other. A minor clock skew between machines or client implementations may prefer one block over the other. Additionally, This problem may be exacerbated if ETH2 reduced the `ETH1_FOLLOW_DISTANCE`. ### Extended Simple Voting Algorithm ```python head_of_voting_period = [0...integer_squareroot(SLOTS_PER_ETH1_VOTING_PERIOD)] ``` In mainnet configuration, the head of the voting period is the first 32 slots of the period `sqrt(1024) = 32`. If we are in the "head" of the voting period, use the simple voting algorithm above. Otherwise, let's consider the majority vote for our ETH1Data vote. 1. Determine the voting period start slot. `period_start_slot = slot - (slot%SLOTS_PER_ETH1_VOTING_PERIOD)`. 1. Determine timestamp of `period_start_slot`. 1. Determine the highest ETH1 block before that timestamp. 1. Determine the `ETH1_FOLLOW_DISTANCE`th ancestor of that block. (`block.number - ETH1_FOLLOW_DISTANCE`). This is the upperbounds of the ETH1 blocks in this voting period. 1. Determine start slot of the previous voting period. `previous_period_start_slot = period_start_slot-SLOTS_PER_ETH1_VOTING_PERIOD`. 1. Determine timestamp of `previous_period_start_slot`. 1. Determine the highest ETH1 block before that timestamp. 1. Determine the `ETH1_FOLLOW_DISTANCE`th ancestor of that block. (`block.number - ETH1_FOLLOW_DISTANCE`). This is the lower bounds of the ETH1 blocks in this voting period. 1. Look at existing votes for this voting period, filter out any that vote on a block which is not present in this range of ETH1 blocks. 1. If no votes exist in the ETH1 range of blocks, use the block from step 4 as the block to vote. 1. If votes exist in the ETH1 range of blocks, choose the vote with the highest count. Prefer the vote with the highest ETH1 block height in the event of a tie. This step is voting with the majority, in which we agree that the block in ETH1 is in the canonical chain and there has been at least 1024 blocks between the start of the voting period and block we are voting on. 1. Construct the ETH1Data and propose the block. ### Example ```graphviz digraph G { rankdir=LR; subgraph eth2 { node [shape="box"]; before_eth2[label="ETH2" shape=none] before_eth2->51200[dir="back",minlen=6,style="dotted"]; 51200->51201[dir="back"]; 51201->51244[dir="back", style="dotted",minlen=2]; } subgraph eth1 { node [shape="box"]; before_eth1[label="ETH1" shape=none] before_eth1->7999999[dir="back",style="dotted"]; 7999999[shape="record" label="<number>7999999|<hash>Hash=0xB3DF|<root>Deposit Trie Root=0x0B|<deposits>Deposits=553"]; 8000000[shape="record" label="<number>8000000|<hash>Hash=0x54AC|<root>Deposit Trie Root=0x0A|<deposits>Deposits=555"]; 7999999->8000000[dir="back" minlen=1]; 8000000->8001024[dir="back" style="dotted" minlen=4]; 8001024->8001025[dir="back" minlen=1]; } { rank=same; 51200; 8001024;} 51200 -> 8001024 [label="Highest block up to timestamp t" minlen=2 arrowhead=none]; } ``` - The current slot is `51245`. - The voting period started at slot `51200`. - The highest ETH1 block at slot `51200` is block`8001024`. - The upper bounds for this voting period is `8001024 - 1024` = `8000000`. - The previous voting period started at `50176`. - The highest ETH1 block at slot `50176` is block `8000586`. _omitted from diagram to save space._ - The lower bounds for this voting period is `8000586 - 1024` = `7999562`. *ETH1Data votes in this voting period so far:* | Vote block hash | Count | |-----------------|-------| | `0xB3DF` | `31` | | `0x54AC` | `10` | | `0xAC54` | `2` | | `0xBEEF` | `1` | Looking at these 44 votes, we can see that the majority of validators attest that `7999999` is the last block in the voting period window. Although this is different from our validators view about ETH 1 (we see `8000000` as the last block in the window), the block at height `7999999` is still within the window so we'll agree with majority. Favoring the majority may lead to faster consensus in ambiguous situations. ### Why Wait to Determine Majority? Having some delay in determining the majority allows for a larger sample set. A larger sample set decreases the influence of the first vote since the first vote would always be the majority when the sample size is 1. ### What About a Stalled ETH1 Chain? In the event that Ethereum 1 appears stalled, either because it actually is stalled or there is a problem with our ETH1 connection, we would continue with the algorithm as described above. In either case, the validator(s) would never come to consensus on advancing a stalled chain. Or perhaps that would come to consensus but the ETH1Data in the state would not advance.