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.

Overview

When you send a Facet transaction to Ethereum's 0xface7 address, Facet nodes automatically detect it and include it in the next Facet block. This happens through a deterministic process where nodes monitor Ethereum, extract valid transactions, and apply them in order - 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)

  • Event log transactions: Single topic equals bytes32(uint256(0xface7))

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 0x7E Transactions

Facet uses Optimism's Deposit Transaction type with modifications:

Standard fields (copied from Facet transaction):

  • to: Destination address

  • value: ETH value (always 0 in practice)

  • gas_limit: Gas limit for execution

  • data: Transaction calldata

Additional fields:

  • source_hash: Unique identifier computed from L1 block and transaction index

  • l1_tx_origin: EOA that initiated the L1 transaction

  • from: Transaction signer (calldata) or emitting contract (logs)

  • mint: FCT amount to mint before execution

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 blocks have 12-second slots

  • Empty "filler blocks" maintain timing when L1 blocks are sparse

  • Block timestamps must align with 12-second intervals

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 = keccak256(
  l1_block_hash || 
  uint64(log_index || sequence_number)
)

L1 Info Transaction Format

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

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