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 B L (5) o---------o----------o | <--- imported ---> | C D H o---------------------o----------------o | <-- unprocessed --> | <-- linked --> | where * *B* -- **base**, current value of this entity (with the same name) of the **FC** module (i.e. the current value when looked up.) * *C* -- coupler, parent of the left endpoint of the chain of headers or blocks to be fetched and imported. The block number of *C* is somewhere between the ones of *B* and *C* inclusive. * *L* -- **latest**, current value of this entity (with the same name) of the **FC** module (i.e. the current value when looked up.) *L* need not be a parent of any header of the linked chain `(C,H]` (see below for notation). Both *L* and *H* might be heads of different forked chains. * *D* -- dangling, header with the 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 B (9) o------------o-------o | <--- imported ---> | D C H o--------------------------------------o | <----------- unprocessed ----------> | with a new sync state *(C,H,H)*. The parameter *B* is the **base** entity of the **FC** module. The parameter *C* is a placeholder with *C ~ B*. The parameter *D* is set to the download start position *H*. The syncer then fetches the header chain *(C,H]* from the network. While iteratively fetching headers, the syncer state *(C,D,H)* will only change on its second position *D* time after a new header was fetched. Having finished downloading then *C~D-1*. The sync state is *(D-1,D,H)*. One will end up with a situation like 0 Y L (10) o---------------o----o | <--- imported ---> | C Z H o----o---------------------------------o | <-------------- linked ------------> | for some *Y* in *[0,L]* and *Z* in *(C,H]* where *Y< | Y H o-----------------------------------o | <------------ blocks -----------> | The blocks *(Y,H]* will then be imported and executed. While this happens, the internal state of the **FC** might change/reset so that further import becomes impossible. Even when starting import, the block *Y* 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. In case all blocks can be imported, one will will end up at 0 Y H L (12) o-----------------o---------------------------------o---o | <--- imported --------------------------------------> | with *H<