Chain State Derivation

How does a transaction sent to Ethereum become part of the Facet chain? This document explains both the high-level process and detailed technical implementation. For a one-page diagram, see the Architecture Overview.

Overview

When you send a Facet transaction to Ethereum's 0xface7 address, Facet nodes automatically detect it and include it in the Facet block for the corresponding 12-second slot. Facet produces blocks every 12 seconds regardless of whether Ethereum produced an L1 block in that slot. If L1 produced a block, the slot’s Facet block includes all 0xface7 inbox transactions from that L1 block in exact order. If L1 skipped the slot (no L1 block), Facet still produces a filler block with no inbox transactions. This is a deterministic process—no sequencer or admin can interfere.

Facet architecture follows Ethereum's consensus/execution split

The system uses two components: facet-node monitors L1 and builds blocks, while facet-geth executes transactions and maintains state. This architecture ensures that anyone running these components will derive exactly the same chain state from the same Ethereum data.

Transaction Processing Pipeline

1. L1 Block Monitoring

facet-node monitors L1 blocks using these RPC calls:

  • eth_getBlockByNumber: Retrieves transaction calldata

  • eth_getBlockReceipts: Retrieves logs and transaction status

2. Facet Transaction Detection

Valid Facet transactions are identified by:

  • Calldata transactions: to address equals address(0xface7) with receipt status = 1

  • Event log transactions: Exactly one topic equal to bytes32(uint256(0xface7)) with payload in data field

One Transaction Per Ethereum Transaction Rule:

  • Each Ethereum transaction contributes at most ONE Facet transaction to the L2 block

  • If multiple valid Facet payloads exist (e.g., calldata + event, or multiple events), only the first is processed

  • Processing order: Calldata is checked first, then events in log index order

  • Additional candidates are silently ignored (not an error condition)

3. Transaction Decoding

Facet transactions must decode to this structure:

{
  chain_id: uint256
  to: address
  value: uint256
  gas_limit: uint256
  data: bytes
  mine_boost: uint256
}

Deposit Transaction Construction

Type 0x7D Transactions

Facet executes Facet payloads as deposit transactions of type 0x7D (like Optimism’s 0x7E deposit tx, with Facet-specific fields/semantics). The effective L2 transaction has the following data model:

// Pseudocode: DepositTx
SourceHash:            bytes32   // The tx hash of the L1 transaction that originated the Facet payload
From:                  address   // For calldata-originated payloads, this is the L1 EOA that signed the envelope; for log-originated payloads, this is the emitting contract address after aliasing (see below)
To:                    address?  // Destination address; `nil` for contract creation
Mint:                  uint256?  // FCT minted on L2 and locked on L1; nil if none
Value:                 uint256   // FCT transferred from L2 balance (applied after Mint)
Gas:                   uint64    // execution gas limit
IsSystemTransaction:   bool      // Legacy field, always `false`
Data:                  bytes     // calldata

Transaction hash computation:

  • The typed-transaction hash uses type 0x7D and standard serialization of the above fields.

  • Important: The Mint field is excluded from the hash by treating it as zero/nil for hashing purposes. In other words, changes to Mint do not affect the transaction hash.

Address Aliasing

For log-originated transactions, the from address is aliased:

aliased_address = original_address + 0x1111000000000000000000000000000000001111

This prevents contracts from impersonating EOAs.

Block Construction

L1 Attributes Transaction

Every Facet block begins with an L1 attributes transaction containing:

  • L1 block number

  • L1 block timestamp

  • L1 block hash

  • Sequence number

Block Timing Rules

  • Facet block times are fixed at 12-second intervals

  • When an L1 block exists for a slot, its inbox transactions appear in that slot’s Facet block

  • When a slot has no L1 block, Facet produces a filler block for that slot (no inbox transactions)

Engine API Communication

Blocks are sent to facet-geth using:

  • engine_forkchoiceUpdatedV2

  • engine_newPayloadV2

  • engine_getPayloadV2

Gas Mechanics

Sequential Gas Buying

Unlike standard EVM chains:

  1. Each transaction attempts to buy gas sequentially

  2. If insufficient gas remains in block, transaction fails

  3. Next transaction attempts to buy gas

  4. Block gas limit is not pre-validated

FCT Minting Rules

For contract-initiated transactions:

  • Contract cannot increase its own FCT balance

  • Excess minted FCT transfers to L1 transaction origin

  • Prevents contracts from self-funding

Base Fee Only

  • No priority fee mechanism

  • All transactions pay current base fee

  • Simplifies gas pricing model

State Transition Differences

Invalid Block Handling

facet-geth modifications ensure:

  • Invalid blocks cannot be submitted by facet-node

  • Pre-check errors affect individual transactions, not entire block

  • Chain continues processing subsequent transactions

Gas Limit Validation

Standard EVM: sum(tx.gas_limit) <= block.gas_limit

Facet: Each transaction validated independently during execution

Data Structures

Source Hash Computation

source_hash = l1_tx_hash

L1 Info Transaction Format

{
  type: 0x7D,
  to: L1_INFO_PRECOMPILE,
  data: abi.encode(
    block_number,
    block_timestamp,
    base_fee,
    block_hash,
    sequence_number
    ...fct_fields
  )
}

Validation Process

Deterministic Derivation

Chain state can be validated by:

  1. Fetching L1 data from any Ethereum RPC

  2. Running facet-node derivation logic

  3. Comparing resulting state roots

Required L1 Data

  • Block headers (number, timestamp, hash)

  • Transaction receipts (status, logs)

  • Transaction calldata

Consensus Rules

All nodes following these rules will:

  • Derive identical state from same L1 data

  • Produce identical block sequences

  • Calculate identical state roots

Implementation References

Last updated