The mechanism is the same as in our design doc. I'm summarizing here implementation details.
x
(think 4") we decide that any block after this is subject to be reorgedy
(think 10") we evaluate our chances.0
func (f *Forkchoice) SetJustifiedBalances([]uint64)
func (f *Forkchoice) ProposerHead() [32]byte
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.
onBlock
is modified to not update Head if the block arrives after x
and not call notifyEngineIfChangedHead
subsequently.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.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.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()
The main dangerous changes are being done in the BlockChain package. From the point of view of a proposer the following happens
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.
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.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.
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.