> For the complete documentation index, see [llms.txt](https://docs.facet.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.facet.org/reference/chain-state-derivation.md).

# 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](/introduction/architecture-overview.md).

## 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.

<figure><img src="/files/7XViqguzZeY6JlE2vDgZ" alt=""><figcaption><p>Facet architecture follows Ethereum's consensus/execution split</p></figcaption></figure>

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

* [facet-node](https://github.com/0xFacet/facet-node): Consensus client implementation
* [facet-geth](https://github.com/0xFacet/facet-geth): Execution client (op-geth fork)
* [Optimism Specs](https://specs.optimism.io/): Deposit transaction specification
