Try   HackMD

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.