# Reorg of late blocks The mechanism is the same as in our design doc. I'm summarizing here implementation details. - At threshold `x` (think 4") we decide that any block after this is subject to be reorged - At threhold `y` (think 10") we evaluate our chances. - Final decisions are always done at second `0` ## Changes to Forkchoice - Forkchoice will emit a message whenever justified checkpoint has changed. - Forkchoice will have a new setter `func (f *Forkchoice) SetJustifiedBalances([]uint64)` - Forkchoice will have a new getter `func (f *Forkchoice) ProposerHead() [32]byte` ## Changes to StateGen StateGen will now listen to the justified checkpoint changed message from forkchoice. When it gets such a message it calls `Forkchoice.SetJustifiedBalances` with the effective balances at the justified checkpoint. ## Changes to BlockChain Package - `onBlock` is modified to not update Head if the block arrives after `x` and not call `notifyEngineIfChangedHead` subsequently. - BlockChain package now is required to process attestations every block at `y` in addition to `0`. The way this is currently achieved is by calling `NewSlot` on a ticker, and then right after calling `UpdateHead`. - `UpdateHead` signature will change to `func (s *Service) UpdateHead(*context.Context) ([32]byte, error)`. It will return the new head root. - After calling to `UpdateHead`, both at second `y` and `0`, blockchain will call `Forkchoice.ProposerHead()` if these two are equal, then blockchain package will call `Service.notifyEngineIfChangedHead`. If they differ, then no call to the engine is made. ## Changes to the validator server - When requested to propose a block, the proposer will not build a block on top of `Head()` but rather `ProposerHead()` - No changes when attesting, we will always attest on `Head()` ## Rationale The main dangerous changes are being done in the BlockChain package. From the point of view of a proposer the following happens - At second `y` we process attestations and call to `UpdateHead` forkchoice knows at this stage if we need to fork or not the last block. if we need to fork it then it will return a different head than the `ProposerHead` so we do not need to call FCU. If the updated head is the same as the `ProposerHead` that means that we will not be forking the block, so we have to call FCU. This has to be done also at second `0`. From the point of view of an attester there are no changes. At second `y` and at second `0` we have updated head so there's nothing to worry, the right head is computed by the time we attest. If we proposed a block, we will import our own block before attesting, and so it will attest to our own head. - There is one danger, that at second `y` or second `0` the return from `UpdateHead()` and `ProposerHead()` are both different and both of them are different than the previous head. Forkchoice will take care that this never happens, so that when `UpdateHead` and `ProposerHead` are both different than the previous head, then it will return both of them equal, thus forcing the beacon to call FCU. ## How does forkchoice compute `ProposerHead`? Forkchoice gets calls to `Head()` after each process attestations. And it has the timings for each inserted block, so it can at each computation of `Head()` assess if the new head has changed, and if it was because of a late block, it can check itself the `10%` threshold condition. So it can decide on each call to `Head()` if the `ProposerHead` needs to be updated or not. ## Non-Goals We could have a message system also for when Head updates. Blockchain could then update it's head view. This is part of the program of deprecating the `head` package.