It's impossible to have 0b111 without triggering Rule 2. Observe the bit position of previous_epoch - 1,
j
0b10
p
j
0b111
Rule 2: Set state.finalized_epoch = state.previous_justified_epoch if (state.justification_bitfield >> 1) % 4 == 0b11 and state.previous_justified_epoch == previous_epoch - 1.
Rule 3: Set state.finalized_epoch = state.justified_epoch if (state.justification_bitfield >> 0) % 8 == 0b111 and state.justified_epoch == previous_epoch - 1.
Related:
Rule 1 might also have some issue, it can only finalize the epoch that was already finalized by Rule 2.
Suppose that at the end of epoch N+2, epoch N+1 is justified but epoch N+2 is not. Then, at the end of epoch N+3, epochs N+1, N+2 and N+3 are all justified, because of messages that were not yet included in the chain before.
That case will trigger rule 2 before 3. because N+1 is now previous justified epoch and the bitfield in rule 3 is a special case of the bitfield in rule 2
Ok, try this:
Rule (2) does not get triggered because prev LJE is NOT previous_epoch - 1, but rule (3) does get triggered because LJE is previous_epoch - 1, the previous epoch is justified, and the current epoch is justified.
Alright, finally find the problem. Some case could trigger two rules at the same time.
I made a wrong assumption and implement the spec wrong. The wrong implementation returns the finalized epoch when a rule is triggered, while in the correct one every rule must be checked.
A simulation in Trinity shows that:
A quick look into the different codebases.
Thank you v for the example 鉂わ笍
Thanks @hwwhww :)
I've drew up some diagrams a while ago and noticed the same thing about double-execution.
Something that I haven't quite got my head across is why rules #1,3 require there to be two justified epochs following the finalized epoch, whilst #2,4 only require one.
The meta-rule behind all four rules is that if there are two epochs B[1] and B[n], where both are justified and B[n] was justified using B[1] as a source, and all intermediate epochs B[2] ... B[n-1] are all also justified (no matter what source), then B[1] can be finalized.
Rules 1 and 3 cover the n=3 case (the difference between the two is that rule 1 assumes that the _current epoch_ is n+1, and rule 3 assumes it's n),and rules 2 and 4 cover the n=2 case.
The reason why any rule except rule 4 (the only rule in the original FFG paper) is necessary is to cover the possibility that it takes an entire epoch for attestations to get included in the chain, and so epoch 1 can't get justified until the chain has already moved on to epoch 2.
The meta-rule behind all four rules is that if there are two epochs
B[1]andB[n], where both are justified andB[n]was justified usingB[1]as a source, and all intermediate epochsB[2] ... B[n-1]are all also justified (no matter what source), thenB[1]can be finalized.Rules 1 and 3 cover the n=3 case (the difference between the two is that rule 1 assumes that the _current epoch_ is n+1, and rule 3 assumes it's n),and rules 2 and 4 cover the n=2 case.
The reason why any rule except rule 4 (the only rule in the original FFG paper) is necessary is to cover the possibility that it takes an entire epoch for attestations to get included in the chain, and so epoch 1 can't get justified until the chain has already moved on to epoch 2.
So my understanding of the FFG paper was that justification can happen to any past epoch as well. But we only allow attestations to the current and previous epoch. So I guess that is why we have those two cases, whereas I would have expected that we need to check all past epochs for justification/finalisation?
Is there a description of the exact consensus algorithm that is used?
We have these limited cases because of a few reasons:
The combination of these three attributes create the 4 possible cases possible to satisfy the general rule described here https://github.com/ethereum/eth2.0-specs/issues/611#issuecomment-463896109
If we allowed 3 epochs of inclusions rather than two, we would need to cover the n=4 case (or change the state a bit to handle things more generally).
There is a WIP academic paper describing this more general purpose finality rule and it's instantiation in a PoS chain similar to our beacon chain. Will share when there's a draft ready
OK, thanks :) This helps me understand what's going on.
Most helpful comment
The meta-rule behind all four rules is that if there are two epochs
B[1]andB[n], where both are justified andB[n]was justified usingB[1]as a source, and all intermediate epochsB[2] ... B[n-1]are all also justified (no matter what source), thenB[1]can be finalized.Rules 1 and 3 cover the n=3 case (the difference between the two is that rule 1 assumes that the _current epoch_ is n+1, and rule 3 assumes it's n),and rules 2 and 4 cover the n=2 case.
The reason why any rule except rule 4 (the only rule in the original FFG paper) is necessary is to cover the possibility that it takes an entire epoch for attestations to get included in the chain, and so epoch 1 can't get justified until the chain has already moved on to epoch 2.