Beacon Sync =========== Some definition of terms, and a suggestion of how a beacon sync can be encoded providing pseudo code is provided by [Beacon Sync](https://notes.status.im/nimbus-merge-first-el?both=#Beacon-sync). In the following, the data domain the Beacon Sync acts upon is explored and presented. This leads to an implementation description without the help of pseudo code but rather provides a definition of the sync and domain state at critical moments. For handling block chain imports and related actions, abstraction methods from the `forked_chain` module will be used (abbreviated **FC**.) The **FC** entities **base** and **latest** from this module are always printed **bold**. Sync Logic Outline ------------------ Here is a simplification of the sync process intended to provide a mental outline of how it works. In the following block chain layouts, a left position always stands for an ancestor of a right one. 0------C1 (1) 0--------L1 (2) \_______H1 0------------------C2 (3) 0--------------------L2 (4) \________H2 where * *0* is genesis * *C1*, *C2* are the *latest* (aka cursor) entities from the **FC** module * *L1*, *L2*, are updated *latest* entities from the **FC** module * *H1*, *H2* are block headers (or blocks) that are used as sync targets At stage *(1)*, there is a chain of imported blocks *[0,C1]* (written as compact interval of block numbers.) At stage *(2)*, there is a sync request to advance up until block *H1* which is then fetched from the network along with its ancestors way back until there is an ancestor within the chain of imported blocks *[0,L1]*. The chain *[0,L1]* is what the *[0,C1]* has morphed into when the chain of blocks ending at *H1* finds its ancestor. At stage *(3)* all blocks recently fetched have now been imported via **FC**. In addition to that, there might have been additional imports from other entities (e.g. `newPayload`) which has advanced *H1* further to *C2*. Stage *(3)* has become similar to stage *(1)* with *C1* renamed as *C2*, ditto for the symbols *L2* and *H2* for stage *(4)*. Implementation, The Gory Details -------------------------------- ### Description of Sync State The following diagram depicts a most general state view of the sync and the *FC* modules and at a given point of time 0 C L (5) o------------o-------o | <--- imported ---> | Y D H o---------------------o----------------o | <-- unprocessed --> | <-- linked --> | where * *C* -- coupler, cached **base** entity of the **FC** module, reported at the time when *H* was set. This determines the maximal way back length of the *linked* ancestor chain starting at *H*. * *Y* -- has the same block number as *C* and is often, but not necessarily equal to *C* (for notation *C~Y* see clause *(6)* below.) * *L* -- **latest**, current value of this entity of the **FC** module (i.e. now, when looked up) * *D* -- dangling, least block number of the linked chain in progress ending at *H*. This variable is used to record the download state eventually reaching *Y* (for notation *D< | where *H<=L* (*H* needs only be known by its block number.) The state parameters *C* and *D* are irrelevant here. Following, there will be a request to advance *H* to a new position as indicated in the diagram below 0 C (9) o------------o-------o | <--- imported ---> | D Y H o--------------------------------------o | <----------- unprocessed ----------> | with a new sync state *(C,D,H)*. The parameter *C* in clause *(9)* is set as the **base** entity of the **FC** module. *Y* is only known by its block number, *Y~C*. The parameter *D* is set to the download start position *H*. The syncer then fetches the header chain *(Y,H]* from the network. For the syncer state *(C,D,H)*, while iteratively fetching headers, only the parameter *D* will change each time a new header was fetched. Having finished dowlnoading *(Y,H]* one might end up with a situation 0 B Z L (10) o-------------o--o---o | <--- imported ---> | Y Z H o---o----------------------------------o | <-------------- linked ------------> | where *Z* is in the intersection of *[B,L]\*(Y,H]* with *B* the current **base** entity of the **FC** logic. It is only known that *0< | Z H o----------------------------------o | <------------ blocks ----------> | The blocks *(Z,H]* will then be imported. While this happens, the internal state of the **FC** might change/reset so that further import becomes impossible. Even when starting import, the block *Z* might not be in *[0,L]* anymore due to some internal reset of the **FC** logic. In any of those cases, sync processing restarts at clause *(8)* by resetting the sync state. Otherwise the block import will end up at 0 Z H L (12) o----------------o----------------------------------o---o | <--- imported --------------------------------------> | with *H<