Skip to main content

Synchronization

There are currently two methods to synchronize with the StarkNet chain (i.e., download, hold, and update the StarkNet state):

  1. The StarkWare feeder gateway (a centralized API provided by StarkWare) or
  2. The Layer 1 StarkNet contracts on the Ethereum chain (these contracts hold the StarkNet data on-chain, providing data availability).

API syncing

The syncing process with the feeder gateway is relatively simple: request a state update from the API like this and apply that state update to the local database.

Layer 1 Syncing

Syncing with the L1 contracts is more complicated. To do this, we listen for events emitted by the contracts to reconstruct the StarkNet state update.

The three key StarkNet contracts on L1 that we are interested in are:

  1. MemoryPageFactRegistry: stores a mapping between a fact (a hash of some data) and a memory page hash. This contract has an external function registerMemoryPageContinuous that accepts memory pages as input (data structure that contains L2 transaction data). When it receives a new valid memory page, the LogMemoryPageFactContinuous event is emitted with the hash of the registered memory page.
  2. GpsStatementVerifier: verifies proofs from layer 2. When this contract verifies a proof, it emits a LogMemoryPagesHashes event, which contains a fact (hash of data used in the verification process) and an array of memory page hashes.
  3. Starknet: transitions the StarkNet state. Emits a LogStateTransitionFact event with a fact corresponding to the state transition being processed. Once it completes additional safety checks, it will officially transition the state and emit a LogStateUpdate event with the new state root and Starknet block number (sequence number).

When syncing against L1, we need to work backwards through the above steps to reconstruct the original state update.

Since we cannot rely on receiving the events in chronological order, we hold three mappings to keep the information straight (one for each contract):

  1. memoryPage: memoryPageHash -> hash of the Ethereum transaction where the LogMemoryPageFactContinuous event was emitted.
  2. gpsVerifier: fact1 -> list of memory page hashes
  3. facts: sequence number -> fact (this fact is from LogStateTransitionFact, sequence number is from LogStateUpdate)

To sync, we follow these steps:

  1. Once we see a LogStateTransitionFact event, we look for a LogStateUpdate in the same Ethereum block. If found, we add it to the third mapping above. If the sequence number (StarkNet block number) is one greater than the latest sequence number of the last block we synced, we begin processing the state update.
  2. Use the fact from the LogStateTransitionFact event to get the list of corresponding memory page hashes from the gpsVerifier mapping.
  3. For each memory page hash, use the memoryPage mapping to find the hash of the transaction where the memory page data was sent.
  4. Query an Ethereum node for the actual transaction using the transaction hash.
  5. Parse the Ethereum transaction calldata to reconstruct the StarkNet state update.

Further exploration:

  1. StarkNet State - layout of the StarkNet state trie
  2. Fact registry design - the reasoning behind the StarkNet L1 contract architecture
  3. StarkEx contracts on GitHub - contain initial implementations of the MemoryPageFactRegistry and GpsStatementVerifier contracts for StarkEx
  4. StarkNet contract on Goerli (may be out of date by the time you're reading this)
  5. Cairo white paper - useful background knowledge to have while reading the above contracts