Facet Docs
  • 1. Introduction
    • Overview of Facet Protocol
    • What is Layer 1+?
    • The Based Sovereign Rollup
  • 2. Getting Started
    • Connecting a Wallet
    • Sending Transactions
    • Bridging In (and Out)
    • What about Gas?
    • Facet Apps
  • 3. Technical Details
    • Introduction
    • Facet RPC & Explorer
    • Genesis Contracts
    • Facet Transactions
      • From Calldata
      • From Event Logs
    • Facet Typescript SDK
    • Facet Sol (Foundry)
    • Chain State Derivation
    • Running a Facet Node
    • Bridging Assets
    • Building an Optimistic Bridge on Facet
    • Basic Transaction Flow
    • Facet's Gas Mechanism
      • FCT Issuance Calculation
      • FCT Gas Fee Calculation
    • Security Audits
  • 4. Community & Support
    • FAQs
    • Comparison with Other Rollups
    • Micro-Grants
    • Community Resources
    • Brand Kit
Powered by GitBook
On this page
  • L1 Data Collection
  • Building Deposit Transactions
  • Building Blocks
  • Applying the State Transition Function
  • Validating Chain Data
  1. 3. Technical Details

Chain State Derivation

PreviousFacet Sol (Foundry)NextRunning a Facet Node

Last updated 4 months ago

You put a properly-encoded Facet transaction in the calldata of an Ethereum transaction and send it to the Facet inbox address. What happens next? How does your transaction become part of the Facet chain?

This process is executed by two pieces of software working together: and . This architecture follows the Consensus/Execution split on the Ethereum L1, with facet-node acting as the consensus client and facet-geth as the execution layer.

facet-geth is a fork of Optimism's op-geth. facet-node is modeled after op-node, though it isn't a fork.

On a high level:

1

facet-node fetches Facet transactions from Ethereum L1 transactions.

2

facet-node creates and sends proposed Facet blocks to facet-geth.

3

facet-geth executes transactions and maintains Facet chain state.

Let's explore this process in more detail with some visualizations.

L1 Data Collection

facet-node connects to an L1 Ethereum RPC server and monitors each L1 block for Ethereum transactions that contain valid Facet transactions.

For each L1 block, facet-node calls eth_getBlockByNumber (to get transaction calldata) and eth_getBlockReceipts (to get logs and transaction status).

facet-node examines each successful transaction whose "to" address is address(0xface7) or event logs whose only topic is bytes32(uint256(0xface7)) and attempts to decode the payload into a Facet transaction object with the following fields:

  • chain_id

  • to

  • value

  • gas_limit

  • data

  • mine_boost

Building Deposit Transactions

If the payload decodes correctly, facet-node verifies the chain_id, and builds a deposit transaction:

Users communicate with facet-node using Facet transactions. facet-node communicates block payloads to facet-geth using a different transaction called a Deposit Transaction.

Deposit transactions (type 0x7E) were created by Optimism in op-geth where they are used to represent rollup transactions that do not go through the sequencer. Facet uses them with two modifications.

Deposit transactions copy the data of these fields directly from Facet transactions:

  • to

  • value

  • gas_limit

  • data

The extra_data field is dropped at this stage. Deposit Transactions also add these fields:

  • source_hash: a unique identifier for the transaction.

  • l1_tx_origin: the EOA that initiated the L1 transaction. This is important for FCT mint logic and is not present in the OP version.

  • from: the signer of the transaction in the case of a calldata-based Facet transaction or the emitting contract in the case of a log-originated Facet transaction. In the latter case this value is aliased according to Optimism's rules.

  • mint: the amount of FCT op-geth should mint the user before processing their transaction. More below on how this works.

Building Blocks

Deposit transactions and sent to op-geth as a Facet block using the engine API (engine_forkchoiceUpdated etc).

However, some processing is required. First, in accordance with the OP protocol, the first transaction in every Facet block is an L1 tx attributes transaction. Second, and also in accordance with OP, Facet block times are 12 seconds, which means Facet blocks cannot be 1-1 with Ethereum L1 blocks as they can skip slots. In such a case facet-node inserts "filler blocks" to preserve the 12 second timing.

Applying the State Transition Function

Once facet-geth receives a block payload from facet-node it can process the transaction. For the most part this happens exactly as it would on the L1 or any EVM rollup. This is what makes Facet EVM-compatible. However, there are a few exceptions:

  • It is not possible for facet-node to submit an invalid block. The usual "pre-check" errors that would make a block invalid instead just affect the individual transaction.

  • A block's gas limit is not validated against the total of the gas limits of its transactions. Instead, each transaction attempts to buy gas sequentially and if there is no more gas in a block for a given transaction to buy that transaction fails (and the next transaction attempts to buy gas).

  • There is no priority fee. All transactions pay the base fee.

  • Transactions initiated by L1 contracts cannot increase the contract's FCT balance. Any minted FCT beyond what is required to pay for the transaction is transferred to the EOA who initiated the transaction on the L1.

Validating Chain Data

The derivation process is deterministic and its only input is Ethereum data available from any Ethereum RPC. Anyone can run a Facet Node to compute or validate the state of the Facet chain at any time.

facet-node
facet-geth