Documentation ¶
Overview ¶
Package sync is responsible for reconciling L1 and L2.
The Ethereum chain is a DAG of blocks with the root block being the genesis block. At any given time, the head (or tip) of the chain can change if an offshoot/branch of the chain has a higher total difficulty. This is known as a re-organization of the canonical chain. Each block points to a parent block and the node is responsible for deciding which block is the head and thus the mapping from block number to canonical block.
The Optimism (L2) chain has similar properties, but also retains references to the Ethereum (L1) chain. Each L2 block retains a reference to an L1 block (its "L1 origin", i.e. L1 block associated with the epoch that the L2 block belongs to) and to its parent L2 block. The L2 chain node must satisfy the following validity rules:
- l2block.number == l2block.l2parent.block.number + 1
- l2block.l1Origin.number >= l2block.l2parent.l1Origin.number
- l2block.l1Origin is in the canonical chain on L1
- l1_rollup_genesis is an ancestor of l2block.l1Origin
During normal operation, both the L1 and L2 canonical chains can change, due to a re-organisation or due to an extension (new L1 or L2 block).
In particular, in the case of L1 extension, the L2 unsafe head will generally remain the same, but in the case of an L1 re-org, we need to search for the new safe and unsafe L2 block.
Index ¶
Constants ¶
const ( CLSyncString string = "consensus-layer" ELSyncString string = "execution-layer" )
const MaxReorgSeqWindows = 5
const RecoverMinSeqWindows = 14
RecoverMinSeqWindows is the number of sequence windows between the unsafe head L1 origin, and the finalized block, while finality is still at genesis, that need to elapse to heuristically recover from a missing forkchoice state. Note that in healthy node circumstances finality should have been forced a long time ago, since blocks are force-inserted after a full sequence window.
Variables ¶
var ModeStrings = []string{CLSyncString, ELSyncString}
var Modes = []Mode{CLSync, ELSync}
var ReorgFinalizedErr = errors.New("cannot reorg finalized block")
var TooDeepReorgErr = errors.New("reorg is too deep")
var WrongChainErr = errors.New("wrong chain")
Functions ¶
This section is empty.
Types ¶
type Config ¶ added in v1.1.4
type Config struct { // SyncMode is defined above. SyncMode Mode `json:"syncmode"` // SkipSyncStartCheck skip the sanity check of consistency of L1 origins of the unsafe L2 blocks when determining the sync-starting point. // This defers the L1-origin verification, and is recommended to use in when utilizing --syncmode=execution-layer on op-node and --syncmode=snap on op-geth // Warning: This will be removed when we implement proper checkpoints. // Note: We probably need to detect the condition that snap sync has not complete when we do a restart prior to running sync-start if we are doing // snap sync with a genesis finalization data. SkipSyncStartCheck bool `json:"skip_sync_start_check"` SupportsPostFinalizationELSync bool `json:"supports_post_finalization_elsync"` }
type FindHeadsResult ¶
type FindHeadsResult struct { Unsafe eth.L2BlockRef Safe eth.L2BlockRef Finalized eth.L2BlockRef }
func FindL2Heads ¶
func FindL2Heads(ctx context.Context, cfg *rollup.Config, l1 L1Chain, l2 L2Chain, lgr log.Logger, syncCfg *Config) (result *FindHeadsResult, err error)
FindL2Heads walks back from `start` (the previous unsafe L2 block) and finds the finalized, unsafe and safe L2 blocks.
- The *unsafe L2 block*: This is the highest L2 block whose L1 origin is a *plausible* extension of the canonical L1 chain (as known to the op-node).
- The *safe L2 block*: This is the highest L2 block whose epoch's sequencing window is complete within the canonical L1 chain (as known to the op-node).
- The *finalized L2 block*: This is the L2 block which is known to be fully derived from finalized L1 block data.
Plausible: meaning that the blockhash of the L2 block's L1 origin (as reported in the L1 Attributes deposit within the L2 block) is not canonical at another height in the L1 chain, and the same holds for all its ancestors.
type L1Chain ¶
type L1Chain interface { L1BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L1BlockRef, error) L1BlockRefByNumber(ctx context.Context, number uint64) (eth.L1BlockRef, error) L1BlockRefByHash(ctx context.Context, hash common.Hash) (eth.L1BlockRef, error) }
type L2Chain ¶
type L2Chain interface { L2BlockRefByHash(ctx context.Context, l2Hash common.Hash) (eth.L2BlockRef, error) L2BlockRefByLabel(ctx context.Context, label eth.BlockLabel) (eth.L2BlockRef, error) }
type Mode ¶ added in v1.4.2
type Mode int
There are two kinds of sync mode that the op-node does:
- In consensus-layer (CL) sync, the op-node fully drives the execution client and imports unsafe blocks & fetches unsafe blocks that it has missed.
- In execution-layer (EL) sync, the op-node tells the execution client to sync towards the tip of the chain. It will consolidate the chain as usual. This allows execution clients to snap sync if they are capable of it.