# BaseHub — full content > Base docs for agents — full Markdown corpus, concatenated. 178 pages. See /llms.txt for the index. Source: https://basehub.org Index: https://basehub.org/llms.txt --- # debug_traceBlockByHash Source: https://basehub.org/api-reference/debug/debug_traceblockbyhash/ Description: Replays every transaction in a block identified by hash and returns an EVM execution trace for each one. Replays all transactions in a block identified by its hash and returns an execution trace for each. Debug methods replay every transaction in the block and are computationally expensive. Availability varies by node provider. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `blockHash` | string | Yes | The 32-byte block hash. | | `traceOptions` | object | No | Optional trace configuration. Accepts the same fields as [`debug_traceTransaction`](/api-reference/debug/debug_traceTransaction/). | ## Returns `result` is an array of trace result objects, one per transaction in the block. | Field | Type | Description | | --- | --- | --- | | `txHash` | string | The transaction hash. | | `result` | object | The execution trace for this transaction. Same format as [`debug_traceTransaction`](/api-reference/debug/debug_traceTransaction/). | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "debug_traceBlockByHash", "params": [ "0x3a4e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3", { "tracer": "callTracer" } ], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": [ { "txHash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "result": { "type": "CALL", "from": "0xd3cda913deb6f4967b2ef66ae97de114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "value": "0x2c68af0bb14000", "gas": "0x5208", "gasUsed": "0x5208", "input": "0x", "output": "0x", "calls": [] } } ] } ``` --- # debug_traceBlockByNumber Source: https://basehub.org/api-reference/debug/debug_traceblockbynumber/ Description: Returns EVM execution traces for every transaction in a block identified by its block number or block tag. Returns the EVM execution traces for all transactions in a block identified by its number. Debug methods replay every transaction in the block and are computationally expensive. Availability varies by node provider. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `block` | string | Yes | A block number in hex, or one of `"latest"`, `"earliest"`, `"safe"`, `"finalized"`. | | `tracerConfig` | object | No | Optional tracer configuration. See [`debug_traceTransaction`](/api-reference/debug/debug_traceTransaction/) for available options. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | array | Array of trace objects, one per transaction in the block. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "debug_traceBlockByNumber", "params": ["latest", {"tracer": "callTracer"}], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": [ { "result": { "type": "CALL", "gasUsed": "0xab3f" } } ] } ``` --- # debug_traceTransaction Source: https://basehub.org/api-reference/debug/debug_tracetransaction/ Description: Replays a transaction and returns its full EVM execution trace, with opcode-level gas, stack, memory, and storage detail. Replays a transaction and returns its complete EVM execution trace, including every opcode executed, gas consumed at each step, stack contents, and storage changes. Debug methods replay transactions and are computationally expensive. Availability and rate limits vary by node provider — avoid calling them in hot paths. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `transactionHash` | string | Yes | The 32-byte transaction hash to trace. | | `traceOptions` | object | No | Optional tracing configuration. | The `traceOptions` object accepts: | Field | Type | Description | | --- | --- | --- | | `tracer` | string | Built-in tracer name. `"callTracer"` returns a call tree. `"prestateTracer"` returns the pre-execution account state. Omit to use the default struct log tracer. | | `tracerConfig` | object | Options for the selected tracer. For `"callTracer"`, `\{ "onlyTopCall": true \}` skips internal calls. | | `disableStorage` | boolean | If `true`, omits storage capture from struct logs. Reduces response size. Defaults to `false`. | | `disableMemory` | boolean | If `true`, omits memory capture from struct logs. Reduces response size. Defaults to `false`. | | `disableStack` | boolean | If `true`, omits stack capture from struct logs. Defaults to `false`. | | `timeout` | string | Execution timeout as a Go duration string (for example, `"10s"`, `"30s"`). Defaults to `"5s"`. | ## Returns `result` is the execution trace. The shape depends on the `tracer` option. ### Default struct log trace | Field | Type | Description | | --- | --- | --- | | `gas` | number | Total gas provided for the transaction. | | `failed` | boolean | Whether the transaction failed (reverted). | | `returnValue` | string | Hex-encoded return value from the execution. | | `structLogs` | array | Array of struct log entries, one per EVM opcode executed. | Each entry in `structLogs` contains: | Field | Type | Description | | --- | --- | --- | | `pc` | number | Program counter position. | | `op` | string | EVM opcode name (for example, `"PUSH1"`, `"SLOAD"`). | | `gas` | number | Remaining gas at this step. | | `gasCost` | number | Gas cost of this opcode. | | `depth` | number | Call depth (1 = top-level call). | | `stack` | array | EVM stack values at this step. | | `memory` | array | EVM memory contents as 32-byte chunks. | | `storage` | object | Contract storage changes at this step (slot to value). | ### callTracer result | Field | Type | Description | | --- | --- | --- | | `type` | string | Call type: `"CALL"`, `"STATICCALL"`, `"DELEGATECALL"`, or `"CREATE"`. | | `from` | string | Sender address. | | `to` | string | Recipient address. | | `value` | string | ETH value sent with the call. | | `gas` | string | Gas provided for the call. | | `gasUsed` | string | Gas actually consumed. | | `input` | string | Call data sent. | | `output` | string | Return data from the call. | | `error` | string | Error message if the call reverted. Optional. | | `calls` | array | Array of nested call objects for internal calls. | ## Example ### Request (default struct log) ```json { "jsonrpc": "2.0", "method": "debug_traceTransaction", "params": [ "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", {} ], "id": 1 } ``` ### Request (callTracer) ```json { "jsonrpc": "2.0", "method": "debug_traceTransaction", "params": [ "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", { "tracer": "callTracer" } ], "id": 1 } ``` ### Response (default) ```json { "jsonrpc": "2.0", "id": 1, "result": { "gas": 21000, "failed": false, "returnValue": "", "structLogs": [ { "pc": 0, "op": "PUSH1", "gas": 21000, "gasCost": 3, "depth": 1, "stack": [], "memory": [], "storage": {} } ] } } ``` ### Response (callTracer) ```json { "jsonrpc": "2.0", "id": 1, "result": { "type": "CALL", "from": "0xd3cda913deb6f4967b2ef66ae97de114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "value": "0x2c68af0bb14000", "gas": "0x5208", "gasUsed": "0x5208", "input": "0x", "output": "0x", "calls": [] } } ``` --- # eth_blockNumber Source: https://basehub.org/api-reference/eth/eth_blocknumber/ Description: Returns the latest block number on Base — the most recent block the node has imported, encoded as a hexadecimal string. Returns the number of the most recently mined block. ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The current block number as a hexadecimal string. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x158a0e9" } ``` --- # eth_call Source: https://basehub.org/api-reference/eth/eth_call/ Description: Executes a read-only message call against Base state without broadcasting a transaction; pair with pending on Flashblocks for pre-confirmed reads. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Runs a message call immediately against node state without broadcasting a transaction or consuming on-chain gas. Use it to read contract state or simulate calls. ## Parameters ### `transaction` (object, required) The transaction call object. | Field | Type | Description | | --- | --- | --- | | `from` | string | Address the call is sent from. Optional; defaults to the zero address. | | `to` | string | Address the call is directed to. Required. | | `gas` | string | Gas provided for the call as a hexadecimal integer. Defaults to a high limit if omitted. | | `gasPrice` | string | Gas price in wei as a hexadecimal integer. For legacy transactions. Optional. | | `maxFeePerGas` | string | EIP-1559 maximum total fee per gas. Optional. | | `maxPriorityFeePerGas` | string | EIP-1559 maximum priority fee per gas. Optional. | | `value` | string | Value transferred in wei as a hexadecimal integer. Optional. | | `data` | string | ABI-encoded call data: the 4-byte function selector followed by encoded arguments. Optional. | ### `block` (string, required) Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Pass `"pending"` on a Flashblocks endpoint to call against pre-confirmed state. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The return value of the call as a hex-encoded byte array. | ## Error codes | Code | Message | Description | | --- | --- | --- | | `-32000` | execution reverted | The call reverted. The `data` field in the error object contains the ABI-encoded revert reason when available. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_call", "params": [ { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006" }, "latest" ], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_call", "params": [ { "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "data": "0x70a082310000000000000000000000004200000000000000000000000000000000000006" }, "pending" ], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000005f5e100" } ``` --- # eth_chainId Source: https://basehub.org/api-reference/eth/eth_chainid/ Description: Returns the EIP-695 chain ID for the connected Base network — 0x2105 for Mainnet and 0x14a34 for Sepolia. Returns the chain ID of the current network, per [EIP-695](https://eips.ethereum.org/EIPS/eip-695). ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The chain ID as a hexadecimal string. `"0x2105"` (8453) for Base Mainnet and `"0x14a34"` (84532) for Base Sepolia. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_chainId", "params": [], "id": 1 } ``` ### Response Base Mainnet: ```json { "jsonrpc": "2.0", "id": 1, "result": "0x2105" } ``` Base Sepolia: ```json { "jsonrpc": "2.0", "id": 1, "result": "0x14a34" } ``` --- # eth_estimateGas Source: https://basehub.org/api-reference/eth/eth_estimategas/ Description: Estimates the gas required to execute a transaction on Base; use pending on Flashblocks to estimate against pre-confirmed state. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns an estimate of how much gas a transaction would require. The reported value may exceed what the transaction actually consumes when executed. ## Parameters ### `transaction` (object, required) The transaction object to estimate gas for. | Field | Type | Description | | --- | --- | --- | | `from` | string | Address the transaction is sent from. Optional. | | `to` | string | Address the transaction is sent to. Optional for contract deployments. | | `gas` | string | Gas limit. Optional; a high default is used if omitted. | | `gasPrice` | string | Gas price in wei for legacy transactions. Optional. | | `maxFeePerGas` | string | EIP-1559 maximum total fee per gas. Optional. | | `maxPriorityFeePerGas` | string | EIP-1559 maximum priority fee per gas. Optional. | | `value` | string | Value to transfer in wei. Optional. | | `data` | string | ABI-encoded call data. Optional. | ### `block` (string, optional) Block to estimate against. Defaults to `"latest"`. Pass `"pending"` on a Flashblocks endpoint to estimate against pre-confirmed state. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The estimated gas amount as a hexadecimal integer. | ## Error codes | Code | Message | Description | | --- | --- | --- | | `-32000` | execution reverted | The transaction would revert. The error `data` field may contain a revert reason. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_estimateGas", "params": [{ "from": "0xd3CdA913deB6f4967b2Ef66ae97DE114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "value": "0x2c68af0bb14000" }], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_estimateGas", "params": [{ "from": "0xd3CdA913deB6f4967b2Ef66ae97DE114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "value": "0x2c68af0bb14000" }, "pending"], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x5208" } ``` --- # eth_feeHistory Source: https://basehub.org/api-reference/eth/eth_feehistory/ Description: Returns historical base fees, gas-used ratios, and priority-fee percentile rewards across a range of Base blocks for fee estimation. Returns historical gas data for a contiguous range of blocks, including per-block base fees and the distribution of priority fees. Useful for building EIP-1559 fee-estimation strategies. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `blockCount` | string \| number | Number of blocks to return. Decimal or hexadecimal integer. The maximum is typically 1024. Required. | | 2 | `newestBlock` | string | The highest block to include, as a block number in hex or a block tag (`"latest"`, `"pending"`, etc.). Required. | | 3 | `rewardPercentiles` | array | Array of percentile values (0–100) to sample from each block's priority fees. For example, `[25, 50, 75]` returns the 25th, 50th, and 75th percentile priority fees. Required. | ## Returns `result` (object): | Field | Type | Description | | --- | --- | --- | | `oldestBlock` | string | The oldest block number in the result set (hex). | | `baseFeePerGas` | array | Base fees per gas for each block, plus one extra entry for the next pending block. | | `gasUsedRatio` | array | Gas-used to gas-limit ratios for each block (0.0 to 1.0). | | `reward` | array | Two-dimensional array of priority-fee percentiles per block, matching the requested percentile values. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_feeHistory", "params": ["0xa", "latest", [25, 50, 75]], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "oldestBlock": "0x158a0e0", "baseFeePerGas": ["0xf5", "0xf7", "0xfa", "0xfc", "0xf8", "0xf5", "0xf2", "0xf0", "0xef", "0xf1", "0xf3"], "gasUsedRatio": [0.45, 0.62, 0.38, 0.71, 0.55, 0.49, 0.43, 0.37, 0.52, 0.64], "reward": [ ["0x1", "0x1", "0x2"], ["0x1", "0x1", "0x1"] ] } } ``` --- # eth_gasPrice Source: https://basehub.org/api-reference/eth/eth_gasprice/ Description: Returns the current gas price on Base in wei as a hexadecimal string; for EIP-1559 fee estimation use eth_maxPriorityFeePerGas and eth_feeHistory. Returns the current gas price in wei. For EIP-1559 transactions, prefer [`eth_maxPriorityFeePerGas`](/api-reference/eth/eth_maxpriorityfeepergas/) and [`eth_feeHistory`](/api-reference/eth/eth_feehistory/) instead. ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The current gas price in wei as a hexadecimal string. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_gasPrice", "params": [], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0xfa" } ``` --- # eth_getBalance Source: https://basehub.org/api-reference/eth/eth_getbalance/ Description: Returns the ETH balance of an account at a given block on Base; use pending on Flashblocks for ~200ms pre-confirmed balances. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns the ETH balance of an address at a given block. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `address` | string | The 20-byte address to query. Required. | | 2 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Pass `"pending"` on a Flashblocks endpoint for the pre-confirmed balance. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The balance in wei as a hexadecimal string. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0x742d35Cc6634C0532925a3b8D4C9dD0b4f3BaEa", "latest"], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0x742d35Cc6634C0532925a3b8D4C9dD0b4f3BaEa", "pending"], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x1a055690d9db80000" } ``` --- # eth_getBlockByHash Source: https://basehub.org/api-reference/eth/eth_getblockbyhash/ Description: Returns block information for a given 32-byte block hash on Base, with full transaction objects or just transaction hashes. Returns information about a block identified by its hash. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `blockHash` | string | The 32-byte block hash. Required. | | 2 | `fullTransactions` | boolean | When `true`, returns full transaction objects; when `false`, returns only transaction hashes. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | object \| null | A block object, or `null` if no block was found. See [`eth_getBlockByNumber`](/api-reference/eth/eth_getblockbynumber/) for the full field list. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getBlockByHash", "params": ["0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8", false], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "number": "0x158a0e9", "hash": "0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8", "parentHash": "0x9edc29b8b0a1e31d28616e40c16132ad0d58faa8bb952595b557526bdb9a960a", "timestamp": "0x67bf8332", "gasLimit": "0x3938700", "gasUsed": "0xab3f", "transactions": ["0x7ef8f8a0..."] } } ``` --- # eth_getBlockByNumber Source: https://basehub.org/api-reference/eth/eth_getblockbynumber/ Description: Returns block data by number on Base; on Flashblocks endpoints the pending tag returns the live pre-confirmed block updated every ~200ms. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns information about a block identified by its number. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Pass `"pending"` on a Flashblocks endpoint to get the in-progress block. Required. | | 2 | `fullTransactions` | boolean | When `true`, returns full transaction objects; when `false`, returns only transaction hashes. Required. | ## Returns `result` (object or `null` if no block was found): | Field | Type | Description | | --- | --- | --- | | `number` | string | Block number in hex. `null` when pending. | | `hash` | string | Block hash. `null` when pending. | | `parentHash` | string | Hash of the parent block. | | `nonce` | string | PoW nonce. Always `"0x0000000000000000"` on Base (PoS). | | `sha3Uncles` | string | Hash of the uncles list. Always empty on Base. | | `logsBloom` | string | Bloom filter for the block's logs. | | `transactionsRoot` | string | Root of the transaction trie. | | `stateRoot` | string | Root of the final state trie. | | `receiptsRoot` | string | Root of the receipts trie. | | `miner` | string | Address of the fee recipient (coinbase). | | `difficulty` | string | Always `"0x0"` on Base (PoS). | | `totalDifficulty` | string | Always `"0x0"` on Base (PoS). | | `extraData` | string | Arbitrary data field set by the sequencer. | | `size` | string | Block size in bytes (hex). | | `gasLimit` | string | Maximum gas allowed in this block (hex). | | `gasUsed` | string | Total gas used in this block (hex). | | `timestamp` | string | Unix timestamp (hex). | | `transactions` | array | Array of transaction hashes or full transaction objects. | | `uncles` | array | Always `[]` on Base. | | `withdrawals` | array | Always `[]` on Base. | | `baseFeePerGas` | string | EIP-1559 base fee per gas (hex). | | `blobGasUsed` | string | Total blob gas used (EIP-4844, hex). | | `excessBlobGas` | string | Excess blob gas for blob fee calculation (EIP-4844, hex). | | `parentBeaconBlockRoot` | string | Parent beacon block root (EIP-4788). | | `requestsHash` | string | Hash of requests (EIP-7685). | ## Flashblock-specific response fields When you query `"pending"` on a Flashblocks endpoint, the response is a live snapshot of the block being built. A few fields behave differently: | Field | Standard `latest` | Flashblocks `pending` | | --- | --- | --- | | `number` | Sealed block number | Current block number (being built) | | `hash` | Final block hash | Hash of the partial block at this Flashblock index | | `gasUsed` | Final gas used | Cumulative gas used up to this Flashblock | | `transactions` | All sealed transactions | Transactions pre-confirmed so far | | `blobGasUsed` | Final blob gas used | Propagated from cumulative Flashblock state | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getBlockByNumber", "params": ["latest", false], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getBlockByNumber", "params": ["pending", false], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "number": "0x158a0e9", "hash": "0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8", "parentHash": "0x9edc29b8b0a1e31d28616e40c16132ad0d58faa8bb952595b557526bdb9a960a", "timestamp": "0x67bf8332", "gasLimit": "0x3938700", "gasUsed": "0xab3f", "baseFeePerGas": "0xfa", "transactions": ["0x7ef8f8a0..."], "withdrawals": [], "miner": "0x4200000000000000000000000000000000000011" } } ``` --- # eth_getBlockReceipts Source: https://basehub.org/api-reference/eth/eth_getblockreceipts/ Description: Returns every transaction receipt for a block on Base in one call; pair with pending on Flashblocks for pre-confirmed receipts. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns every transaction receipt for a given block in a single call. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | array | Array of receipt objects, one per transaction in the block. See [`eth_getTransactionReceipt`](/api-reference/eth/eth_gettransactionreceipt/) for the receipt object shape. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_getBlockReceipts","params":["latest"],"id":1}' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_getBlockReceipts","params":["pending"],"id":1}' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": [ { "transactionHash": "0xabc123...", "blockNumber": "0x158a0e9", "status": "0x1", "gasUsed": "0x5208", "type": "0x2" } ] } ``` --- # eth_getBlockTransactionCountByHash Source: https://basehub.org/api-reference/eth/eth_getblocktransactioncountbyhash/ Description: Returns the number of transactions included in the Base block matching the supplied 32-byte block hash. Returns the number of transactions in a block matching the given block hash. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `blockHash` | string | The 32-byte block hash. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The number of transactions in the block as a hexadecimal integer. `null` if no block was found. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getBlockTransactionCountByHash", "params": ["0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x1f" } ``` --- # eth_getBlockTransactionCountByNumber Source: https://basehub.org/api-reference/eth/eth_getblocktransactioncountbynumber/ Description: Returns the transaction count for a Base block by number; on Flashblocks endpoints pending counts pre-confirmed transactions in the live Flashblock. import { Aside } from '@astrojs/starlight/components'; Returns the number of transactions in a block matching the given block number. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The number of transactions in the block as a hexadecimal integer. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getBlockTransactionCountByNumber", "params": ["latest"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x1f" } ``` --- # eth_getCode Source: https://basehub.org/api-reference/eth/eth_getcode/ Description: Returns the deployed bytecode at an address on Base; use pending on Flashblocks to detect newly deployed contracts before block finalization. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns the compiled bytecode at a given address. Returns `"0x"` for externally owned accounts (EOAs). ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `address` | string | The 20-byte address to query. Required. | | 2 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The bytecode at the address as a hex string. `"0x"` if there is no code. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getCode", "params": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "latest"], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getCode", "params": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "pending"], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x608060405234801561001057600080fd5b50..." } ``` --- # eth_getLogs Source: https://basehub.org/api-reference/eth/eth_getlogs/ Description: Returns event logs on Base matching a filter object; pair with pending on Flashblocks to query logs from pre-confirmed transactions. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns an array of all logs matching a filter object. The primary tool for indexing on-chain events. ## Parameters ### `filter` (object, required) Filter options. At least one criterion should be provided. | Field | Type | Description | | --- | --- | --- | | `fromBlock` | string | Start of the block range. Block number in hex or a block tag. Pass `"pending"` on a Flashblocks endpoint to include pre-confirmed logs. Defaults to `"latest"`. | | `toBlock` | string | End of the block range. Block number in hex or a block tag. Defaults to `"latest"`. | | `address` | string \| array | A contract address or array of addresses to filter by. Optional. | | `topics` | array | Array of 32-byte topic filters. Each position can be `null` (match any), a single topic hex string, or an array of hex strings (match any in the array). Position 0 is typically the `keccak256` hash of the event signature. Optional. | | `blockHash` | string | Restricts logs to the block with this hash. When supplied, `fromBlock` and `toBlock` are ignored. Optional. | ## Returns `result` (array of log objects): | Field | Type | Description | | --- | --- | --- | | `address` | string | 20-byte address of the contract that emitted the log. | | `topics` | array | Array of 0–4 indexed 32-byte topics. Topic 0 is typically the event signature hash. | | `data` | string | ABI-encoded non-indexed event parameters. | | `blockNumber` | string | Block number in which this log was emitted (hex). | | `transactionHash` | string | 32-byte hash of the transaction that emitted this log. | | `transactionIndex` | string | Index of the transaction in the block (hex). | | `blockHash` | string | 32-byte hash of the block. | | `logIndex` | string | The log's index position within the block (hex). | | `removed` | boolean | `true` if the log was removed due to a chain reorganization. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getLogs", "params": [{ "fromBlock": "0x12ced00", "toBlock": "0x12ced28", "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] }], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getLogs", "params": [{ "fromBlock": "pending", "toBlock": "pending", "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] }], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": [ { "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000d3cda913deb6f4967b2ef66ae97de114a83bcc01", "0x0000000000000000000000004200000000000000000000000000000000000006" ], "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", "blockNumber": "0x12ced28", "transactionHash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "transactionIndex": "0x0", "blockHash": "0x3a4e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3", "logIndex": "0x0", "removed": false } ] } ``` --- # eth_getStorageAt Source: https://basehub.org/api-reference/eth/eth_getstorageat/ Description: Returns the 32-byte value stored at a contract storage slot on Base; use pending on Flashblocks for pre-confirmed storage reads. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Returns the value held at a storage position for a given contract address. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `address` | string | The 20-byte address that owns the storage. Required. | | 2 | `position` | string | The storage slot position as a hexadecimal integer. Required. | | 3 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The value at the storage position as a 32-byte hex string. | ## Example ### Request ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getStorageAt", "params": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "0x0", "latest"], "id": 1 }' ``` ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getStorageAt", "params": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "0x0", "pending"], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000000000001" } ``` --- # eth_getTransactionByBlockHashAndIndex Source: https://basehub.org/api-reference/eth/eth_gettransactionbyblockhashandindex/ Description: Returns transaction data on Base by combining a 32-byte block hash with the transaction's zero-based index inside that block. Returns information about a transaction identified by a block hash and the transaction's index position within that block. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `blockHash` | string | The 32-byte block hash. Required. | | 2 | `index` | string | The transaction index position as a hexadecimal integer. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | object \| null | A transaction object, or `null` if not found. See [`eth_getTransactionByHash`](/api-reference/eth/eth_gettransactionbyhash/) for the full field list. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getTransactionByBlockHashAndIndex", "params": ["0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8", "0x0"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "hash": "0x7ef8f8a0...", "blockNumber": "0x158a0e9", "transactionIndex": "0x0", "type": "0x7e" } } ``` --- # eth_getTransactionByBlockNumberAndIndex Source: https://basehub.org/api-reference/eth/eth_gettransactionbyblocknumberandindex/ Description: Returns transaction data on Base by pairing a block number or tag with the transaction's zero-based index inside that block. Returns information about a transaction identified by a block number and the transaction's index position within that block. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `block` | string | Block number in hex, or `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Required. | | 2 | `index` | string | The transaction index position as a hexadecimal integer. Required. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | object \| null | A transaction object, or `null` if not found. See [`eth_getTransactionByHash`](/api-reference/eth/eth_gettransactionbyhash/) for the full field list. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getTransactionByBlockNumberAndIndex", "params": ["latest", "0x0"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "hash": "0x7ef8f8a0...", "blockNumber": "0x158a0e9", "transactionIndex": "0x0", "type": "0x7e" } } ``` --- # eth_getTransactionByHash Source: https://basehub.org/api-reference/eth/eth_gettransactionbyhash/ Description: Returns full transaction data for a 32-byte transaction hash on Base, or null when the node has not seen the transaction. Returns information about a transaction given its hash. Returns `null` for unknown transactions. ## Parameters | Position | Name | Type | Description | | --- | --- | --- | --- | | 1 | `transactionHash` | string | The 32-byte transaction hash. Required. | ## Returns `result` (object, or `null` if the transaction was not found): | Field | Type | Description | | --- | --- | --- | | `hash` | string | 32-byte transaction hash. | | `nonce` | string | Number of transactions sent by the sender prior to this one (hex). | | `blockHash` | string | 32-byte hash of the block containing this transaction. `null` if pending. | | `blockNumber` | string | Block number (hex). `null` if pending. | | `transactionIndex` | string | Index position in the block (hex). `null` if pending. | | `from` | string | 20-byte sender address. | | `to` | string | 20-byte recipient address. `null` for contract deployments. | | `value` | string | ETH value transferred in wei (hex). | | `gas` | string | Gas provided by the sender (hex). | | `gasPrice` | string | Gas price in wei. For EIP-1559 transactions, this is the effective gas price paid (hex). | | `maxFeePerGas` | string | EIP-1559 maximum total fee per gas (hex). Present for type `0x2` transactions only. | | `maxPriorityFeePerGas` | string | EIP-1559 maximum priority fee per gas (hex). Present for type `0x2` transactions only. | | `input` | string | ABI-encoded call data. `"0x"` for plain ETH transfers. | | `type` | string | Transaction type: `"0x0"` Legacy, `"0x1"` Access List, `"0x2"` EIP-1559, `"0x7e"` Deposit (L1→L2). | | `chainId` | string | Chain ID the transaction is valid for. `"0x2105"` for Base Mainnet, `"0x14a34"` for Base Sepolia. | | `accessList` | array | List of addresses and storage keys pre-declared by the transaction (EIP-2930). Present for type `0x1` and `0x2` transactions. | | `v` | string | ECDSA recovery ID (hex). | | `r` | string | 32-byte ECDSA signature component r (hex). | | `s` | string | 32-byte ECDSA signature component s (hex). | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getTransactionByHash", "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "hash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "nonce": "0x1b", "blockHash": "0x3a4e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3", "blockNumber": "0x12ced28", "transactionIndex": "0x0", "from": "0xd3CdA913deB6f4967b2Ef66ae97DE114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "value": "0x2c68af0bb14000", "gas": "0x5208", "gasPrice": "0x3b9aca00", "maxFeePerGas": "0x77359400", "maxPriorityFeePerGas": "0x3b9aca00", "input": "0x", "type": "0x2", "chainId": "0x2105", "accessList": [], "v": "0x1", "r": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b", "s": "0x2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c" } } ``` When the node has not seen the transaction: ```json { "jsonrpc": "2.0", "id": 1, "result": null } ``` --- # eth_getTransactionCount Source: https://basehub.org/api-reference/eth/eth_gettransactioncount/ Description: Returns the transaction count (nonce) for an address. Use the pending tag on a Flashblocks endpoint to include pre-confirmed transactions. Returns the number of transactions sent from an address. The value is the account nonce — pass it as `nonce` when constructing the next transaction. On a Flashblocks endpoint (`https://mainnet-preconf.base.org`), querying with `"pending"` returns the nonce inclusive of every pre-confirmed transaction and refreshes every ~200ms. This eliminates nonce gaps when an agent submits transactions at high frequency. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `address` | string | Yes | The 20-byte address to query. | | `block` | string | Yes | A block number in hex, or one of `"latest"`, `"pending"`, `"safe"`, `"finalized"`, `"earliest"`. Use `"pending"` against a Flashblocks endpoint to include all pre-confirmed transactions in the count. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The transaction count (nonce) as a hexadecimal string. | ## Example ### Request (standard, latest confirmed) ```bash curl https://mainnet.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getTransactionCount", "params": ["0x742d35Cc6634C0532925a3b8D4C9dD0b4f3BaEa", "latest"], "id": 1 }' ``` ### Request (Flashblocks pending nonce, ~200ms) ```bash curl https://mainnet-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_getTransactionCount", "params": ["0x742d35Cc6634C0532925a3b8D4C9dD0b4f3BaEa", "pending"], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x4d2" } ``` --- # eth_getTransactionReceipt Source: https://basehub.org/api-reference/eth/eth_gettransactionreceipt/ Description: Returns the receipt for a mined transaction by hash, or null when the transaction is still pending or has not been included in a block. Returns the receipt for a transaction identified by its hash. Returns `null` while the transaction is still pending or has not yet been mined. Receipts are only emitted once a transaction is included in a block. To track a transaction beforehand, call [`base_transactionStatus`](/api-reference/flashblocks/base_transactionStatus/) to confirm it has reached the mempool, or subscribe to [`newFlashblockTransactions`](/api-reference/flashblocks/newFlashblockTransactions/) to detect its pre-confirmation inside a Flashblock. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `transactionHash` | string | Yes | The 32-byte transaction hash. | ## Returns `result` is the receipt object, or `null` if the transaction has not been mined. | Field | Type | Description | | --- | --- | --- | | `transactionHash` | string | 32-byte transaction hash. | | `transactionIndex` | string | Position of the transaction in the block (hex). | | `blockHash` | string | 32-byte hash of the block containing this transaction. | | `blockNumber` | string | Block number (hex). | | `from` | string | 20-byte sender address. | | `to` | string | 20-byte recipient address. `null` for contract deployments. | | `cumulativeGasUsed` | string | Total gas used in the block up to and including this transaction (hex). | | `effectiveGasPrice` | string | Actual gas price paid per unit of gas for this transaction (hex). | | `gasUsed` | string | Gas used by this specific transaction (hex). | | `contractAddress` | string \| null | Address of the deployed contract, or `null` if the transaction was not a deployment. | | `logs` | array | Array of log objects emitted by this transaction. | | `logsBloom` | string | 256-byte bloom filter for the logs in this receipt. | | `type` | string | Transaction type: `"0x0"` Legacy, `"0x1"` Access List, `"0x2"` EIP-1559, `"0x7e"` Deposit (L1→L2). | | `status` | string | `"0x1"` for success, `"0x0"` for failure (revert). | | `blobGasUsed` | string | Blob gas consumed by this transaction (EIP-4844). `null` for non-blob transactions. Propagated accurately in both finalized and pre-confirmed Flashblock state. | | `blobGasPrice` | string | Blob gas price at the time of this transaction (EIP-4844). `null` for non-blob transactions. | ## Error codes | Code | Message | Description | | --- | --- | --- | | `-32000` | transaction indexing is in progress | The node is still indexing transactions. Retry once the node finishes syncing. | ## Flashblock-specific response fields The Flashblocks infrastructure stream surfaces pre-confirmed receipt data inside the `metadata.receipts` map of each Flashblock payload before the block seals. The abbreviated receipt mirrors the standard receipt shape: | Field | Flashblock `metadata.receipts[hash]` | | --- | --- | | `type` | Transaction type (`0x0`, `0x1`, `0x2`, `0x7e`) | | `status` | `"0x1"` success / `"0x0"` failure | | `cumulativeGasUsed` | Cumulative gas in block to this transaction | | `logs` | Emitted log objects | | `logsBloom` | Bloom filter | | `transactionIndex` | Index in block | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_getTransactionReceipt", "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": { "transactionHash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238", "transactionIndex": "0x0", "blockHash": "0x3a4e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3", "blockNumber": "0x12ced28", "from": "0xd3CdA913deB6f4967b2Ef66ae97DE114a83bcc01", "to": "0x4200000000000000000000000000000000000006", "cumulativeGasUsed": "0x5208", "effectiveGasPrice": "0x3b9aca00", "gasUsed": "0x5208", "contractAddress": null, "logs": [], "logsBloom": "0x00000000000000000000000000000000...", "status": "0x1", "type": "0x2" } } ``` ### Response (not found) ```json { "jsonrpc": "2.0", "id": 1, "result": null } ``` --- # eth_maxPriorityFeePerGas Source: https://basehub.org/api-reference/eth/eth_maxpriorityfeepergas/ Description: Returns the suggested EIP-1559 priority fee (tip) per gas to pay the sequencer on top of the base fee. Returns a suggested value for `maxPriorityFeePerGas` to use in an EIP-1559 transaction. The value is the tip paid to the sequencer on top of the base fee. ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The suggested priority fee per gas in wei as a hexadecimal string. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_maxPriorityFeePerGas", "params": [], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0x1" } ``` --- # eth_sendRawTransaction Source: https://basehub.org/api-reference/eth/eth_sendrawtransaction/ Description: Submits a pre-signed RLP-encoded transaction to the network. Submit to a Flashblocks preconf endpoint for ~200ms pre-confirmation. Submits a pre-signed, RLP-encoded transaction to the network and returns the resulting transaction hash. Submit to `https://mainnet-preconf.base.org` to have the transaction considered for the next Flashblock (~200ms). After submission, call [`base_transactionStatus`](/api-reference/flashblocks/base_transactionStatus/) to confirm receipt in the mempool, then subscribe to [`newFlashblockTransactions`](/api-reference/flashblocks/newFlashblockTransactions/) to detect pre-confirmation. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `data` | string | Yes | The signed transaction as an RLP-encoded hex string. Typically produced by a wallet library such as viem, ethers.js, or web3.js. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The 32-byte transaction hash, returned when the transaction is accepted into the mempool. | ## Error codes | Code | Message | Description | | --- | --- | --- | | `-32000` | nonce too low | The transaction nonce is below the current account nonce. | | `-32000` | insufficient funds for gas * price + value | The sender's balance cannot cover the gas cost plus the value transferred. | | `-32000` | already known | An identical transaction is already in the mempool. | | `-32000` | replacement transaction underpriced | A replacement transaction must increase the gas price by at least 10%. | ## Example ### Request (standard) ```bash curl https://mainnet.base.org \ -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0x02f86b82210501843b9aca008477359400825208944200000000000000000000000000000000000006872c68af0bb1400080c001a0..."],"id":1}' ``` ### Request (Flashblocks preconf submission) ```bash curl https://mainnet-preconf.base.org \ -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0x02f86b82210501843b9aca008477359400825208944200000000000000000000000000000000000006872c68af0bb1400080c001a0..."],"id":1}' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238" } ``` --- # eth_subscribe Source: https://basehub.org/api-reference/eth/eth_subscribe/ Description: Opens a real-time WebSocket subscription. Flashblocks endpoints add three subscription types and emit newHeads roughly every 200ms. Opens a real-time event subscription over a WebSocket connection. Returns a subscription ID; events arrive as `eth_subscription` notifications without the client needing to poll. On `wss://mainnet-preconf.base.org`, `newHeads` fires every ~200ms (once per Flashblock) instead of every ~2 seconds. Three additional subscription types are exclusive to Flashblocks endpoints: [`newFlashblockTransactions`](/api-reference/flashblocks/newFlashblockTransactions/), [`pendingLogs`](/api-reference/flashblocks/pendingLogs/), and [`newFlashblocks`](/api-reference/flashblocks/newFlashblocks/). ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `subscriptionType` | string | Yes | The event type to subscribe to. | | `filterOptions` | object | No | Optional filter object. Only applicable for the `"logs"` subscription type. | The `filterOptions` object accepts: | Field | Type | Description | | --- | --- | --- | | `address` | string \| array | A contract address or array of addresses to filter by. Optional. | | `topics` | array | Array of topic filters in the same format as `eth_getLogs`. Optional. | ## Subscription types | Type | Description | Notification payload | | --- | --- | --- | | `newHeads` | Fires for each new block appended to the chain | Block header object (~200ms on Flashblocks endpoints) | | `logs` | Fires for each new log matching the filter criteria | Log object | | `newPendingTransactions` | Fires for each new transaction hash added to the mempool | Transaction hash string | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | A hex-encoded subscription ID. Every event notification from this subscription includes the same ID under `params.subscription`. | Event notifications arrive as unsolicited JSON-RPC messages: ```json { "jsonrpc": "2.0", "method": "eth_subscription", "params": { "subscription": "0x1887ec8b9589ccad00000000000532da", "result": { ... } } } ``` ## Example ### Subscribe to newHeads ```json {"jsonrpc": "2.0", "method": "eth_subscribe", "params": ["newHeads"], "id": 1} ``` ### Subscribe to logs (with filter) ```json { "jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": [ "logs", { "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] } ] } ``` ### Subscription ID response ```json {"jsonrpc": "2.0", "id": 1, "result": "0x1887ec8b9589ccad00000000000532da"} ``` ### newHeads event ```json { "jsonrpc": "2.0", "method": "eth_subscription", "params": { "subscription": "0x1887ec8b9589ccad00000000000532da", "result": { "number": "0x12ced29", "hash": "0x4b5e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e4", "parentHash": "0x3a4e8c5d7f2b1a6e9d0c4f8b3e7a2d5c8f1b4e7a0d3c6f9b2e5a8d1c4f7b0e3", "gasLimit": "0x1c9c380", "gasUsed": "0xa410", "timestamp": "0x6783a5d2", "baseFeePerGas": "0x3b9aca00" } } } ``` ### logs event ```json { "jsonrpc": "2.0", "method": "eth_subscription", "params": { "subscription": "0x2a7bc8d4e3f5a6b1c2d3e4f5a6b7c8d9", "result": { "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "topics": [ "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000d3cda913deb6f4967b2ef66ae97de114a83bcc01", "0x0000000000000000000000004200000000000000000000000000000000000006" ], "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", "blockNumber": "0x12ced29", "transactionHash": "0xc903239f...", "blockHash": "0x4b5e8c5d...", "logIndex": "0x0", "removed": false } } } ``` --- # eth_syncing Source: https://basehub.org/api-reference/eth/eth_syncing/ Description: Returns the sync status of the node. Returns false when the node is fully synced, otherwise an object describing sync progress. Returns the sync status of the node. Returns `false` when the node is fully synced. ## Parameters None. ## Returns `result` is `false` if the node is fully synced. Otherwise it is a sync status object with the following fields: | Field | Type | Description | | --- | --- | --- | | `startingBlock` | string | Block at which the sync started (hex). | | `currentBlock` | string | Current block being processed (hex). | | `highestBlock` | string | Estimated highest block (hex). | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "eth_syncing", "params": [], "id": 1 } ``` ### Response (synced) ```json { "jsonrpc": "2.0", "id": 1, "result": false } ``` --- # eth_unsubscribe Source: https://basehub.org/api-reference/eth/eth_unsubscribe/ Description: Cancels an active WebSocket subscription created with eth_subscribe and invalidates the subscription ID. Cancels a subscription created with [`eth_subscribe`](/api-reference/eth/eth_subscribe/). The subscription ID is no longer valid after this call. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `subscriptionId` | string | Yes | The subscription ID returned by `eth_subscribe`. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | boolean | `true` if the subscription was successfully cancelled, `false` if the subscription ID was not found. | ## Example ### Request ```json { "jsonrpc": "2.0", "id": 1, "method": "eth_unsubscribe", "params": ["0x1887ec8b9589ccad00000000000532da"] } ``` ### Response (success) ```json { "jsonrpc": "2.0", "id": 1, "result": true } ``` ### Response (not found) ```json { "jsonrpc": "2.0", "id": 1, "result": false } ``` --- # net_version Source: https://basehub.org/api-reference/eth/net_version/ Description: Returns the current network ID as a decimal string. Base Mainnet is 8453 and Base Sepolia is 84532. Returns the current network ID as a decimal string. ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The network ID as a decimal string. `"8453"` for Base Mainnet, `"84532"` for Base Sepolia. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1 } ``` ### Response (Base Mainnet) ```json { "jsonrpc": "2.0", "id": 1, "result": "8453" } ``` --- # web3_clientVersion Source: https://basehub.org/api-reference/eth/web3_clientversion/ Description: Returns the version string identifying the underlying node client software running the JSON-RPC endpoint. Returns the version string of the node client software. ## Parameters None. ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | The client version string. | ## Example ### Request ```json { "jsonrpc": "2.0", "method": "web3_clientVersion", "params": [], "id": 1 } ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": "op-reth/v1.1.0/linux-x86_64" } ``` --- # base_transactionStatus Source: https://basehub.org/api-reference/flashblocks/base_transactionstatus/ Description: Reports whether a transaction hash is present in the node mempool, useful for confirming submission before pre-confirmation lands. Reports whether a specific transaction is present in the node mempool. Use it to confirm that a submitted transaction has been received before it appears in a Flashblock. Only available on Flashblocks endpoints: `https://mainnet-preconf.base.org` / `https://sepolia-preconf.base.org`. Requires [base/base](https://github.com/base/base) minimum client version v0.3.0. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `transactionHash` | string | Yes | The 32-byte transaction hash to query. | ## Returns `result` is the transaction status object: | Field | Type | Description | | --- | --- | --- | | `status` | string | `"Known"` if the transaction is present in the mempool. `"Unknown"` if the node has not seen it. | ## Example ### Request ```bash curl https://mainnet-preconf.base.org \ -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"base_transactionStatus","params":["0xabc123..."],"id":1}' ``` ### Response (Known) ```json {"jsonrpc": "2.0", "id": 1, "result": {"status": "Known"}} ``` ### Response (Unknown) ```json {"jsonrpc": "2.0", "id": 1, "result": {"status": "Unknown"}} ``` --- # eth_simulateV1 Source: https://basehub.org/api-reference/flashblocks/eth_simulatev1/ Description: Simulates one or more transaction bundles against the current pre-confirmed Flashblock state, with state overrides and optional transfer tracing. Simulates one or more transaction bundles against the current pre-confirmed Flashblock state. Supports state overrides, multi-block simulation, and optional transfer tracing. Only available on Flashblocks endpoints: `https://mainnet-preconf.base.org` / `https://sepolia-preconf.base.org`. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `simulationPayload` | object | Yes | The simulation configuration. | | `blockParameter` | string | Yes | Use `"pending"` to simulate against the current Flashblock state. | The `simulationPayload` object accepts: | Field | Type | Required | Description | | --- | --- | --- | --- | | `blockStateCalls` | array | Yes | Array of block state call objects. Each object represents one simulated block. | | `traceTransfers` | boolean | No | If `true`, ETH transfer events are included as logs in the result. Defaults to `false`. | | `validation` | boolean | No | If `true`, transaction validation (nonce, balance) is enforced. Defaults to `false`. | Each entry in `blockStateCalls` accepts: | Field | Type | Description | | --- | --- | --- | | `calls` | array | Array of transaction call objects to simulate within this block. | | `stateOverrides` | object | Per-address state overrides applied before simulation (for example, balance, nonce, code, storage). Optional. | | `blockOverrides` | object | Block-level overrides (for example, `number`, `timestamp`). Optional. | ## Returns `result` is an array of simulated block results, one per entry in `blockStateCalls`. Each block result has: | Field | Type | Description | | --- | --- | --- | | `calls` | array | Array of individual call results. | Each entry in `calls` has: | Field | Type | Description | | --- | --- | --- | | `status` | string | `"0x1"` for success, `"0x0"` for failure. | | `gasUsed` | string | Gas used as a hexadecimal integer. | | `returnData` | string | Hex-encoded return data. | | `logs` | array | Logs emitted (including ETH transfer logs if `traceTransfers` is `true`). | | `error` | string | Revert reason if the call failed. Optional. | ## Example ### Request ```bash curl https://sepolia-preconf.base.org \ -X POST \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "eth_simulateV1", "params": [ { "blockStateCalls": [ { "calls": [{"to": "0x...", "data": "0x..."}], "stateOverrides": {} } ], "traceTransfers": true, "validation": true }, "pending" ], "id": 1 }' ``` ### Response ```json { "jsonrpc": "2.0", "id": 1, "result": [ { "calls": [ { "status": "0x1", "gasUsed": "0x5208", "returnData": "0x", "logs": [] } ] } ] } ``` --- # newFlashblocks Source: https://basehub.org/api-reference/flashblocks/newflashblocks/ Description: Subscribe to the full Flashblock payload stream and receive each pre-confirmed block delta as the sequencer builds it, every ~200ms. Subscribe via `eth_subscribe` to receive full block state updates as each Flashblock is built. Each message contains the accumulated pre-confirmed state for the block in progress. Only available on Flashblocks WebSocket endpoints: `wss://mainnet-preconf.base.org` and `wss://sepolia-preconf.base.org`. Requires [base/base](https://github.com/base/base) minimum client version v0.3.1. Each subscription emits one Flashblock object per WebSocket message, with events arriving roughly every 200ms. If your handler does heavy work per event, throttle or debounce it to avoid blocking. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `subscriptionType` | string | Yes | Must be `"newFlashblocks"`. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | Hex-encoded subscription ID. Each event notification delivers a Flashblock object — not a standard block object. The payload contains `payload_id`, `index`, `diff`, and (on index 0) `base`. See the [infrastructure stream schema](/api-reference/flashblocks/overview/#flashblock-object) for the full structure. | ## Example ### Subscribe ```json {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newFlashblocks"]} ``` ### Subscription ID response ```json {"jsonrpc": "2.0", "id": 1, "result": "0x3b8cd9e5f4a7b2c1d0e3f4a5b6c7d8e9"} ``` ### JavaScript ```javascript import WebSocket from 'ws'; // Use a Flashblocks-enabled provider WSS endpoint in production const ws = new WebSocket('wss://mainnet-preconf.base.org'); ws.on('open', () => { ws.send(JSON.stringify({ jsonrpc: '2.0', method: 'eth_subscribe', params: ['newFlashblocks'], id: 1 })); }); ws.on('message', (data) => { const msg = JSON.parse(data.toString()); if (msg.method === 'eth_subscription') { // Fires every ~200ms with the latest Flashblock state console.log('Flashblock update:', msg.params.result); } }); ``` --- # newFlashblockTransactions Source: https://basehub.org/api-reference/flashblocks/newflashblocktransactions/ Description: Subscribe to receive each transaction the sequencer pre-confirms into a Flashblock, optionally with full transaction and log data. Subscribe via `eth_subscribe` to receive each transaction as it is pre-confirmed into a Flashblock. Pass `true` as the second parameter to receive full transaction and log data. Only available on Flashblocks WebSocket endpoints: `wss://mainnet-preconf.base.org` / `wss://sepolia-preconf.base.org`. Requires [base/base](https://github.com/base/base) minimum client version v0.3.1. Each subscription emits one item per WebSocket message, with events arriving roughly every 200ms. If your handler does heavy work per event, throttle or debounce it to avoid blocking. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `subscriptionType` | string | Yes | Must be `"newFlashblockTransactions"`. | | `full` | boolean | No | If `true`, each notification includes the full transaction object and associated logs. Defaults to `false` (minimal data only). | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | Hex-encoded subscription ID. | ## Example ### Subscribe ```json {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newFlashblockTransactions"]} ``` ### Subscribe (full data) ```json {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newFlashblockTransactions", true]} ``` ### Subscription ID response ```json {"jsonrpc": "2.0", "id": 1, "result": "0x1887ec8b9589ccad00000000000532da"} ``` --- # Flashblocks API overview Source: https://basehub.org/api-reference/flashblocks/overview/ Description: Flashblocks-specific RPC methods, WebSocket subscriptions, and the infrastructure stream schema for Base pre-confirmations. Flashblocks endpoints expose every standard Ethereum JSON-RPC method along with a set of pre-confirmation-specific additions. Together they let you read state, simulate transactions, and stream events against sequencer-ordered data up to ~1.8 seconds before a block seals. All [standard Ethereum JSON-RPC methods](/api-reference/rpc-overview/) work identically on Flashblocks endpoints. Pass the `"pending"` block tag to resolve against pre-confirmed state instead of the transaction pool. See the [Overview](/api-reference/rpc-overview/) for endpoint URLs and a full description of the two tiers. ## HTTP methods | Method | Description | | --- | --- | | [`eth_simulateV1`](/api-reference/flashblocks/eth_simulateV1/) | Simulate transaction bundles against pre-confirmed state. | | [`base_transactionStatus`](/api-reference/flashblocks/base_transactionStatus/) | Check whether a transaction has been received by the node mempool. | ## WebSocket subscriptions On a Flashblocks WSS endpoint, `eth_subscribe` with `newHeads` emits a new event approximately every 200ms per Flashblock instead of every 2 seconds. Three additional subscription types are exclusive to Flashblocks endpoints: | Subscription | Description | | --- | --- | | [`newFlashblockTransactions`](/api-reference/flashblocks/newFlashblockTransactions/) | Stream individual transactions as they are pre-confirmed (~200ms each). | | [`pendingLogs`](/api-reference/flashblocks/pendingLogs/) | Stream filtered event logs from pre-confirmed transactions. | | [`newFlashblocks`](/api-reference/flashblocks/newFlashblocks/) | Stream full Flashblock payload objects from the sequencer. | ## Infrastructure stream The raw Flashblocks infrastructure stream is the upstream WebSocket feed consumed by Flashblocks-aware RPC nodes. It emits a new message approximately every 200ms as the sequencer pre-confirms transactions. Applications should not connect directly to the infrastructure stream — these endpoints are reserved for node operators. App developers should use the [WebSocket subscription methods](#websocket-subscriptions) above through a Flashblocks-aware RPC provider. | Network | Raw stream URL | | --- | --- | | Mainnet | `wss://mainnet.flashblocks.base.org/ws` | | Sepolia | `wss://sepolia.flashblocks.base.org/ws` | ### Flashblock object The root structure of each infrastructure stream message. | Field | Type | Description | | --- | --- | --- | | `payload_id` | string | Unique identifier for the block being built. Remains consistent across all Flashblocks within a single full block. | | `index` | number | Flashblock index within the current block. Starts at 0 (system transactions only). User transactions begin at index 1. Typically reaches 9–10 per block, but may exceed 10 during sequencer timing drift. | | `base` | Base Object | Block header properties. **Only present when `index` is `0`.** See [Base object](#base-object). | | `diff` | Diff Object | Incremental block state changes for this Flashblock. Present in every message. See [Diff object](#diff-object). | | `metadata` | Metadata Object | Supplemental data. **Unstable — fields may change without notice.** See [Metadata object](#metadata-object). | ### Base object Contains full block header properties. Only present in the `index: 0` message (the first Flashblock of each full block). | Field | Type | Description | | --- | --- | --- | | `parent_hash` | string | Hash of the parent block. | | `fee_recipient` | string | Address receiving transaction fees (coinbase). | | `block_number` | string | Block number in hex. | | `gas_limit` | string | Maximum gas allowed in this block (hex). | | `timestamp` | string | Unix timestamp of block creation (hex). | | `base_fee_per_gas` | string | EIP-1559 base fee per gas (hex). | | `prev_randao` | string | Previous RANDAO value used for on-chain randomness. | | `extra_data` | string | Arbitrary data field set by the sequencer. | ### Diff object Contains the incremental block state changes for this specific Flashblock. Present in every message. | Field | Type | Description | | --- | --- | --- | | `state_root` | string | Merkle root of the state trie after applying this Flashblock's transactions. | | `block_hash` | string | Hash of the partial block at this Flashblock index. Changes with each Flashblock as more transactions are pre-confirmed. | | `gas_used` | string | Cumulative gas used up to and including this Flashblock (hex). | | `blob_gas_used` | string | Cumulative blob gas used (EIP-4844, hex). | | `transactions` | string[] | Array of RLP-encoded transactions included in this Flashblock. | | `withdrawals` | array | Validator withdrawals (always empty on Base L2). | | `receipts_root` | string | Merkle root of transaction receipts. | | `logs_bloom` | string | Bloom filter for logs in this Flashblock. | | `withdrawals_root` | string | Merkle root of withdrawals. | ### Metadata object The `metadata` object is not stable. Fields may be added, modified, or removed without prior notice. Do not build production dependencies on it — use the [`diff`](#diff-object) object or query finalized block data via standard RPC instead. | Field | Type | Description | | --- | --- | --- | | `block_number` | number | Block number as a decimal integer. | | `new_account_balances` | object | Map of addresses to their updated ETH balances (hex). Only includes accounts whose balances changed in this Flashblock. | | `receipts` | object | Map of transaction hashes to their [Receipt](#receipt-object) objects. | ### Receipt object The abbreviated transaction receipt included in `metadata.receipts`. Check the `type` field to determine the transaction type. | Field | Type | Description | | --- | --- | --- | | `type` | string | Transaction type: `0x0` Legacy, `0x1` Access List, `0x2` EIP-1559, `0x7e` Deposit (L1→L2). | | `status` | string | Transaction status: `0x1` for success, `0x0` for failure. | | `cumulativeGasUsed` | string | Total gas used in the block up to and including this transaction (hex). | | `logs` | Log[] | Array of event logs emitted by the transaction. See [Log object](#log-object). | | `logsBloom` | string | Bloom filter for the logs in this receipt. | | `transactionIndex` | string | Index of the transaction within the block (hex). | ### Log object | Field | Type | Description | | --- | --- | --- | | `address` | string | Contract address that emitted the event. | | `topics` | string[] | Array of indexed event parameters. Topic 0 is typically the event signature hash. | | `data` | string | ABI-encoded non-indexed event parameters. | ### Complete examples Index 0 — includes the `base` object (block header): ```json { "payload_id": "0x03997352d799c31a", "index": 0, "base": { "parent_hash": "0x9edc29b8b0a1e31d28616e40c16132ad0d58faa8bb952595b557526bdb9a960a", "fee_recipient": "0x4200000000000000000000000000000000000011", "block_number": "0x158a0e9", "gas_limit": "0x3938700", "timestamp": "0x67bf8332", "base_fee_per_gas": "0xfa" }, "diff": { "state_root": "0x208fd63edc0681161105f27d03daf9f8c726d8c94e584a3c0696c98291c24333", "block_hash": "0x5c330e55a190f82ea486b61e5b12e27dfb4fb3cecfc5746886ef38ca1281bce8", "gas_used": "0xab3f", "transactions": ["0x7ef8f8a0b4afc0b7ce10e150801bbaf08ac33fecb0f38311793abccb022120d321c6d276..."], "withdrawals": [] }, "metadata": { "block_number": 22585577, "new_account_balances": { "0x000f3df6d732807ef1319fb7b8bb8522d0beac02": "0x0" }, "receipts": { "0x07d7f06b06fea714c1d1d446efa2790c6970aa74ee006186a32b5b7dd8ca2d82": { "type": "0x7e", "status": "0x1", "cumulativeGasUsed": "0xab3f", "logs": [], "logsBloom": "0x00000000...", "transactionIndex": "0x0" } } } } ``` Index 1–N (diff only) — no `base` object: ```json { "payload_id": "0x03997352d799c31a", "index": 4, "diff": { "state_root": "0x7a8f45038665072f382730e689f4a1561835c9987fca8942fa95872fb9367eaa", "block_hash": "0x9b32f7a14cbd1efc8c2c5cad5eb718ec9e0c5da92c3ba7080f8d4c49d660c332", "gas_used": "0x1234f", "transactions": ["0x02f90133...", "0x02f90196..."], "withdrawals": [] }, "metadata": { "block_number": 22585577, "new_account_balances": { "0x4200000000000000000000000000000000000015": "0x1234" }, "receipts": { "0x7c69632dc315f13a...": { "type": "0x2", "status": "0x1", "cumulativeGasUsed": "0x1234f", "logs": [], "logsBloom": "0x00000000...", "transactionIndex": "0x1" } } } } ``` --- # pendingLogs Source: https://basehub.org/api-reference/flashblocks/pendinglogs/ Description: Subscribe to logs from pre-confirmed transactions matching an optional address and topics filter, with sub-block latency on Flashblocks endpoints. Subscribe via `eth_subscribe` to receive logs from pre-confirmed transactions matching an optional filter. Useful for monitoring contract events with sub-block latency. Only available on Flashblocks WebSocket endpoints: `wss://mainnet-preconf.base.org` / `wss://sepolia-preconf.base.org`. Requires [base/base](https://github.com/base/base) minimum client version v0.3.1. Each subscription emits one item per WebSocket message, with events arriving roughly every 200ms. If your handler does heavy work per event, throttle or debounce it to avoid blocking. ## Parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `subscriptionType` | string | Yes | Must be `"pendingLogs"`. | | `filterOptions` | object | No | Optional log filter. | The `filterOptions` object accepts: | Field | Type | Description | | --- | --- | --- | | `address` | string \| array | A single contract address or array of addresses to filter by. | | `topics` | array | Array of topic filters in the same format as `eth_getLogs`. | ## Returns | Field | Type | Description | | --- | --- | --- | | `result` | string | Hex-encoded subscription ID. | ## Example ### Subscribe (with filter) ```json { "jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": [ "pendingLogs", { "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"] } ] } ``` ### Subscription ID response ```json {"jsonrpc": "2.0", "id": 1, "result": "0x2a7bc8d4e3f5a6b1c2d3e4f5a6b7c8d9"} ``` --- # RPC overview Source: https://basehub.org/api-reference/rpc-overview/ Description: Full reference for the JSON-RPC and Flashblocks methods exposed by Base nodes across the eth, net, web3, debug, txpool, and base namespaces. import { Tabs, TabItem, Aside } from '@astrojs/starlight/components'; Base exposes one EVM-compatible JSON-RPC API across two performance tiers. Switch a single endpoint URL and the `pending` block tag to move from 2-second sealed blocks to 200ms pre-confirmations — every other method behaves the same. ## Networks | Network | Chain ID | Type | Archive | | :--- | :--- | :--- | :--- | | Mainnet | `8453` | Production | Yes | | Sepolia | `84532` | Testnet | Yes | ## Endpoints | Tier | HTTP | WSS | | :--- | :--- | :--- | | Standard | `https://mainnet.base.org` | `wss://mainnet.base.org` | | Flashblocks | `https://mainnet-preconf.base.org` | `wss://mainnet-preconf.base.org` | | Tier | HTTP | WSS | | :--- | :--- | :--- | | Standard | `https://sepolia.base.org` | `wss://sepolia.base.org` | | Flashblocks | `https://sepolia-preconf.base.org` | `wss://sepolia-preconf.base.org` | ## The Flashblocks tier Flashblocks endpoints are fully EVM-equivalent — every standard `eth_` method works identically. The difference is what the `pending` block tag returns. - On **Standard** endpoints, `pending` reflects the transaction pool (unmined state). - On **Flashblocks** endpoints, `pending` reflects the **pre-confirmed block currently being built**, refreshed every ~200ms with new batches of sequencer-ordered transactions. Methods such as `eth_getBalance`, `eth_getStorageAt`, and `eth_call` execute against real sequencer state up to 1.8 seconds before a block seals, with sub-second latency. ## Namespaces Base nodes implement the standard Ethereum namespaces plus a small set of Base-specific methods. - **`eth`** — core Ethereum protocol methods for accounts, blocks, transactions, gas, and logs. Available on both Standard and Flashblocks endpoints. - **`net`** — network identification (`net_version`). - **`web3`** — client identification (`web3_clientVersion`). - **`debug`** — replay and tracing utilities for deep transaction inspection. Computationally expensive; availability depends on the node provider. - **`txpool`** — inspection of the local mempool. - **`base`** — Base-specific helpers, including pre-confirmation status checks (`base_transactionStatus`). - **Flashblocks** — pre-confirmation methods (`eth_simulateV1`) and WebSocket streams (`newFlashblockTransactions`, `pendingLogs`, `newFlashblocks`) available only on Flashblocks endpoints. ## Method index ### Ethereum JSON-RPC API Methods marked with a check mark support the `"pending"` block tag on Flashblocks endpoints. | Method | Description | Flashblocks `pending` | | :--- | :--- | :--- | | [eth_blockNumber](/api-reference/eth/eth_blocknumber/) | Current block number | — | | [eth_getBalance](/api-reference/eth/eth_getbalance/) | Account ETH balance | yes | | [eth_getTransactionCount](/api-reference/eth/eth_gettransactioncount/) | Account nonce / tx count | yes | | [eth_getCode](/api-reference/eth/eth_getcode/) | Deployed contract bytecode | yes | | [eth_getStorageAt](/api-reference/eth/eth_getstorageat/) | Contract storage slot value | yes | | [eth_call](/api-reference/eth/eth_call/) | Execute read-only call | yes | | [eth_getBlockByNumber](/api-reference/eth/eth_getblockbynumber/) | Block data by number | yes | | [eth_getBlockByHash](/api-reference/eth/eth_getblockbyhash/) | Block data by hash | — | | [eth_getBlockReceipts](/api-reference/eth/eth_getblockreceipts/) | All receipts for a block | yes | | [eth_getBlockTransactionCountByNumber](/api-reference/eth/eth_getblocktransactioncountbynumber/) | Tx count by block number | yes | | [eth_getBlockTransactionCountByHash](/api-reference/eth/eth_getblocktransactioncountbyhash/) | Tx count by block hash | — | | [eth_getTransactionByHash](/api-reference/eth/eth_gettransactionbyhash/) | Transaction data by hash | — | | [eth_getTransactionByBlockHashAndIndex](/api-reference/eth/eth_gettransactionbyblockhashandindex/) | Tx by block hash and index | — | | [eth_getTransactionByBlockNumberAndIndex](/api-reference/eth/eth_gettransactionbyblocknumberandindex/) | Tx by block number and index | — | | [eth_getTransactionReceipt](/api-reference/eth/eth_gettransactionreceipt/) | Receipt for a mined tx | — | | [eth_sendRawTransaction](/api-reference/eth/eth_sendrawtransaction/) | Submit signed transaction | — | | [eth_gasPrice](/api-reference/eth/eth_gasprice/) | Current gas price | — | | [eth_maxPriorityFeePerGas](/api-reference/eth/eth_maxpriorityfeepergas/) | Max priority fee estimate | — | | [eth_feeHistory](/api-reference/eth/eth_feehistory/) | Historical base fee and rewards | — | | [eth_estimateGas](/api-reference/eth/eth_estimategas/) | Estimate gas for a tx | yes | | [eth_getLogs](/api-reference/eth/eth_getlogs/) | Query event logs by filter | yes | | [eth_chainId](/api-reference/eth/eth_chainid/) | Network chain ID | — | | [eth_syncing](/api-reference/eth/eth_syncing/) | Node sync status | — | | [net_version](/api-reference/eth/net_version/) | Network version ID | — | | [web3_clientVersion](/api-reference/eth/web3_clientversion/) | Client version string | — | | [eth_subscribe](/api-reference/eth/eth_subscribe/) | Subscribe to events (WSS) | yes | | [eth_unsubscribe](/api-reference/eth/eth_unsubscribe/) | Cancel a subscription (WSS) | — | ### Flashblocks API Pre-confirmation methods that deliver sub-second transaction signals on Base. These are only available on Flashblocks endpoints and let you read state, simulate bundles, and stream events up to ~1.8 seconds ahead of block sealing. | Method | Description | | --- | --- | | [eth_simulateV1](/api-reference/flashblocks/eth_simulatev1/) | Simulate transaction bundles against pre-confirmed state | | [base_transactionStatus](/api-reference/flashblocks/base_transactionstatus/) | Check whether a transaction has been received by the mempool | | [newFlashblockTransactions](/api-reference/flashblocks/newflashblocktransactions/) | Subscribe to individual pre-confirmed transactions | | [pendingLogs](/api-reference/flashblocks/pendinglogs/) | Subscribe to filtered logs from pre-confirmed transactions | | [newFlashblocks](/api-reference/flashblocks/newflashblocks/) | Subscribe to the full Flashblock payload stream | ### Debug API Development and debugging utilities for transaction replay and block inspection. Debug methods replay execution and are computationally expensive — availability and rate limits vary by node provider. | Method | Description | | --- | --- | | [debug_traceTransaction](/api-reference/debug/debug_tracetransaction/) | Full EVM execution trace for a transaction | | [debug_traceBlockByHash](/api-reference/debug/debug_traceblockbyhash/) | EVM traces for every transaction in a block by hash | | [debug_traceBlockByNumber](/api-reference/debug/debug_traceblockbynumber/) | EVM traces for every transaction in a block by number | ## Request and response format All requests are HTTP `POST` with `Content-Type: application/json`. | Field | Type | Description | | :--- | :--- | :--- | | `jsonrpc` | string | Always `"2.0"` | | `method` | string | The RPC method name | | `params` | array | Method parameters in order | | `id` | number \| string | Identifier echoed back in the response | **Request:** ```json { "jsonrpc": "2.0", "method": "eth_getBalance", "params": ["0x742d35Cc6634C0532925a3b8D4C9dD0b4f3BaEa", "pending"], "id": 1 } ``` **Success response:** ```json { "jsonrpc": "2.0", "id": 1, "result": "0x1a055690d9db80000" } ``` **Error response:** ```json { "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "Invalid params" } } ``` ## Error codes | Code | Name | Description | | --- | --- | --- | | `-32700` | Parse error | Invalid JSON | | `-32600` | Invalid request | Not a valid JSON-RPC 2.0 object | | `-32601` | Method not found | Method does not exist or is unavailable | | `-32602` | Invalid params | Invalid method parameters | | `-32603` | Internal error | Internal JSON-RPC error | | `-32000` | Server error | Node-specific error (see message) | ## Block parameters | Value | Standard | Flashblocks | | --- | --- | --- | | `"latest"` | Most recently sealed block | Most recently sealed block | | `"pending"` | Unmined transaction pool state | **Current Flashblock in progress (~200ms resolution)** | | `"safe"` | Latest safe block | Latest safe block | | `"finalized"` | Latest finalized block | Latest finalized block | | `"earliest"` | Genesis block | Genesis block | | `"0x"` | Specific block by number | Specific block by number | --- # Crate Dependency Graph Source: https://basehub.org/architecture/crate-graph/ Description: Visual map of workspace dependencies across the 8 crate groups in base/base. The `base/base` workspace organizes 8 top-level crate groups into a directed acyclic dependency graph. This page traces how the groups connect, which crates are foundational, and where the integration boundaries sit. ## High-level dependency flow The dependency graph flows downward: higher-level groups depend on lower-level ones, but not the reverse. ``` ┌─────────────────────────────────────────────────────┐ │ infra │ │ based, basectl, ingress-rpc, websocket-proxy, ... │ └───────────┬──────────┬──────────┬───────────────────┘ │ │ │ v v v ┌──────────────┐ ┌──────────┐ ┌──────────┐ │ builder │ │ client │ │consensus │ │ core, pub, │ │ node,cli,│ │ protocol,│ │ metering │ │ engine, │ │ rpc,kona │ │ │ │ flash │ │ │ └──────┬───────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ ┌────┘ │ │ v │ │ ┌──────────┐ │ └───►│execution │◄──────────┘ └────┬─────┘ │ v ┌──────────┐ ┌──────────┐ │ shared │◄────│ proof │ └────┬─────┘ └──────────┘ │ v ┌──────────┐ │ alloy │ └──────────┘ ``` **Key observations:** - **`alloy`** and **`shared`** sit at the bottom of the graph. They have no internal workspace dependencies and are consumed by everything above them. - **`execution`** depends on `shared` and `alloy` for types, and is consumed by both `client` and `builder`. - **`client`** is the main integration point -- it pulls in execution, consensus, and shared. - **`infra`** binaries sit at the top, assembling components from multiple groups. - **`proof`** is relatively isolated. It depends on `shared` for types but has its own Kona-derived execution and derivation logic (designed to run inside a fault proof VM). ## Detailed crate-level dependencies ### Alloy crates ``` alloy/ └── (external: alloy-rs ecosystem) No internal workspace dependencies. Consumed by: shared, client, consensus, builder, execution ``` The alloy crates define Ethereum and Optimism wire types using the [Alloy](https://github.com/alloy-rs/alloy) framework. They are leaf dependencies with no intra-workspace imports. ### Shared crates ``` shared/ ├── base-primitives ← foundational types (blocks, txs, receipts) ├── base-bundles ← depends on: base-primitives ├── base-jwt ← standalone (JWT auth tokens) ├── base-cli-utils ← standalone (CLI helpers) ├── base-engine-ext ← depends on: base-primitives ├── base-access-lists ← depends on: base-primitives ├── base-reth-rpc-types ← depends on: base-primitives └── base-txpool-rpc ← depends on: base-primitives, base-reth-rpc-types ``` [`base-primitives`](https://github.com/base/base/tree/main/crates/shared/primitives) is the single most depended-upon crate. It defines `BaseTxEnvelope`, `BaseBlock`, chain IDs, and fee calculation types. Almost every other workspace crate imports it directly or transitively. ### Execution crates ``` execution/ └── (execution crates) depends on: base-primitives, alloy types consumed by: client, builder ``` The execution group provides Base's EVM configuration. It depends on `base-primitives` for block and transaction types and on alloy types for encoding. The `client` and `builder` groups both consume execution crates to run EVM state transitions. ### Consensus crates ``` consensus/ ├── base-protocol ← depends on: base-primitives ├── base-consensus-rpc ← depends on: base-protocol, base-primitives │ └── kona-* (vendored) ├── kona-node-service ← top-level; depends on most kona-* below ├── kona-engine ← depends on: kona-derive, kona-providers-alloy ├── kona-derive ← depends on: kona-sources, kona-genesis, kona-hardforks ├── kona-gossip ← depends on: kona-disc, kona-peers ├── kona-sources ← depends on: kona-providers-alloy ├── kona-providers-alloy ← depends on: kona-genesis ├── kona-genesis ← depends on: kona-registry ├── kona-registry ← depends on: kona-hardforks ├── kona-hardforks ← leaf ├── kona-disc ← leaf (peer discovery) ├── kona-peers ← leaf (peer management) ├── kona-cli ← leaf (CLI utils) └── kona-macros ← leaf (proc macros) ``` The Kona crates form their own internal dependency tree. `kona-node-service` is the top-level entry point, and `kona-derive` is the core derivation pipeline. The Base-native consensus crates (`base-protocol`, `base-consensus-rpc`) integrate with the Kona stack and provide Base-specific protocol constants. ### Builder crates ``` builder/ ├── base-builder-core ← depends on: base-primitives, base-bundles, │ execution crates, base-engine-ext ├── base-builder-publish ← depends on: base-builder-core, base-primitives └── base-builder-metering ← depends on: base-builder-core ``` The builder's dependency chain: ``` base-builder-metering ──► base-builder-core ──► base-primitives │ │ base-builder-publish ───────────┘ v alloy types │ v execution crates ``` `base-builder-core` contains the block building loop and depends on execution crates for EVM access and on `base-primitives` for block/transaction types. `base-builder-publish` handles the output side -- streaming flashblocks and submitting sealed blocks. ### Client crates ``` client/ ├── base-client-node ← depends on: base-client-cli, base-client-engine, │ base-flashblocks, base-metering, base-txpool-tracing, │ execution crates, consensus crates, shared crates ├── base-client-cli ← depends on: base-cli-utils ├── base-client-engine ← depends on: base-primitives, base-engine-ext ├── base-flashblocks ← depends on: base-primitives ├── base-metering ← depends on: base-primitives, base-reth-rpc-types └── base-txpool-tracing ← depends on: base-primitives ``` `base-client-node` is the integration hub. It is where Reth's `NodeBuilder` is configured with all Base-specific components. Its dependency list is the longest in the workspace because it wires together execution, consensus, flashblocks, metering, and the transaction pool. ### Proof crates ``` proof/ ├── kona-proof ← depends on: kona-driver, kona-mpt ├── kona-driver ← depends on: kona-executor, kona-preimage ├── kona-executor ← depends on: kona-mpt, kona-preimage ├── kona-mpt ← leaf (Merkle Patricia Trie) ├── kona-preimage ← leaf (preimage oracle interface) ├── kona-std-fpvm ← leaf (FPVM runtime) └── kona-std-fpvm-proc ← leaf (proc macros for FPVM) ``` The proof group is intentionally isolated from the rest of the workspace. It must be compilable to FPVM targets (MIPS/RISC-V), so it avoids pulling in networking, RPC, or OS-specific dependencies. It re-implements derivation and execution logic using `kona-preimage` to read data from the host environment. ### Infra crates ``` infra/ ├── based ← depends on: client, builder, consensus, shared ├── basectl-cli ← depends on: shared (base-cli-utils, base-primitives) ├── ingress-rpc-lib ← depends on: shared (base-jwt, base-primitives) ├── websocket-proxy ← depends on: shared (base-primitives) ├── mempool-rebroadcaster ← depends on: shared (base-primitives, base-txpool-rpc) ├── audit-archiver-lib ← depends on: shared (base-primitives) └── system-tests ← depends on: client, shared, infra binaries ``` Infra crates are consumers. They import from the lower layers but are not imported by any other workspace crate (except `system-tests`, which depends on infra binaries for integration testing). ## Dependency rules The workspace follows these conventions: 1. **No circular dependencies.** The crate graph is a DAG. 2. **Shared and alloy are leaf layers.** They never depend on higher-level groups. 3. **Proof is sandboxed.** Proof crates do not depend on client, builder, or infra crates, keeping them FPVM-compilable. 4. **External Reth dependencies flow through execution and client.** Other groups do not directly import `reth-*` crates; they go through the abstractions in execution or shared. 5. **Kona crates are vendored, not patched.** The consensus and proof groups contain full copies of Kona crates (not Git patches), allowing Base-specific modifications while preserving the ability to pull upstream changes. ## Workspace Cargo.toml structure All inter-crate dependencies are declared as workspace dependencies in the root [`Cargo.toml`](https://github.com/base/base/blob/main/Cargo.toml). Individual crate `Cargo.toml` files reference these with `workspace = true`: ```toml # Root Cargo.toml (excerpt) [workspace.dependencies] base-primitives = { path = "crates/shared/primitives" } base-builder-core = { path = "crates/builder/core" } base-client-node = { path = "crates/shared/node" } # ... etc. ``` This centralized dependency management ensures version consistency and makes it straightforward to audit the full dependency graph. --- # Execution Pipeline Source: https://basehub.org/architecture/execution-pipeline/ Description: Transaction flow from RPC receipt through the transaction pool, payload building, EVM execution, state trie update, and block production. A transaction enters the Base node through the RPC layer, lands in the pool, gets selected by the builder, executes against the EVM, and lands in a sealed block committed to the state trie. Each stage below names the crate that owns it. ## Pipeline overview ``` User/Wallet │ ▼ ┌──────────────────┐ │ 1. RPC Ingress │ ingress-rpc-lib, base-reth-rpc-types └────────┬─────────┘ ▼ ┌──────────────────┐ │ 2. Transaction │ base-txpool-rpc, base-txpool-tracing, │ Pool │ base-access-lists, base-bundles └────────┬─────────┘ ▼ ┌──────────────────┐ │ 3. Payload │ base-builder-core, base-engine-ext │ Building │ └────────┬─────────┘ ▼ ┌──────────────────┐ │ 4. EVM │ execution crates (EvmConfig), │ Execution │ base-primitives └────────┬─────────┘ ▼ ┌──────────────────┐ │ 5. State Trie │ Reth's state database, │ Update │ kona-mpt (for proofs) └────────┬─────────┘ ▼ ┌──────────────────┐ │ 6. Block │ base-builder-publish, │ Sealing │ base-client-engine └──────────────────┘ ``` ## Stage 1: RPC ingress Transactions enter the system through JSON-RPC endpoints. The Base node exposes the standard Ethereum JSON-RPC API (`eth_sendRawTransaction`) plus Base-specific extensions. **Relevant crates:** - [`ingress-rpc-lib`](https://github.com/base/base/tree/main/crates/infra/ingress-rpc) -- in production deployments, an ingress proxy sits in front of the node. It handles rate limiting, authentication (via `base-jwt`), and request routing. The proxy forwards validated requests to the node's internal RPC server. - [`base-reth-rpc-types`](https://github.com/base/base/tree/main/crates/shared/rpc-types) -- defines the request and response types for Base-specific RPC methods. When the node receives `eth_sendRawTransaction`, it: 1. Decodes the RLP-encoded transaction bytes into a `BaseTxEnvelope` (defined in `base-primitives`). 2. Validates the signature, chain ID, and basic transaction fields. 3. Submits the transaction to the transaction pool. For bundle submissions (used by MEV searchers), the `base-bundles` crate defines the `BaseBundle` type, which groups multiple transactions with ordering constraints and tip payments. ## Stage 2: Transaction pool The transaction pool holds pending transactions that are valid but not yet included in a block. Base uses Reth's built-in transaction pool with custom extensions. **Relevant crates:** - [`base-txpool-rpc`](https://github.com/base/base/tree/main/crates/shared/txpool-rpc) -- RPC methods for querying pool state (`txpool_content`, `txpool_status`, and Base-specific methods). - [`base-txpool-tracing`](https://github.com/base/base/tree/main/crates/client/txpool-tracing) -- emits tracing events for transaction lifecycle (received, promoted, dropped, included). Useful for debugging and monitoring. - [`base-access-lists`](https://github.com/base/base/tree/main/crates/shared/access-lists) -- access list generation. When a transaction declares storage slots it will touch, the pool can pre-validate these and the execution engine can optimize state loading. - [`base-bundles`](https://github.com/base/base/tree/main/crates/shared/bundles) -- bundle handling logic. Bundles are stored separately from individual transactions and are evaluated atomically during payload building. The pool maintains several sub-pools: - **Pending** -- transactions ready for immediate inclusion (correct nonce, sufficient balance). - **Queued** -- transactions with future nonces, waiting for gaps to fill. - **Basefee** -- transactions whose `maxFeePerGas` is below the current base fee. They become pending when the base fee drops. Transactions are sorted by **effective tip** (the priority fee the builder would receive). The builder pulls from the pending pool in tip-descending order. ## Stage 3: Payload building Payload building is the process of selecting transactions from the pool and assembling them into a candidate block. In Base, this happens in the builder, which operates on a configurable interval. **Relevant crates:** - [`base-builder-core`](https://github.com/base/base/tree/main/crates/builder/core) -- the main building loop. It: 1. Receives a `PayloadAttributes` message from the consensus layer (via `engine_forkchoiceUpdated`). This message includes the parent block hash, timestamp, and any **deposit transactions** from L1. 2. Pulls pending transactions from the pool, sorted by effective tip. 3. Applies each transaction against the current state to check validity and compute gas used. 4. Respects the block gas limit and any per-transaction gas limits. 5. Optionally includes bundles, evaluating them atomically (all-or-nothing). - [`base-engine-ext`](https://github.com/base/base/tree/main/crates/shared/engine-ext) -- Engine API extensions that carry additional payload attributes specific to Base (e.g., Flashblocks configuration, builder identity). ### Deposit transactions Every L2 block begins with **deposit transactions** -- L1-to-L2 messages derived from L1 by the consensus layer. These are mandatory and always placed at the top of the block, before any user transactions. The builder does not select them from the pool; they are injected by the engine. The ordering within a block is: ``` ┌──────────────────────────────────────┐ │ Deposit transactions (from L1) │ ← mandatory, first ├──────────────────────────────────────┤ │ User transactions (from pool) │ ← sorted by effective tip ├──────────────────────────────────────┤ │ Bundle transactions (if any) │ ← evaluated atomically └──────────────────────────────────────┘ ``` ### Flashblocks sub-intervals In Flashblocks mode, the builder does not wait for the full 2-second block time. Instead, it produces partial payloads (**flashblocks**) every 200 milliseconds. Each flashblock contains whatever transactions have been processed since the last interval. See [Flashblocks Pipeline](/architecture/flashblocks-pipeline/) for details. ## Stage 4: EVM execution Each transaction is executed against the Ethereum Virtual Machine. Base uses Reth's EVM with an Optimism-specific configuration. **Relevant crates:** - Execution crates in [`crates/execution/`](https://github.com/base/base/tree/main/crates/execution) -- provide the `EvmConfig` implementation that configures: - **L1 data fee** -- Optimism charges an additional fee based on the transaction's L1 data cost (the cost of posting the transaction data to L1). This is calculated using the L1 base fee and blob base fee, which are read from the L1 attributes deposit transaction at the start of each block. - **Custom precompiles** -- Base may add precompiles beyond the standard Ethereum set. - **System transactions** -- the L1 attributes deposit transaction updates on-chain variables (`l1BaseFee`, `l1BlobBaseFee`, `sequenceNumber`, etc.) by calling the `L1Block` system contract. - [`base-primitives`](https://github.com/base/base/tree/main/crates/shared/primitives) -- defines the transaction envelope types that the EVM processes, including Optimism deposit transactions (`TxDeposit`). The EVM execution loop for each transaction: 1. **Load sender state** -- retrieve the sender's nonce and balance from the state trie. 2. **Validate** -- check nonce matches, balance covers `gasLimit * gasPrice + value`, and the transaction is well-formed. 3. **Deduct upfront cost** -- subtract the maximum possible gas cost from the sender's balance. 4. **Execute** -- run the EVM bytecode. For contract creations, deploy the code. For calls, execute the target contract. 5. **Apply state changes** -- write modified storage slots, created/destroyed accounts, and balance transfers to the state. 6. **Calculate gas refund** -- refund unused gas to the sender (up to the refund cap). 7. **Pay fees** -- transfer the priority fee to the builder's fee recipient. The base fee is burned. The L1 data fee is sent to the L1 fee vault. 8. **Emit receipt** -- produce a transaction receipt with status, gas used, and logs. ## Stage 5: State trie update After all transactions in the payload are executed, the resulting state changes are committed to the state trie. Base uses Reth's state storage, which maintains: - **Account trie** -- maps addresses to account state (nonce, balance, storage root, code hash). - **Storage tries** -- per-account Merkle Patricia Tries mapping storage slots to values. - **State root** -- the root hash of the account trie, included in the block header. The state root is a cryptographic commitment to the entire world state after the block's execution. It is used by: - **Consensus** -- the consensus layer verifies that the state root in a proposed block matches the result of re-executing all transactions. - **Fault proofs** -- the proof system (`kona-mpt`) uses Merkle Patricia Trie proofs to verify individual state transitions without re-executing the entire block. For fault proof purposes, [`kona-mpt`](https://github.com/base/base/tree/main/crates/proof/mpt) provides a standalone MPT implementation that can verify inclusion/exclusion proofs against a known state root inside the FPVM. ## Stage 6: Block sealing Once all transactions are executed and the state root is computed, the block is sealed. **Relevant crates:** - [`base-builder-publish`](https://github.com/base/base/tree/main/crates/builder/publish) -- the builder packages the sealed payload (transactions, receipts, state root, block header) and publishes it. - [`base-client-engine`](https://github.com/base/base/tree/main/crates/client/engine) -- the node's engine handler receives the sealed payload via `engine_newPayload` and: 1. Validates the payload (re-executes transactions and checks the state root). 2. Stores the block in the database. 3. Updates the chain tip via `engine_forkchoiceUpdated`. The sealed block header contains: | Field | Source | |---|---| | `parentHash` | Previous block's hash | | `stateRoot` | Computed from stage 5 | | `transactionsRoot` | Merkle root of the transaction list | | `receiptsRoot` | Merkle root of the receipt list | | `logsBloom` | Bloom filter over all logs | | `gasUsed` | Total gas consumed by all transactions | | `timestamp` | From the `PayloadAttributes` | | `baseFeePerGas` | Calculated from parent block's gas usage via EIP-1559 | | `extraData` | Builder-specific metadata | ## End-to-end latency In normal operation (non-Flashblocks mode), the full pipeline from transaction receipt to block sealing takes up to 2 seconds (the L2 block time). In Flashblocks mode, the first confirmation comes within 200 milliseconds because the builder streams partial results as they are produced. | Mode | First confirmation | Final block | |---|---|---| | Standard | ~2 seconds | 2 seconds | | Flashblocks | ~200 milliseconds | 2 seconds | The Flashblocks pipeline does not change the final block structure -- it only provides earlier visibility into which transactions will be included. The sealed block at the end of the 2-second interval is identical regardless of whether Flashblocks streaming was active. --- # Flashblocks Pipeline Source: https://basehub.org/architecture/flashblocks-pipeline/ Description: How the builder produces flashblocks at 200ms sub-block intervals, streams them over WebSockets, and reconciles state at block boundaries. Flashblocks are partial block updates the builder emits every 200 milliseconds within a 2-second L2 block. They deliver sub-second inclusion confirmation without altering the sealed block or the consensus protocol. The sections below cover how the builder produces flashblocks, how they stream to consumers, and how state reconciles when the block seals. ## Motivation Standard L2 blocks on Base are produced every 2 seconds. For latency-sensitive applications (trading, gaming, real-time UIs), 2 seconds is too slow for a responsive experience. Flashblocks reduce the effective confirmation time to approximately 200 milliseconds by streaming the builder's work-in-progress. A flashblock is not a new consensus primitive. It is an **application-layer optimization**: the builder shares its intermediate results before the block is finalized. Consumers who trust the sequencer can act on flashblocks immediately; consumers who require consensus finality wait for the sealed block as usual. ## Architecture The Flashblocks pipeline involves three crate groups: ``` ┌──────────────────────────────────────────────────────────────┐ │ Builder │ │ │ │ ┌───────────────────┐ ┌───────────────────┐ │ │ │ base-builder-core │───►│base-builder-publish│──► Engine API │ │ │ │ │ │ │ │ │ tx selection, │ │ flashblock framing│ │ │ │ EVM execution, │ │ WebSocket publish │ │ │ │ 200ms timer │ │ sealed block emit │ │ │ └───────────────────┘ └────────┬──────────┘ │ │ │ │ │ ┌───────────────────┐ │ │ │ │base-builder-meter.│ │ │ │ │ │ │ │ │ │ build time, tx │ │ │ │ │ count, revenue │ │ │ │ └───────────────────┘ │ │ └────────────────────────────────────┼──────────────────────────┘ │ ▼ ┌───────────────────┐ │ websocket-proxy │ (infra) │ │ │ fan-out to │ │ subscribers │ └────────┬──────────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ Client A Client B Client C ``` ``` ┌──────────────────────────────────────────────────────────────┐ │ Client Node │ │ │ │ ┌───────────────────┐ ┌───────────────────┐ │ │ │ base-flashblocks │◄───│ base-client-engine│ │ │ │ │ │ │ │ │ │ flashblock state │ │ engine API handler│ │ │ │ tracking, sub │ │ payload validation│ │ │ │ management │ │ │ │ │ └───────────────────┘ └───────────────────┘ │ └──────────────────────────────────────────────────────────────┘ ``` ## The build loop The core building loop in [`base-builder-core`](https://github.com/base/base/tree/main/crates/builder/core) operates on a timer-driven cycle within each 2-second block interval. ### Step 1: Receive payload attributes The consensus layer sends `engine_forkchoiceUpdated` with `PayloadAttributes` to begin a new block. The attributes include: - **Parent block hash** -- the block to build on top of. - **Timestamp** -- the L2 timestamp for the new block. - **Deposit transactions** -- mandatory L1-to-L2 messages that must appear at the start of the block. - **Fee recipient** -- the address that receives priority fees. - **Flashblocks configuration** -- whether flashblocks are enabled and the sub-interval duration (default: 200ms). ### Step 2: Initialize the build context The builder sets up: - A mutable state overlay on top of the parent block's state. - A running transaction list (starts with the deposit transactions). - A cumulative gas counter. - A 200ms interval timer. - A flashblock sequence counter (starting at 0). ### Step 3: Execute transactions in sub-intervals The builder enters a loop that repeats every 200 milliseconds until the block time expires: ``` for each 200ms interval: 1. Pull pending transactions from the pool (sorted by effective tip) 2. Execute each transaction against the state overlay: - If the transaction succeeds: append to the running tx list, update cumulative gas, record the receipt - If the transaction fails (reverts, out-of-gas, nonce mismatch): skip it and try the next 3. Compute the intermediate state root 4. Emit a flashblock containing: - The transactions processed in this interval - The receipts for those transactions - The cumulative gas used so far - The intermediate state root - The flashblock index (0, 1, 2, ...) - The block number and parent hash 5. Increment the flashblock sequence counter ``` A typical 2-second block produces up to **10 flashblocks** (2000ms / 200ms). In practice, the number may be fewer if the builder finishes processing all pending transactions before the block time expires. ### Step 4: Seal the block When the block timer expires, the builder: 1. Stops accepting new transactions. 2. Computes the final state root. 3. Assembles the complete block header (with all transactions from all flashblocks). 4. Sends the sealed payload to the node via `engine_newPayload`. The sealed block is identical to what would have been produced without Flashblocks. The only difference is that consumers received incremental updates during construction. ## Publishing: `base-builder-publish` The [`base-builder-publish`](https://github.com/base/base/tree/main/crates/builder/publish) crate handles the output side of the pipeline. It is responsible for two output channels: ### Engine API output The sealed block payload is sent to the node's Engine API (`engine_newPayload`), followed by a `engine_forkchoiceUpdated` call to update the canonical chain tip. This is the standard Reth/OP Stack block import path. ### WebSocket streaming output Flashblocks are streamed in real time over a WebSocket connection. Each flashblock is serialized as a JSON object and pushed to connected subscribers. The publish crate: 1. Maintains a set of WebSocket connections (via the `websocket-proxy` infra binary, which handles fan-out). 2. Serializes each flashblock into the `flashblocks_v0` JSON-RPC notification format. 3. Sends the notification to the proxy, which distributes it to all subscribers. 4. At the end of the block, sends a final `flashblocks_v0` notification with `sealed: true`, signaling that the block is complete. ### Flashblock message format Each flashblock notification contains: ```json { "jsonrpc": "2.0", "method": "flashblocks_v0", "params": { "index": 3, "blockNumber": "0x1a2b3c", "parentHash": "0xabc...def", "timestamp": "0x67890", "transactions": ["0x...rlp1", "0x...rlp2"], "receipts": [{ ... }, { ... }], "stateRoot": "0x...", "gasUsed": "0x...", "sealed": false } } ``` When `sealed` is `true`, the message represents the final state of the block. Consumers can treat a `sealed: true` flashblock as equivalent to a full block notification. ## WebSocket proxy: fan-out and backpressure The [`websocket-proxy`](https://github.com/base/base/tree/main/crates/infra/websocket-proxy) binary sits between the builder and external consumers. It exists because the builder should focus on building blocks, not managing thousands of WebSocket connections. The proxy: - Accepts incoming WebSocket connections from clients. - Subscribes to the builder's flashblock stream (a single connection). - Fans out each flashblock notification to all connected clients. - Applies backpressure: if a client cannot keep up, the proxy drops messages for that client rather than blocking the builder. - Handles connection lifecycle (ping/pong, reconnection, graceful shutdown). This separation ensures that a slow or misbehaving consumer cannot affect block building performance. ## Client-side: `base-flashblocks` On the node side, the [`base-flashblocks`](https://github.com/base/base/tree/main/crates/client/flashblocks) crate manages flashblock state within the running node. Its responsibilities: - **Tracking in-progress flashblocks** -- maintains a buffer of flashblocks for the current block interval, updating as new ones arrive from the builder. - **Subscription management** -- the node exposes its own `flashblocks_subscribe` RPC method for local consumers. The `base-flashblocks` crate manages these subscriptions and forwards flashblock notifications. - **State reconciliation** -- when the sealed block arrives via `engine_newPayload`, the crate reconciles the flashblock state with the final block. Any speculative state derived from flashblocks is replaced by the canonical block state. ## State reconciliation Flashblocks introduce a concept of **speculative state**: consumers act on transactions that are included in a flashblock but not yet in a sealed block. In the normal case, the sealed block contains exactly the union of all flashblock transactions, so speculative state matches final state perfectly. However, there are edge cases: ### Reorgs within a block interval If the builder receives a new `forkchoiceUpdated` that changes the parent block during construction (e.g., due to an L1 reorg affecting deposit transactions), the builder: 1. Discards the in-progress block. 2. Sends a `flashblocks_v0` notification with `"reorg": true` to signal that previous flashblocks for this block number are invalid. 3. Starts building a new block from the updated parent. Consumers must handle reorg notifications by discarding any speculative state derived from the invalidated flashblocks. ### Builder restarts If the builder process restarts mid-block, flashblock numbering resets. The `websocket-proxy` detects the upstream disconnection and sends a disconnect notification to subscribers. When the builder reconnects, it starts a fresh block interval. ## Metering: `base-builder-metering` The [`base-builder-metering`](https://github.com/base/base/tree/main/crates/builder/metering) crate collects performance metrics from the build loop: | Metric | Description | |---|---| | `builder_flashblock_build_time_ms` | Time to produce each flashblock | | `builder_flashblock_tx_count` | Number of transactions per flashblock | | `builder_block_total_gas` | Total gas used in the sealed block | | `builder_block_tx_count` | Total transactions in the sealed block | | `builder_block_revenue_wei` | Total priority fees earned by the builder | | `builder_block_build_time_ms` | Wall-clock time for the full 2-second build cycle | | `builder_flashblock_count` | Number of flashblocks produced per block | These metrics are exported via Prometheus and are critical for monitoring builder performance in production. A drop in `flashblock_tx_count` or a spike in `flashblock_build_time_ms` can indicate EVM execution bottlenecks or transaction pool issues. ## Timeline of a single block The following timeline illustrates a typical 2-second block with Flashblocks: ``` Time (ms) Event ───────── ───── 0 forkchoiceUpdated received; builder starts block N 0-10 Deposit transactions executed 10-200 User transactions executed from pool 200 Flashblock 0 emitted (deposits + first batch of user txs) 200-400 More user transactions executed 400 Flashblock 1 emitted 400-600 More user transactions executed 600 Flashblock 2 emitted ... (continues every 200ms) 1800-2000 Final batch of user transactions executed 2000 Flashblock 9 emitted (final interval) 2000 Block sealed; engine_newPayload sent 2000+ forkchoiceUpdated confirms block N as canonical ``` In this example, a user whose transaction was included in Flashblock 0 received confirmation at t=200ms -- a 10x improvement over the 2-second block time. ## Integration with the execution pipeline Flashblocks do not change the execution pipeline described in [Execution Pipeline](/architecture/execution-pipeline/). The EVM execution, state trie updates, and block sealing steps are identical. Flashblocks simply add **observation points** at 200ms intervals, allowing external consumers to see progress before the block is complete. The key invariant is: **the set of transactions in the sealed block is exactly the union of all flashblock transaction sets for that block**. There are no transactions that appear in a flashblock but not in the sealed block (barring the reorg case described above), and no transactions that appear in the sealed block but not in any flashblock. --- # Architecture Overview Source: https://basehub.org/architecture/overview/ Description: How the 8 crate groups in base/base fit together — from Reth integration to Flashblocks production. `base/base` is a Rust workspace that implements the Base L2 node on top of [Reth](https://github.com/paradigmxyz/reth) v1.11.0. It layers Optimism rollup semantics, a Flashblocks-aware block builder, and a [Kona](https://github.com/op-rs/kona)-derived fault proof pipeline onto the Reth execution client. The workspace is organized into **8 top-level crate groups**, each in its own subdirectory under `crates/`. These groups map to the major subsystems of an L2 node: receiving transactions, building blocks, executing the EVM, reaching consensus with L1, generating fault proofs, and operating the infrastructure that ties it all together. ## System diagram At the highest level, the system looks like this: ``` L1 (Ethereum) | ┌───────────────┼───────────────┐ v v v ┌─────────┐ ┌───────────┐ ┌───────────┐ │consensus│ │ proof │ │ builder │ │ (kona) │ │ (kona) │ │(flashblocks│ └────┬────┘ └───────────┘ │ + core) │ │ └─────┬─────┘ v v ┌─────────┐ ┌───────────┐ │ client │◄─────────────────►│ execution │ │(node + │ │ (EVM + │ │ engine) │ │ payload) │ └────┬────┘ └───────────┘ │ v ┌─────────┐ ┌───────────┐ ┌───────────┐ │ shared │ │ alloy │ │ infra │ │(prims, │ │ (types + │ │(binaries +│ │ utils) │ │ codecs) │ │ tooling) │ └─────────┘ └───────────┘ └───────────┘ ``` ## Crate groups ### 1. Client — the node core **Path:** [`crates/client/`](https://github.com/base/base/tree/main/crates/client) The client group contains the node implementation itself. It is the entry point for the `base-reth-node` binary and assembles all the other subsystems into a running process. | Crate | Purpose | |---|---| | `base-client-node` | Node configuration, component wiring, Reth `NodeBuilder` integration | | `base-client-cli` | CLI argument parsing and subcommand definitions | | `base-client-engine` | Engine API handler — receives payloads from the consensus layer and drives execution | | `base-flashblocks` | Flashblocks state management, WebSocket streaming, sub-block interval logic | | `base-metering` | Gas metering extensions and RPC metering endpoints | | `base-txpool-tracing` | Transaction pool event tracing and diagnostics | The client group depends on nearly every other group. It pulls primitives from **shared**, types from **alloy**, EVM logic from **execution**, and consensus derivation from **consensus**. ### 2. Execution — EVM and payload construction **Path:** [`crates/execution/`](https://github.com/base/base/tree/main/crates/execution) This group wraps Reth's EVM execution with Base-specific customizations. It is responsible for: - Configuring the `EvmConfig` with Optimism-specific precompiles and fee logic - Building execution payloads (the block body that the engine seals) - Applying L1-to-L2 deposit transactions that arrive via the derivation pipeline Reth's modular `EvmConfig` trait allows Base to inject its own gas pricing rules (L1 data fee), custom precompiles, and Optimism system transaction handling without forking the core EVM loop. ### 3. Consensus — L1 derivation **Path:** [`crates/consensus/`](https://github.com/base/base/tree/main/crates/consensus) Consensus is split into two sub-groups: **Base-native crates:** | Crate | Purpose | |---|---| | `base-protocol` | Protocol constants, chain config, fork schedule | | `base-consensus-rpc` | RPC interface for consensus queries | **Kona-derived crates** (forked/vendored from the [Kona](https://github.com/op-rs/kona) project): | Crate | Purpose | |---|---| | `kona-node-service` | Top-level consensus node service | | `kona-engine` | Engine driver — sends `engine_forkchoiceUpdated` / `engine_newPayload` calls | | `kona-derive` | L1 derivation pipeline — reads batches from L1, produces L2 payload attributes | | `kona-gossip` | P2P gossip protocol for unsafe block propagation | | `kona-sources` | Data source adapters (L1 RPC, blobs, DA) | | `kona-providers-alloy` | Alloy-based provider implementations for L1/L2 data | | `kona-genesis` | Genesis state and rollup config loading | | `kona-registry` | Chain registry (rollup configs for known chains) | | `kona-hardforks` | Hardfork activation logic | | `kona-disc` | Peer discovery | | `kona-peers` | Peer management and scoring | | `kona-cli` | CLI utilities for consensus binaries | | `kona-macros` | Procedural macros used across kona crates | The derivation pipeline reads L1 blocks, extracts batch data (from calldata or EIP-4844 blobs), and derives the sequence of L2 blocks that the execution layer must process. This is the mechanism by which Base inherits Ethereum's security. ### 4. Builder — block construction and Flashblocks **Path:** [`crates/builder/`](https://github.com/base/base/tree/main/crates/builder) The builder group implements Base's custom block builder, which goes beyond standard Reth payload building by producing **Flashblocks** -- partial block updates streamed every 200 milliseconds. | Crate | Purpose | |---|---| | `base-builder-core` | Core block building loop, transaction ordering, Flashblock interval timer | | `base-builder-publish` | Publishing built blocks/flashblocks to consumers (WebSocket, engine) | | `base-builder-metering` | Builder-specific metrics (build times, transaction counts, revenue) | The builder runs as a separate binary (`builder`) and communicates with the node via the Engine API. See [Flashblocks Pipeline](/architecture/flashblocks-pipeline/) for a detailed walkthrough. ### 5. Proof — fault proof generation **Path:** [`crates/proof/`](https://github.com/base/base/tree/main/crates/proof) The proof group contains the machinery for generating fault proofs that can be verified on L1. These crates are also derived from Kona and target execution inside a fault proof virtual machine (FPVM). | Crate | Purpose | |---|---| | `kona-proof` | Top-level proof orchestration | | `kona-driver` | Drives the derivation + execution pipeline inside the FPVM | | `kona-executor` | EVM executor adapted for the proof environment | | `kona-mpt` | Merkle Patricia Trie operations for state proof verification | | `kona-preimage` | Preimage oracle client — requests data from the host during proof execution | | `kona-std-fpvm` | Standard FPVM runtime (syscall interface, memory management) | | `kona-std-fpvm-proc` | Procedural macros for FPVM entry points | In a fault proof, the entire derivation-then-execution pipeline runs deterministically inside a sandboxed VM. The `kona-driver` crate replays the same logic as the consensus layer's derivation pipeline, but reads data through a preimage oracle rather than from the network. ### 6. Shared — common types and utilities **Path:** [`crates/shared/`](https://github.com/base/base/tree/main/crates/shared) Shared crates provide types, utilities, and abstractions used across multiple other groups. | Crate | Purpose | |---|---| | `base-primitives` | Core types: `BaseTxEnvelope`, `BaseBlock`, chain IDs, fee types | | `base-bundles` | Bundle types for MEV/searcher bundle submission | | `base-jwt` | JWT authentication for Engine API and inter-service communication | | `base-cli-utils` | Common CLI argument types and parsing helpers | | `base-engine-ext` | Engine API extensions (additional methods beyond the standard spec) | | `base-access-lists` | Access list generation and optimization | | `base-reth-rpc-types` | Custom RPC type definitions | | `base-txpool-rpc` | Transaction pool RPC method types | `base-primitives` is the most widely depended-upon crate in the workspace. It defines the canonical transaction, block, and receipt types that every other group imports. ### 7. Alloy — type system and codecs **Path:** [`crates/alloy/`](https://github.com/base/base/tree/main/crates/alloy) The alloy group provides Ethereum/Optimism type definitions and encoding/decoding logic built on the [Alloy](https://github.com/alloy-rs/alloy) library ecosystem. These crates define the wire format for transactions, receipts, and other protocol objects, ensuring compatibility with the broader Ethereum tooling ecosystem. ### 8. Infra — binaries and operational tooling **Path:** [`crates/infra/`](https://github.com/base/base/tree/main/crates/infra) The infra group contains the supporting binaries and tooling that run alongside the core node. | Crate/Binary | Purpose | |---|---| | `based` | Sequencer orchestrator daemon | | `basectl-cli` | Operator CLI tool for node management and diagnostics | | `ingress-rpc-lib` | RPC ingress proxy — routes and load-balances incoming RPC requests | | `websocket-proxy` | WebSocket proxy for Flashblocks streaming | | `mempool-rebroadcaster` | Rebroadcasts mempool transactions to peers | | `audit-archiver-lib` | Archives audit logs for compliance and debugging | | `system-tests` | End-to-end integration test harness | ## Reth integration Base does not fork Reth. Instead, it uses Reth as a library dependency and extends it through Reth's plugin architecture: 1. **`NodeBuilder`** — the client group uses Reth's `NodeBuilder` to assemble a node with custom components (EVM config, transaction pool, payload builder). 2. **`EvmConfig`** — the execution group provides an Optimism-aware EVM configuration that plugs into Reth's execution pipeline. 3. **`PayloadBuilder`** — the builder group implements a custom payload builder that produces Flashblocks. 4. **`EngineApi`** — the client engine crate extends the standard Engine API with additional methods for Flashblocks and metering. This library-based integration means Base automatically picks up upstream Reth improvements (perf optimizations, new EVM opcodes, database improvements) by updating the Reth dependency version. ## Optimism component usage Base is an OP Stack chain, and the codebase relies on several Optimism-specific components: - **`reth-optimism-*` crates** — Reth ships first-party Optimism support. Base uses these for deposit transaction handling, L1 fee calculation, and the Optimism-specific Engine API extensions (`op-engine-api`). - **Kona** — the consensus and proof groups are built on Kona, the Rust implementation of the OP Stack's derivation pipeline and fault proof program. Base vendors these crates to apply Base-specific patches (e.g., Flashblocks-aware derivation). - **Alloy Optimism types** — the alloy group extends Alloy's Optimism type definitions with Base-specific transaction types and receipt fields. ## Build toolchain The workspace uses: - **Rust edition 2024** with a minimum supported Rust version of **1.88** - **MIT license** for all crates - **Just** as the task runner (see `justfile` at the repo root) - **Docker** for containerized builds and deployments --- # audit-archiver Source: https://basehub.org/binaries/audit-archiver/ Description: Kafka-to-S3 audit log archival service with configurable worker pools. import { LinkCard } from '@astrojs/starlight/components'; `audit-archiver` consumes audit log messages from the Kafka topics that `ingress-rpc` writes to and archives them to S3-compatible storage for long-term retention, debugging, and compliance. ## Package - **Crate name:** `audit-archiver` - **Source:** [`bin/audit-archiver`](https://github.com/base/base/tree/main/bin/audit-archiver) - **Library:** [`crates/infra/audit`](https://github.com/base/base/tree/main/crates/infra/audit) (`audit-archiver-lib`) ## Architecture The archiver runs a configurable pool of workers that consume messages from Kafka topics and write them in batches to S3: ``` Kafka topics → audit-archiver (worker pool) → S3 bucket ``` The service supports a `noop-archive` mode for testing where messages are consumed and logged but not written to S3. ## Features | Feature | Description | |---------|-------------| | **Worker pool** | Configurable pool of up to 80 concurrent workers | | **S3 archival** | Writes audit logs to S3-compatible object storage | | **Noop mode** | `noop-archive` mode for testing without S3 writes | | **Metrics** | Exposes Prometheus metrics on port 9002 | | **Batch processing** | Groups messages into batches for efficient writes | ## Ports | Port | Protocol | Purpose | |------|----------|---------| | 9002 | HTTP | Prometheus metrics | ## Key Dependencies - `audit-archiver-lib` — Core archival logic - `rdkafka` — Kafka consumer - `aws-sdk-s3` — S3 client - `tokio` — Async runtime ## Build ```bash cargo build --bin audit-archiver --release ``` ## Usage ```bash ./target/release/audit-archiver [OPTIONS] ``` ## Source --- # base-reth-node Source: https://basehub.org/binaries/base-reth-node/ Description: The main Base Reth Node binary — a Reth-based Ethereum execution client for the Base L2 network. import { LinkCard } from '@astrojs/starlight/components'; `base-reth-node` runs the Base L2 execution client. It extends the standard Reth OP node with five extensions covering Flashblocks streaming, transaction pool RPC, resource metering, and proofs history retention. ## Package - **Crate name:** `base-reth-node` - **Source:** [`bin/node`](https://github.com/base/base/tree/main/bin/node) - **Dockerfile:** `etc/docker/Dockerfile.client` ## Extensions The node binary installs five extensions on top of the standard Reth OP node: | Extension | Crate | Purpose | |-----------|-------|---------| | `TxPoolRpcExtension` | `base-txpool-rpc` | Exposes custom transaction pool RPC methods | | `TxPoolExtension` | `base-txpool-tracing` | Adds transaction pool tracing and diagnostics | | `MeteringExtension` | `base-metering` | Resource metering RPC for gas accounting | | `FlashblocksExtension` | `base-flashblocks` | Flashblocks streaming provider over WebSocket | | `ProofsHistoryExtension` | `base-proofs-history` | Retains trie proofs for the fault proof window | These extensions are registered via Reth's `NodeComponents` system. Each one hooks into the node lifecycle to provide additional RPC methods or background services. ## Key Dependencies - `reth-optimism-node` — Base Reth node builder - `reth-optimism-cli` — CLI framework with jemalloc and OTel - `base-flashblocks` — Flashblocks RPC provider - `base-metering` — Resource metering RPC - `base-txpool-rpc` — Transaction pool RPC extensions - `base-txpool-tracing` — Transaction pool tracing - `base-proofs-history` — Proofs history extension - `base-cli-utils` — CLI utilities (logging, metrics) ## Build ```bash # Build just this binary just build-node # Or using cargo directly cargo build --bin base-reth-node # Release build cargo build --release --bin base-reth-node # Max performance build (PGO + LTO) just build-maxperf ``` ## Usage ```bash ./target/release/base-reth-node node \ --chain base \ --datadir /data/base \ --http \ --http.api eth,net,web3,debug,txpool \ --ws \ --ws.api eth,net,web3 ``` View all available options: ```bash ./target/release/base-reth-node --help ``` ## Docker ```bash # Build the image docker build -t base-reth-node -f etc/docker/Dockerfile.client . # Run docker run -it --rm \ -v /data/base:/data \ -p 8545:8545 \ -p 8546:8546 \ base-reth-node node --chain base --datadir /data ``` ## Source --- # basectl Source: https://basehub.org/binaries/basectl/ Description: TUI management utility for configuring and inspecting Base nodes across different network targets. import { LinkCard } from '@astrojs/starlight/components'; `basectl` is the operator TUI for configuring and inspecting Base nodes across multiple network targets. The interface is built with [`ratatui`](https://github.com/ratatui/ratatui). ## Package - **Crate name:** `basectl` - **Source:** [`bin/basectl`](https://github.com/base/base/tree/main/bin/basectl) - **Library:** [`crates/infra/basectl`](https://github.com/base/base/tree/main/crates/infra/basectl) (`basectl-cli`) ## Architecture `basectl` is split into two crates: - **`basectl`** (binary) — The CLI entry point that parses arguments and launches the TUI - **`basectl-cli`** (library) — The core logic for configuration management, subcommands, and the TUI renderer The TUI is built with [`ratatui`](https://github.com/ratatui/ratatui), providing an interactive terminal interface for node management. ## Subcommands | Subcommand | Purpose | |------------|---------| | `config` | Generate or inspect node configuration for a target network | | `flashblocks` | Inspect and manage flashblocks streaming state | | `da` | Data availability layer inspection and diagnostics | | `command-center` | Interactive TUI dashboard for monitoring and managing the node | ## Configuration Targets | Config | Network | |--------|---------| | `mainnet` | Base Mainnet | | `sepolia` | Base Sepolia Testnet | | `devnet` | Local Development Network | | `` | Custom configuration file path | ## Key Dependencies - `basectl-cli` — Configuration logic library - `ratatui` — TUI framework - `clap` — CLI argument parsing - `anyhow` — Error handling - `tokio` — Async runtime ## Usage ```bash # Via cargo cargo run -p basectl --release -- -c # Via Just (preferred) just basectl mainnet just basectl sepolia just basectl devnet ``` ## Source --- # based Source: https://basehub.org/binaries/based/ Description: Block-building sidecar service with health checks and StatsD metrics. import { LinkCard } from '@astrojs/starlight/components'; `based` runs as a sidecar to the block builder, exposing HTTP health check endpoints and forwarding metrics over StatsD to Datadog or compatible backends. ## Package - **Crate name:** `based-bin` - **Binary name:** `based` - **Source:** [`bin/based`](https://github.com/base/base/tree/main/bin/based) - **Library:** [`crates/infra/based`](https://github.com/base/base/tree/main/crates/infra/based) (`based`) ## Architecture `based` runs as a sidecar alongside the block builder. It: 1. Exposes HTTP health check endpoints for load balancer integration 2. Reports block-building metrics via StatsD to Datadog or compatible backends 3. Reads configuration from environment variables for deployment flexibility ## Key Dependencies - `based` — Core daemon library - `clap` — CLI argument parsing - `tracing` / `tracing-subscriber` — Structured logging - `tokio` — Async runtime - `cadence` — StatsD metrics client (for Datadog integration) ## Environment Variables | Variable | Purpose | |----------|---------| | `STATSD_HOST` | StatsD server hostname | | `STATSD_PORT` | StatsD server port | | `STATSD_PREFIX` | Metric name prefix | | `CODEFLOW_*` | Codeflow environment integration variables | ## Build ```bash cargo build --bin based --release ``` ## Usage ```bash ./target/release/based [OPTIONS] ``` ## Source --- # builder Source: https://basehub.org/binaries/builder/ Description: The Base block builder binary for flashblock production and block building. import { LinkCard } from '@astrojs/starlight/components'; `base-builder` produces flashblocks every 200 milliseconds and assembles the sealed canonical blocks for Base. It orchestrates the build pipeline through `FlashblocksServiceBuilder`. ## Package - **Crate name:** `base-builder-bin` - **Binary name:** `base-builder` - **Source:** [`bin/builder`](https://github.com/base/base/tree/main/bin/builder) - **Dockerfile:** `etc/docker/Dockerfile.builder` ## Architecture The builder binary bootstraps using `FlashblocksServiceBuilder`, which wires together: 1. **Block building** — Assembles transactions from the pool into execution payloads 2. **Flashblock production** — Produces 200ms sub-block preconfirmations streamed to subscribers 3. **Metering** — Tracks gas usage and resource consumption via `MeteringStoreExtension` 4. **Transaction pool RPC** — Exposes custom pool methods via `TxPoolRpcExtension` The builder uses jemalloc as its global allocator for improved memory allocation performance. ## Key Extensions | Extension | Purpose | |-----------|---------| | `FlashblocksServiceBuilder` | Orchestrates the full flashblocks pipeline | | `MeteringStoreExtension` | Resource metering data store | | `TxPoolRpcExtension` | Transaction pool RPC methods | ## Key Dependencies - `base-cli-utils` — CLI utilities (logging, metrics) - `base-builder-core` — Core block building logic - `base-builder-metering` — Resource metering - `base-builder-publish` — Block publishing and streaming - `reth-optimism-node` — Reth node builder - `jemalloc` — Memory allocator ## Build ```bash # Build the builder binary cargo build --bin base-builder --release ``` ## Docker ```bash # Build the image docker build -t base-builder -f etc/docker/Dockerfile.builder . # Run docker run -it --rm base-builder [OPTIONS] ``` ## Usage ```bash ./target/release/base-builder [OPTIONS] ``` ## Source --- # consensus Source: https://basehub.org/binaries/consensus/ Description: The Base consensus node binary implementing the OP Stack consensus protocol via Kona. import { LinkCard } from '@astrojs/starlight/components'; `base-consensus` runs the Base consensus layer, implementing the OP Stack consensus protocol on top of the [Kona](https://github.com/op-rs/kona) derivation framework. ## Package - **Crate name:** `base-consensus` - **Source:** [`bin/consensus`](https://github.com/base/base/tree/main/bin/consensus) ## Architecture The consensus binary: 1. **L1 derivation** — Connects to L1 Ethereum to read rollup data and derives L2 blocks from L1 batches using the derivation pipeline 2. **P2P networking** — Manages peer-to-peer networking for block gossip and state sync 3. **Engine API** — Communicates with the execution layer (base-reth-node) via the Engine API to deliver derived payloads 4. **Kona integration** — Uses `kona-node-service` for the core consensus loop and `kona-genesis` for chain configuration ## Key Dependencies - `base-cli-utils` — CLI utilities (logging, metrics) - `base-client-cli` — Client CLI extensions - `kona-genesis` — Genesis configuration - `kona-cli` — Consensus CLI framework - `kona-node-service` — Node service orchestration ## Build ```bash cargo build --bin base-consensus --release ``` ## Usage ```bash ./target/release/base-consensus [OPTIONS] ``` The consensus node must be configured with: - An L1 Ethereum RPC endpoint for reading rollup data - An Engine API endpoint for communicating with the execution layer - A P2P configuration for block gossip ## Source --- # ingress-rpc Source: https://basehub.org/binaries/ingress-rpc/ Description: JSON-RPC ingress proxy with Kafka audit trail for transaction and bundle submission. import { LinkCard } from '@astrojs/starlight/components'; `ingress-rpc` fronts the node, accepting JSON-RPC requests and routing each one to the right backend. Every request is mirrored to Kafka for audit and replay. ## Package - **Crate name:** `ingress-rpc` - **Source:** [`bin/ingress-rpc`](https://github.com/base/base/tree/main/bin/ingress-rpc) - **Library:** [`crates/infra/ingress-rpc`](https://github.com/base/base/tree/main/crates/infra/ingress-rpc) (`ingress-rpc-lib`) ## Architecture The ingress RPC proxy handles three categories of traffic: 1. **Transaction submission** — `eth_sendRawTransaction` calls forwarded to the transaction pool 2. **Bundle submission** — `eth_sendBundle` and related methods forwarded to the builder 3. **Mempool/simulation/raw TX forwarding** — Read and simulation requests forwarded to the appropriate backend All requests are logged to Kafka for audit and replay purposes. The proxy uses `jsonrpsee` for its JSON-RPC server implementation. ## Request Flow ``` Client → ingress-rpc → Kafka (audit log) → Backend (node/builder/mempool) → Client (response) ``` ## Key Dependencies - `ingress-rpc-lib` — Core proxy logic - `clap` — CLI argument parsing - `tokio` — Async runtime - `rdkafka` — Kafka client for audit logging - `jsonrpsee` — JSON-RPC server - `dotenvy` — Environment variable loading ## Build ```bash cargo build --bin ingress-rpc --release ``` ## Usage ```bash ./target/release/ingress-rpc [OPTIONS] ``` ## Source --- # mempool-rebroadcaster Source: https://basehub.org/binaries/mempool-rebroadcaster/ Description: Bidirectional Geth-Reth mempool transaction rebroadcasting service. import { LinkCard } from '@astrojs/starlight/components'; `mempool-rebroadcaster` bridges the Geth and Reth transaction pools, forwarding pending transactions in both directions so the two clients stay in sync. ## Package - **Crate name:** `mempool-rebroadcaster-bin` - **Binary name:** `mempool-rebroadcaster` - **Source:** [`bin/mempool-rebroadcaster`](https://github.com/base/base/tree/main/bin/mempool-rebroadcaster) - **Library:** [`crates/infra/mempool-rebroadcaster`](https://github.com/base/base/tree/main/crates/infra/mempool-rebroadcaster) ## Architecture The rebroadcaster connects to both a Geth node and a Reth node, monitoring each transaction pool and forwarding new transactions to the other: ``` Geth txpool ←→ mempool-rebroadcaster ←→ Reth txpool ``` This ensures that during the migration from Geth to Reth, or in hybrid deployments where both clients are running, transactions submitted to either node are visible to both. The service periodically polls both pools and rebroadcasts any transactions that are missing from the other. ## Key Dependencies - `mempool-rebroadcaster` — Core rebroadcasting logic - `clap` — CLI argument parsing - `dotenvy` — Environment variable loading - `tracing` / `tracing-subscriber` — Structured logging - `tokio` — Async runtime ## Build ```bash cargo build --bin mempool-rebroadcaster --release ``` ## Usage ```bash ./target/release/mempool-rebroadcaster [OPTIONS] ``` ## Source --- # websocket-proxy Source: https://basehub.org/binaries/websocket-proxy/ Description: Fan-out WebSocket proxy with Brotli compression, API key authentication, and rate limiting. import { LinkCard } from '@astrojs/starlight/components'; `websocket-proxy` fans out flashblock streams from one or more upstream builders to connected clients. It handles Brotli compression, API key authentication, and per-IP rate limiting. ## Package - **Crate name:** `websocket-proxy-bin` - **Binary name:** `websocket-proxy` - **Source:** [`bin/websocket-proxy`](https://github.com/base/base/tree/main/bin/websocket-proxy) - **Library:** [`crates/infra/websocket-proxy`](https://github.com/base/base/tree/main/crates/infra/websocket-proxy) - **Dockerfile:** `etc/docker/Dockerfile.websocket-proxy` ## Architecture The proxy operates as a fan-out service: ``` Upstream 1 ─┐ Upstream 2 ─┤→ websocket-proxy ─→ Client A Upstream N ─┘ ─→ Client B ─→ Client N ``` It connects to one or more upstream WebSocket URIs (e.g., builder nodes producing flashblocks) and fans out the messages to all connected downstream clients. This enables horizontal scaling of flashblock delivery. ## Features | Feature | Description | |---------|-------------| | **Fan-out** | Multiplexes messages from upstream sources to all connected clients | | **Brotli compression** | Compresses WebSocket frames for bandwidth-efficient delivery | | **API key auth** | Authenticates clients via API keys before allowing connections | | **Per-IP rate limiting** | Prevents abuse by limiting connection rates per source IP | | **Metrics** | Exposes Prometheus metrics on port 9000 | | **Multiple upstreams** | Connects to multiple upstream URIs for redundancy | ## Ports | Port | Protocol | Purpose | |------|----------|---------| | 8545 | WebSocket | Client-facing flashblock stream | | 9000 | HTTP | Prometheus metrics | ## Key Dependencies - `websocket-proxy` — Core proxy logic - `brotli` — Brotli compression - `futures` — Async stream utilities - `hostname` — Hostname resolution - `tokio` — Async runtime ## Docker ```bash # Build the image docker build -t websocket-proxy -f etc/docker/Dockerfile.websocket-proxy . # Run docker run -it --rm \ -p 8545:8545 \ -p 9000:9000 \ websocket-proxy [OPTIONS] ``` ## Build ```bash cargo build --bin websocket-proxy --release ``` ## Usage ```bash ./target/release/websocket-proxy [OPTIONS] ``` ## Source --- # Contributing Source: https://basehub.org/contributing/ Description: Open issues, pick up help-wanted work, and submit pull requests against the base/base repository. ## Ways to Contribute 1. **Opening issues:** Report bugs or request features in the [issue tracker](https://github.com/base/base/issues). 2. **Adding context:** Provide screenshots, logs, and code snippets to existing issues. 3. **Resolving issues:** Open pull requests that fix issues. ## What We Accept from External Contributors - **Small, focused changes:** One-liner fixes, typo corrections, small bug fixes - **Issues labeled `help wanted`:** Look for unassigned issues [with this label](https://github.com/base/base/issues?q=state%3Aopen%20label%3AM-help-wanted) - **Bug reports:** Well-documented bug reports with reproduction steps ## Before Starting Work If you're considering a larger contribution (new features, refactors, architectural changes), **open an issue first** to discuss your proposal. This ensures alignment with project goals and prevents wasted effort. Only work on issues that are assigned to you. Comment on an issue to request assignment. ## Making Changes 1. Fork the repository and create your branch from `main` 2. Follow the existing code style 3. Add or update tests as appropriate 4. Run all checks locally: ```bash just ci ``` This runs: formatting checks, clippy, tests, dependency auditing, link checking, and no-std verification. ## Development Commands ```bash # Fix formatting and clippy issues just fix # Run checks (format, udeps, clippy, tests, deny) just check # Run tests just test # Build contracts (needed before tests) just build-contracts ``` See the [Development Workflow](/getting-started/development/) guide for more details. ## Opening a Pull Request 1. Link to the related issue 2. Describe what your changes do and why 3. Keep your PR up to date with the `main` branch 4. Respond to feedback and requests for changes ## Submitting a Bug Report Include: - The Base version you are on (and that it is up to date) - Relevant logs and error messages - Concrete steps to reproduce the bug - Any relevant configuration ## Getting Help - Open a discussion in the [repository](https://github.com/base/base) - Comment on the relevant issue - Check existing [documentation](https://docs.base.org/) and issues first --- # alloy/consensus Source: https://basehub.org/crates/alloy/consensus/ Description: Base alloy consensus types — transactions, receipts with Base-specific fields. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-consensus` crate defines Base consensus types, including custom transaction and receipt types. It extends the standard Alloy consensus types for the OP Stack L2 environment. ## Key Dependencies - `alloy-consensus` — Upstream consensus types - `op-alloy-consensus` — OP Stack consensus types ## Source --- # alloy/evm Source: https://basehub.org/crates/alloy/evm/ Description: EVM implementation with Base hardfork awareness. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-evm` crate implements the EVM with Base hardfork awareness. It builds on `op-revm` to customize execution for the Base L2 chain. ## Key Dependencies - `op-revm` — OP Stack REVM extensions - `revm` — Rust EVM implementation - `base-alloy-hardforks` — Base hardfork definitions ## Source --- # alloy/hardforks Source: https://basehub.org/crates/alloy/hardforks/ Description: Named bindings for Base-specific hardforks. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-hardforks` crate defines named bindings for Base hardforks. Other crates use these bindings to gate hardfork-aware behavior. ## Source --- # alloy/network Source: https://basehub.org/crates/alloy/network/ Description: Base blockchain RPC behavior abstraction at the network layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-network` crate defines how the Base chain implements Alloy's network traits. It abstracts RPC behavior at the network layer. ## Source --- # alloy Source: https://basehub.org/crates/alloy/overview/ Description: Alloy type extensions for Base — consensus types, EVM customizations, RPC types, and network definitions. The `alloy` crate group extends [Alloy](https://github.com/alloy-rs/alloy), the standard Rust toolkit for Ethereum types and RPC, with Base-specific consensus types, RPC types, EVM behavior, and hardfork definitions. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [consensus](/crates/alloy/consensus/) | `base-alloy-consensus` | Base-specific consensus types | | [evm](/crates/alloy/evm/) | `base-alloy-evm` | EVM customizations for Base | | [hardforks](/crates/alloy/hardforks/) | `base-alloy-hardforks` | Base hardfork definitions | | [network](/crates/alloy/network/) | `base-alloy-network` | Network type definitions | | [provider](/crates/alloy/provider/) | `base-alloy-provider` | Alloy provider extensions | | [rpc-jsonrpsee](/crates/alloy/rpc-jsonrpsee/) | `base-alloy-rpc-jsonrpsee` | JSON-RPC server traits (jsonrpsee) | | [rpc-types-engine](/crates/alloy/rpc-types-engine/) | `base-alloy-rpc-types-engine` | Engine API RPC types | | [rpc-types](/crates/alloy/rpc-types/) | `base-alloy-rpc-types` | General RPC type extensions | ## Role in the Architecture The alloy crates sit at the foundation of the dependency graph. They define the types that flow through every other layer — from how blocks and transactions are represented in consensus, to the RPC types returned to users, to the EVM execution context. These crates extend the upstream Alloy types with Base-specific fields and behaviors needed for the OP Stack L2 environment. ## Source [`crates/alloy/`](https://github.com/base/base/tree/main/crates/alloy) --- # alloy/provider Source: https://basehub.org/crates/alloy/provider/ Description: Interface with a Base blockchain via the Engine API provider. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-provider` crate exposes an Alloy provider for the Base chain, including Engine API extensions used by the consensus layer. ## Source --- # alloy/rpc-jsonrpsee Source: https://basehub.org/crates/alloy/rpc-jsonrpsee/ Description: Base RPC client using the jsonrpsee framework. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-rpc-jsonrpsee` crate implements the Base RPC client on top of the [jsonrpsee](https://github.com/paritytech/jsonrpsee) framework. ## Source --- # alloy/rpc-types Source: https://basehub.org/crates/alloy/rpc-types/ Description: Base RPC types for blocks and transactions. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-rpc-types` crate defines Base-specific RPC types for blocks and transactions. It extends the standard Ethereum JSON-RPC types. ## Source --- # alloy/rpc-types-engine Source: https://basehub.org/crates/alloy/rpc-types-engine/ Description: Base RPC types for the engine namespace — SSZ, snappy, and sha2 hashing. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-alloy-rpc-types-engine` crate defines RPC types for the `engine` namespace, with SSZ serialization, snappy compression, and sha2 hashing support. ## Source --- # builder/core Source: https://basehub.org/crates/builder/core/ Description: Core block builder for the OP Stack — the main builder logic for sequencing and flashblock production. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-builder-core` crate drives block building for the OP Stack. It handles sequencing, flashblock production at ~200ms intervals, and canonical block assembly. This is the largest crate in the builder group, with dependencies on reth, alloy, revm, and the shared primitives. It integrates transaction bundling, gas metering, caching (via moka), and secp256k1 signing. ## Key Dependencies - `base-bundles` — Transaction bundle types - `base-client-node` — Node harness - `base-primitives` — Core types - `base-access-lists` — FAL implementation - `reth-*` / `reth-optimism-*` — Reth execution crates - `alloy-*` / `op-alloy-*` — Alloy types - `revm` / `op-revm` — EVM execution ## Source --- # builder/metering Source: https://basehub.org/crates/builder/metering/ Description: Resource metering backend for the OP Stack block builder. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-builder-metering` crate is the resource metering backend for the block builder. It tracks gas usage and resource consumption during block construction. ## Source --- # builder Source: https://basehub.org/crates/builder/overview/ Description: Block building, flashblock production, metering, and block publishing for Base. The `builder` crate group produces blocks and flashblocks. It assembles flashblocks at 200ms intervals and publishes them to streaming clients. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [core](/crates/builder/core/) | `base-builder-core` | Core block building logic and flashblock production | | [metering](/crates/builder/metering/) | `base-builder-metering` | Resource metering for block building | | [publish](/crates/builder/publish/) | `base-builder-publish` | Block/flashblock publishing and distribution | ## Role in the Architecture The builder sits between the execution layer and the consensus layer. It: 1. Receives transactions from the transaction pool 2. Builds execution payloads using the EVM 3. Produces flashblocks at ~200ms intervals during the 2-second block time 4. Publishes flashblocks via WebSocket for real-time streaming 5. Finalizes the canonical block at the end of each slot The `base-builder-core` crate contains the main building logic, `base-builder-metering` handles gas and resource accounting, and `base-builder-publish` handles distribution of produced blocks. ## Source [`crates/builder/`](https://github.com/base/base/tree/main/crates/builder) --- # builder/publish Source: https://basehub.org/crates/builder/publish/ Description: WebSocket broadcast publisher for flashblock distribution. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-builder-publish` crate is the WebSocket broadcast publisher for the OP Stack block builder. It streams produced flashblocks and canonical blocks to connected clients. ## Source --- # client/cli Source: https://basehub.org/crates/client/cli/ Description: CLI argument types for Base node consensus clients. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-client-cli` crate defines the CLI argument types for Base node consensus clients. It integrates Kona and Alloy for chain configuration and argument parsing. ## Source --- # client/engine Source: https://basehub.org/crates/client/engine/ Description: Engine validator for the Base Node — handles Engine API, trie computation, and flashblocks. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-client-engine` crate implements the engine validator for the Base Node. It handles Engine API communication, trie root computation, and flashblocks integration between the execution and consensus layers. ## Source --- # client/flashblocks Source: https://basehub.org/crates/client/flashblocks/ Description: Flashblocks state management — WebSocket streaming, pending state, EVM re-execution. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-flashblocks` crate manages the core flashblocks state. It handles: - WebSocket streaming of flashblock updates from the builder - Pending state cache for preconfirmed transactions - EVM re-execution for state queries against the pending block - The `pending` tag support for standard Ethereum JSON-RPC methods This is the crate that powers the [Flashblocks RPC](/specifications/flashblocks/). ## Source --- # client/flashblocks-node Source: https://basehub.org/crates/client/flashblocks-node/ Description: Flashblocks node extension — integrates flashblocks into the node lifecycle. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-flashblocks-node` crate wires flashblocks into the Reth node lifecycle. It registers the flashblocks RPC, WebSocket streaming, and pending state management. ## Source --- # client/metering Source: https://basehub.org/crates/client/metering/ Description: Metering RPC for the Base node — resource and gas metering per block. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-metering` crate exposes metering RPC endpoints for the Base node. It tracks gas usage and resource consumption per block. ## Source --- # client Source: https://basehub.org/crates/client/overview/ Description: Node client — CLI, engine, flashblocks integration, metering, proofs, and transaction pool tracing. The `client` crate group assembles the full Base Reth Node. It supplies the CLI, Engine API integration, flashblocks support, metering RPC, proof extensions, and transaction pool tracing. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [cli](/crates/client/cli/) | `base-client-cli` | CLI argument parsing and node configuration | | [engine](/crates/client/engine/) | `base-client-engine` | Engine API client for consensus-execution communication | | [flashblocks-node](/crates/client/flashblocks-node/) | `base-flashblocks-node` | Flashblocks-enabled node assembly | | [flashblocks](/crates/client/flashblocks/) | `base-flashblocks` | Flashblocks RPC provider and pending state cache | | [metering](/crates/client/metering/) | `base-metering` | Metering RPC endpoints for resource tracking | | [proofs](/crates/client/proofs/) | `base-proofs-extension` | Proof generation extensions | | [txpool-tracing](/crates/client/txpool-tracing/) | `base-txpool-tracing` | Transaction pool tracing and diagnostics | ## Role in the Architecture The client crate group is the primary interface for node operators. It: 1. Parses CLI arguments and configures the node (`cli`) 2. Manages the Engine API connection between execution and consensus (`engine`) 3. Assembles the flashblocks-enabled node with all components (`flashblocks-node`) 4. Provides the Flashblocks RPC for querying preconfirmed state (`flashblocks`) 5. Exposes metering endpoints for gas and resource tracking (`metering`) 6. Supports proof generation for the fault proof system (`proofs`) 7. Adds tracing to the transaction pool for debugging (`txpool-tracing`) The `base-reth-node` binary (in `bin/node`) depends primarily on this crate group. ## Source [`crates/client/`](https://github.com/base/base/tree/main/crates/client) --- # client/proofs Source: https://basehub.org/crates/client/proofs/ Description: Proofs extension for the Base node — fault proof data via Execution Extensions. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-proofs-extension` crate is the proofs extension for the Base node. It uses Reth's Execution Extensions (ExEx) framework to generate and serve fault proof data. ## Source --- # client/txpool-tracing Source: https://basehub.org/crates/client/txpool-tracing/ Description: Transaction tracing extensions — LRU caching, metrics, and streaming. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-txpool-tracing` crate adds transaction tracing extensions to the Base node. It supplies LRU caching, metrics collection, and streaming support for transaction pool diagnostics. ## Source --- # consensus/cli Source: https://basehub.org/crates/consensus/cli/ Description: Shared CLI utilities for Kona crates — tracing, metrics, and clap argument parsing. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-cli` crate provides shared CLI utilities for Kona consensus crates, including tracing, metrics, and clap argument parsing. ## Source --- # consensus/derive Source: https://basehub.org/crates/consensus/derive/ Description: A `no_std` derivation pipeline implementation for the OP Stack. Derives L2 blocks from L1 data. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-derive` crate implements the OP Stack derivation pipeline. It derives L2 blocks from L1 data and runs in `no_std` environments. ## Source --- # consensus/disc Source: https://basehub.org/crates/consensus/disc/ Description: Discovery service for the OP Stack using discv5 and libp2p. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-disc` crate runs the peer discovery service for the OP Stack consensus layer. It uses discv5 and libp2p to find peers on the network. ## Source --- # consensus/engine Source: https://basehub.org/crates/consensus/engine/ Description: OP Stack engine client implementation — makes Engine API calls to the execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-engine` crate implements the OP Stack engine client. It makes Engine API calls from the consensus layer to the execution layer. ## Source --- # consensus/genesis Source: https://basehub.org/crates/consensus/genesis/ Description: Optimism genesis types including rollup config, system config, and hardfork definitions. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-genesis` crate defines Optimism genesis types, including the rollup config, system config, and hardfork definitions. ## Source --- # consensus/gossip Source: https://basehub.org/crates/consensus/gossip/ Description: Gossip protocol implementation for the OP Stack using libp2p gossipsub. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-gossip` crate implements the OP Stack gossip protocol on top of libp2p gossipsub. ## Source --- # consensus/hardforks Source: https://basehub.org/crates/consensus/hardforks/ Description: Consensus hardfork type definitions for the OP Stack. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-hardforks` crate defines the consensus hardfork types for the OP Stack. ## Source --- # consensus/macros Source: https://basehub.org/crates/consensus/macros/ Description: Utility procedural macros for kona crates. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-macros` crate supplies utility procedural macros used across the Kona consensus crates. ## Source --- # consensus Source: https://basehub.org/crates/consensus/overview/ Description: OP Stack consensus implementation — derivation pipeline, gossip networking, P2P discovery, and sequencing. The `consensus` crate group implements the OP Stack consensus protocol for Base. The crates derive from the [Kona](https://github.com/op-rs/kona) project and handle L1 derivation, P2P networking, gossip, and block sequencing. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [cli](/crates/consensus/cli/) | `kona-cli` | Consensus node CLI | | [derive](/crates/consensus/derive/) | `kona-derive` | L1 derivation pipeline | | [disc](/crates/consensus/disc/) | `kona-disc` | Peer discovery | | [engine](/crates/consensus/engine/) | `kona-engine` | Consensus engine driver | | [genesis](/crates/consensus/genesis/) | `kona-genesis` | Genesis state and chain configuration | | [gossip](/crates/consensus/gossip/) | `kona-gossip` | Gossip protocol implementation | | [hardforks](/crates/consensus/hardforks/) | `kona-hardforks` | OP Stack hardfork definitions | | [macros](/crates/consensus/macros/) | `kona-macros` | Procedural macros for consensus code | | [peers](/crates/consensus/peers/) | `kona-peers` | Peer management | | [protocol](/crates/consensus/protocol/) | `base-protocol` | Base-specific protocol extensions | | [providers-alloy](/crates/consensus/providers-alloy/) | `kona-providers-alloy` | Alloy-based data providers for L1/L2 | | [registry](/crates/consensus/registry/) | `kona-registry` | Chain and rollup configuration registry | | [rpc](/crates/consensus/rpc/) | `base-consensus-rpc` | Consensus RPC endpoints | | [service](/crates/consensus/service/) | `kona-node-service` | Consensus node service orchestration | | [sources](/crates/consensus/sources/) | `kona-sources` | Data source abstractions for derivation | ## Role in the Architecture The consensus layer runs independently from the execution layer, communicating via the Engine API. It: 1. Connects to L1 Ethereum to read rollup data (`sources`, `providers-alloy`) 2. Derives L2 blocks from L1 data using the derivation pipeline (`derive`) 3. Manages P2P networking for block gossip (`gossip`, `disc`, `peers`) 4. Drives the consensus engine that feeds payloads to the execution layer (`engine`) 5. Handles chain configuration and hardfork activation (`genesis`, `hardforks`, `registry`) The `base-consensus` binary (in `bin/consensus`) runs this layer. ## Source [`crates/consensus/`](https://github.com/base/base/tree/main/crates/consensus) --- # consensus/peers Source: https://basehub.org/crates/consensus/peers/ Description: Network peers library for the OP Stack — peer management, discv5, and libp2p integration. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-peers` crate manages network peers for the OP Stack consensus layer. It integrates discv5 and libp2p for peer tracking and connection lifecycle. ## Source --- # consensus/protocol Source: https://basehub.org/crates/consensus/protocol/ Description: Base-specific protocol types — batches, channels, frames, and compression (brotli, zlib). import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-protocol` crate defines Base-specific protocol types: batches, channels, frames, and compression via brotli and zlib. ## Source --- # consensus/providers-alloy Source: https://basehub.org/crates/consensus/providers-alloy/ Description: Alloy-backed data providers for L1/L2 data including beacon, execution, and blob fetching with c-kzg. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-providers-alloy` crate supplies Alloy-backed data providers for L1 and L2 data, covering beacon, execution, and blob fetching with c-kzg. ## Source --- # consensus/registry Source: https://basehub.org/crates/consensus/registry/ Description: Registry of superchain configurations — chain configs loaded from TOML. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-registry` crate holds the registry of superchain configurations, loaded from TOML. ## Source --- # consensus/rpc Source: https://basehub.org/crates/consensus/rpc/ Description: RPC types and client for Base consensus using jsonrpsee. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `base-consensus-rpc` crate defines the RPC types and client for the Base consensus layer, built on jsonrpsee. ## Source --- # consensus/service Source: https://basehub.org/crates/consensus/service/ Description: OP Stack consensus node service — orchestrates derivation, gossip, discovery, and engine communication. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-node-service` crate orchestrates the OP Stack consensus node. It coordinates derivation, gossip, discovery, and engine communication. ## Source --- # consensus/sources Source: https://basehub.org/crates/consensus/sources/ Description: Data source types and utilities for the consensus node including remote signer and transport abstractions. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `kona-sources` crate defines data source types and utilities for the consensus node, including remote signer and transport abstractions. ## Source --- # execution/chainspec Source: https://basehub.org/crates/execution/chainspec/ Description: Defines OP chain parameters, genesis state, and hardfork activation for the Base execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/chainspec` sub-crate (`reth-optimism-chainspec`) is part of the [execution crate group](/crates/execution/overview/). It defines the OP chain spec, including genesis state, gas parameters, and hardfork activation rules consumed by the EVM and consensus layers. ## Source --- # execution/cli Source: https://basehub.org/crates/execution/cli/ Description: Command-line entry point for the OP execution node with jemalloc, OpenTelemetry, and asm-keccak. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/cli` sub-crate (`reth-optimism-cli`) is part of the [execution crate group](/crates/execution/overview/). It exposes the command-line interface for the OP execution node and wires in jemalloc, OpenTelemetry tracing, and the asm-keccak backend. ## Source --- # execution/consensus Source: https://basehub.org/crates/execution/consensus/ Description: Validates OP blocks and verifies trie roots inside the execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/consensus` sub-crate (`reth-optimism-consensus`) is part of the [execution crate group](/crates/execution/overview/). It validates OP block headers and bodies and verifies state, transaction, and receipt trie roots before blocks enter the chain. ## Source --- # execution/evm Source: https://basehub.org/crates/execution/evm/ Description: OP EVM block executor and state transition logic for the Base execution environment. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/evm` sub-crate (`reth-optimism-evm`) is part of the [execution crate group](/crates/execution/overview/). It runs the OP-flavored EVM, executing blocks and applying state transitions for the Base execution environment. ## Source --- # execution/exex Source: https://basehub.org/crates/execution/exex/ Description: Execution Extensions for OP-Reth, including the proofs ExEx that emits trie updates. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/exex` sub-crate (`reth-optimism-exex`) is part of the [execution crate group](/crates/execution/overview/). It hosts Execution Extensions for OP-Reth, including the proofs ExEx that streams trie updates alongside committed blocks. ## Source --- # execution/hardforks Source: https://basehub.org/crates/execution/hardforks/ Description: Defines Optimism hardforks and activation rules used throughout op-reth. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/hardforks` sub-crate (`reth-optimism-forks`) is part of the [execution crate group](/crates/execution/overview/). It enumerates Optimism hardforks and their activation rules, supplying the fork schedule consumed across op-reth. ## Source --- # execution/node Source: https://basehub.org/crates/execution/node/ Description: Assembles the OP execution node from EVM, RPC, payload, pool, and storage components. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/node` sub-crate (`reth-optimism-node`) is part of the [execution crate group](/crates/execution/overview/). It assembles the OP execution node, wiring the EVM, RPC, payload builder, transaction pool, and storage into a runnable binary. ## Source --- # execution Source: https://basehub.org/crates/execution/overview/ Description: Execution layer crates covering the EVM, chain spec, payload building, storage, transaction pool, and state. The `execution` crate group runs the Base node's execution layer. It spans EVM execution, state storage, transaction pool, and payload construction. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [chainspec](/crates/execution/chainspec/) | `reth-optimism-chainspec` | EVM chain spec for Optimism | | [cli](/crates/execution/cli/) | `reth-optimism-cli` | Execution layer CLI (jemalloc, OTel) | | [consensus](/crates/execution/consensus/) | `reth-optimism-consensus` | Block validation and trie roots | | [evm](/crates/execution/evm/) | `reth-optimism-evm` | Block executor and state transitions | | [exex](/crates/execution/exex/) | `reth-optimism-exex` | Execution Extensions — proofs with trie updates | | [hardforks](/crates/execution/hardforks/) | `reth-optimism-forks` | Optimism hardfork definitions | | [node](/crates/execution/node/) | `reth-optimism-node` | Node builder — assembles all components | | [payload](/crates/execution/payload/) | `reth-optimism-payload-builder` | Payload construction from pending transactions | | [primitives](/crates/execution/primitives/) | `reth-optimism-primitives` | Custom transaction and receipt types | | [reth](/crates/execution/reth/) | `reth-op` | Meta-crate re-exporting all OP reth components | | [rpc](/crates/execution/rpc/) | `reth-optimism-rpc` | eth\_, debug\_, op\_ RPC namespaces | | [storage](/crates/execution/storage/) | `reth-optimism-storage` | Database codec implementations | | [trie](/crates/execution/trie/) | `reth-optimism-trie` | Trie storage for fault proof window | | [txpool](/crates/execution/txpool/) | `reth-optimism-txpool` | Transaction pool with L1 cost calculation | ## Role in the Architecture The execution crate group is the heart of the node. It: 1. Defines the Base chain specification including gas limits, hardforks, and genesis (`chainspec`, `hardforks`) 2. Configures and runs the EVM for transaction execution (`evm`) 3. Builds execution payloads from pending transactions (`payload`) 4. Manages the transaction pool for pending transactions (`txpool`) 5. Handles state storage and the Merkle Patricia Trie (`storage`, `trie`) 6. Provides RPC endpoints for querying execution state (`rpc`) 7. Integrates with Reth's execution pipeline (`reth`, `node`) 8. Supports Execution Extensions for custom indexing (`exex`) Built on top of [Reth](https://github.com/paradigmxyz/reth) v1.11.0, these crates customize Reth's execution engine for the Base L2 environment. ## Source [`crates/execution/`](https://github.com/base/base/tree/main/crates/execution) --- # execution/payload Source: https://basehub.org/crates/execution/payload/ Description: Builds OP execution payloads from pending transactions for the engine API. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/payload` sub-crate (`reth-optimism-payload-builder`) is part of the [execution crate group](/crates/execution/overview/). It builds OP execution payloads from the pending transaction set, returning blocks ready for the engine API to commit. ## Source --- # execution/primitives Source: https://basehub.org/crates/execution/primitives/ Description: OP-specific transaction, receipt, and block primitive types shared across the execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/primitives` sub-crate (`reth-optimism-primitives`) is part of the [execution crate group](/crates/execution/overview/). It defines the OP transaction, receipt, and block primitive types reused across the EVM, RPC, payload, and storage crates. ## Source --- # execution/reth Source: https://basehub.org/crates/execution/reth/ Description: Meta-crate that re-exports all OP reth components behind feature gates. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/reth` sub-crate (`reth-op`) is part of the [execution crate group](/crates/execution/overview/). It re-exports the full OP reth surface behind `full`, `node`, `evm`, and `rpc` feature gates so downstream crates pull in only what they need. ## Source --- # execution/rpc Source: https://basehub.org/crates/execution/rpc/ Description: Implements the eth_, debug_, and op_ JSON-RPC namespaces for the OP execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/rpc` sub-crate (`reth-optimism-rpc`) is part of the [execution crate group](/crates/execution/overview/). It implements the `eth_`, `debug_`, and `op_` JSON-RPC namespaces that clients use to query state, trace execution, and read OP-specific data. ## Source --- # execution/storage Source: https://basehub.org/crates/execution/storage/ Description: Database codecs for OP storage types used by the execution layer. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/storage` sub-crate (`reth-optimism-storage`) is part of the [execution crate group](/crates/execution/overview/). It implements database codecs for OP-specific storage types so the execution layer can persist and read them through Reth's database stack. ## Source --- # execution/trie Source: https://basehub.org/crates/execution/trie/ Description: Stores trie nodes so the node can serve proofs across the fault proof window. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/trie` sub-crate (`reth-optimism-trie`) is part of the [execution crate group](/crates/execution/overview/). It persists Merkle Patricia Trie nodes so the node can serve state and storage proofs throughout the fault proof window. ## Source --- # execution/txpool Source: https://basehub.org/crates/execution/txpool/ Description: OP-Reth transaction pool with gas estimation and L1 data cost accounting. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `execution/txpool` sub-crate (`reth-optimism-txpool`) is part of the [execution crate group](/crates/execution/overview/). It manages the OP-Reth transaction pool, applying gas estimation and L1 data fee accounting to pending transactions before they enter blocks. ## Source --- # infra/audit Source: https://basehub.org/crates/infra/audit/ Description: Consumes transaction events from Kafka and archives them to S3 for audit retention. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/audit` sub-crate (`audit-archiver-lib`) is part of the [infra crate group](/crates/infra/overview/). It consumes transaction events from Kafka and archives them to S3, producing the audit trail used for operational review. ## Source --- # infra/basectl Source: https://basehub.org/crates/infra/basectl/ Description: Ratatui-based terminal UI for interacting with Base, with WebSocket, clipboard, and contract support. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/basectl` sub-crate (`basectl-cli`) is part of the [infra crate group](/crates/infra/overview/). It ships a ratatui terminal UI for interacting with Base nodes, including WebSocket subscriptions, clipboard helpers, and contract calls. ## Source --- # infra/based Source: https://basehub.org/crates/infra/based/ Description: Shared library for block header fetching and StatsD metrics emission via cadence. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/based` sub-crate (`based`) is part of the [infra crate group](/crates/infra/overview/). It provides shared building blocks for fetching block headers and emitting StatsD metrics through cadence across the infra binaries. ## Source --- # infra/ingress-rpc Source: https://basehub.org/crates/infra/ingress-rpc/ Description: Ingress JSON-RPC server that forwards transactions to the builder and writes a Kafka audit trail. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/ingress-rpc` sub-crate (`ingress-rpc-lib`) is part of the [infra crate group](/crates/infra/overview/). It runs the ingress JSON-RPC server, forwarding incoming transactions to the builder and writing each one to Kafka for the audit trail. ## Source --- # infra/mempool-rebroadcaster Source: https://basehub.org/crates/infra/mempool-rebroadcaster/ Description: Rebroadcasts mempool transactions to multiple upstream providers to ensure propagation. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/mempool-rebroadcaster` sub-crate (`mempool-rebroadcaster`) is part of the [infra crate group](/crates/infra/overview/). It rebroadcasts pending mempool transactions to multiple upstream providers so they propagate even when individual peers drop them. ## Source --- # infra Source: https://basehub.org/crates/infra/overview/ Description: Operational tooling for Base — basectl, ingress RPC, WebSocket proxy, mempool rebroadcaster, and tests. The `infra` crate group runs the operational services around the Base node. It powers the auxiliary binaries that sit beside the main client. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [audit](/crates/infra/audit/) | `audit-archiver-lib` | Audit log archival | | [basectl](/crates/infra/basectl/) | `basectl-cli` | Node management utility | | [based](/crates/infra/based/) | `based` | Base daemon service | | [ingress-rpc](/crates/infra/ingress-rpc/) | `ingress-rpc-lib` | RPC ingress proxy (Kafka-based) | | [mempool-rebroadcaster](/crates/infra/mempool-rebroadcaster/) | `mempool-rebroadcaster` | Transaction rebroadcasting service | | [system-tests](/crates/infra/system-tests/) | `system-tests` | End-to-end system test framework | | [websocket-proxy](/crates/infra/websocket-proxy/) | `websocket-proxy` | WebSocket proxy for flashblock streaming | ## Role in the Architecture The infra crates provide the operational tooling around the core node: - **basectl** — A management utility for configuring and inspecting Base nodes. Supports mainnet, sepolia, and devnet configurations. - **based** — The Base daemon that orchestrates node services. - **ingress-rpc** — An RPC proxy that routes incoming JSON-RPC requests, using Kafka for message queuing. - **websocket-proxy** — Proxies WebSocket connections for flashblock streaming with Brotli compression. - **mempool-rebroadcaster** — Rebroadcasts transactions from the mempool to ensure propagation. - **audit** — Archives audit logs for operational monitoring. - **system-tests** — Integration and end-to-end tests using Docker Compose. ## Source [`crates/infra/`](https://github.com/base/base/tree/main/crates/infra) --- # infra/system-tests Source: https://basehub.org/crates/infra/system-tests/ Description: End-to-end test harness exercising the Base stack against Kafka, S3, and multiple providers. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/system-tests` sub-crate (`system-tests`) is part of the [infra crate group](/crates/infra/overview/). It runs end-to-end tests against the full Base stack, standing up Kafka, S3, and multiple provider configurations to validate behavior. ## Source --- # infra/websocket-proxy Source: https://basehub.org/crates/infra/websocket-proxy/ Description: WebSocket proxy built on axum with Brotli compression and exponential backoff reconnects. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `infra/websocket-proxy` sub-crate (`websocket-proxy`) is part of the [infra crate group](/crates/infra/overview/). It runs an axum-based WebSocket proxy that fans out flashblock streams with Brotli compression and exponential backoff on reconnects. ## Source --- # Crate Reference Source: https://basehub.org/crates/overview/ Description: The 8 top-level crate groups that make up the base/base Cargo workspace. The `base/base` Cargo workspace splits into 8 top-level crate groups. Each group owns a domain of the Base Reth Node and contains its own set of sub-crates. ## Workspace Structure | Crate Group | Sub-crates | Purpose | |-------------|-----------|---------| | [alloy](/crates/alloy/overview/) | 8 | Alloy type extensions for Base (consensus types, RPC types, EVM, hardforks) | | [builder](/crates/builder/overview/) | 3 | Block building, flashblock production, and metering | | [client](/crates/client/overview/) | 7 | Node client — CLI, engine, flashblocks integration, metering, RPC | | [consensus](/crates/consensus/overview/) | 15 | OP Stack consensus — derivation, gossip, P2P, sequencing (Kona-based) | | [execution](/crates/execution/overview/) | 14 | Execution layer — EVM, chainspec, payload building, storage, txpool | | [infra](/crates/infra/overview/) | 7 | Infrastructure tooling — basectl, ingress RPC, WebSocket proxy | | [proof](/crates/proof/overview/) | 7 | Fault proof system — FPVM, preimage oracle, proof driver (Kona-based) | | [shared](/crates/shared/overview/) | 9 | Shared utilities — primitives, access lists, JWT, bundles, CLI utils | ## Naming Conventions Crate names in `Cargo.toml` follow these patterns: - **`base-*`** — Core Base crates (e.g., `base-primitives`, `base-flashblocks`, `base-builder-core`) - **`kona-*`** — Consensus and proof crates derived from the Kona project (e.g., `kona-derive`, `kona-proof`) - **Infrastructure** — Named after their binary or function (e.g., `based`, `basectl-cli`, `ingress-rpc-lib`) ## Dependency Flow At a high level, dependencies flow in this direction: ``` shared, alloy (foundation types) ↓ execution (EVM, state, txpool) ↓ client (node assembly, CLI, RPC) ↓ builder (block building, flashblocks) consensus (independent OP Stack consensus) proof (independent fault proof system) infra (infrastructure binaries, depends on various crates) ``` The `shared` and `alloy` crates provide foundational types used throughout the workspace. The `execution` crates build on these to implement the EVM and state management. The `client` crates assemble the full node, and the `builder` crates handle block production. The `consensus` and `proof` crate groups are relatively independent — they implement the OP Stack consensus protocol and fault proof system respectively, with their own internal dependency chains. ## Source Code All crates live under [`crates/`](https://github.com/base/base/tree/main/crates) in the repository. --- # proof/driver Source: https://basehub.org/crates/proof/driver/ Description: no_std driver that sequences derivation and execution steps inside the fault proof program. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/driver` sub-crate (`kona-driver`) is part of the [proof crate group](/crates/proof/overview/). It drives the `no_std` derivation pipeline, sequencing derive and execute steps so the fault proof program can advance the L2 chain step by step. ## Source --- # proof/executor Source: https://basehub.org/crates/proof/executor/ Description: no_std stateless OP Stack block builder that runs the EVM inside the FPVM. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/executor` sub-crate (`kona-executor`) is part of the [proof crate group](/crates/proof/overview/). It builds OP Stack blocks statelessly inside the FPVM, executing the EVM against witness data supplied through the preimage oracle. ## Source --- # proof/mpt Source: https://basehub.org/crates/proof/mpt/ Description: Merkle Patricia Trie utilities for traversal, lookup, and proof verification inside the FPVM. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/mpt` sub-crate (`kona-mpt`) is part of the [proof crate group](/crates/proof/overview/). It implements Merkle Patricia Trie traversal, lookup, and proof verification used by the fault proof program to read state. ## Source --- # proof Source: https://basehub.org/crates/proof/overview/ Description: Fault proof crates covering the FPVM runtime, preimage oracle, driver, executor, and MPT verification. The `proof` crate group implements Base's fault proof stack. The crates derive from [Kona](https://github.com/op-rs/kona) and cover proof generation, verification, and the Fault Proof Virtual Machine (FPVM) interface. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [driver](/crates/proof/driver/) | `kona-driver` | Proof generation driver | | [executor](/crates/proof/executor/) | `kona-executor` | Stateless block executor for proofs | | [mpt](/crates/proof/mpt/) | `kona-mpt` | Merkle Patricia Trie for proofs | | [preimage](/crates/proof/preimage/) | `kona-preimage` | Preimage oracle interface | | [proof](/crates/proof/proof/) | `kona-proof` | Core proof logic | | [std-fpvm](/crates/proof/std-fpvm/) | `kona-std-fpvm` | Standard FPVM runtime | | [std-fpvm-proc](/crates/proof/std-fpvm-proc/) | `kona-std-fpvm-proc` | Procedural macros for FPVM | ## Role in the Architecture The proof system enables trustless verification of L2 state transitions on L1. It: 1. Re-executes L2 blocks in a deterministic environment (`executor`) 2. Uses the Merkle Patricia Trie for state proof verification (`mpt`) 3. Interfaces with the preimage oracle for reading L1/L2 data (`preimage`) 4. Runs inside the Fault Proof Virtual Machine (`std-fpvm`) 5. Coordinates the proof generation process (`driver`, `proof`) These crates compile to targets that run inside the FPVM (e.g., MIPS or RISC-V) for on-chain dispute resolution. ## Source [`crates/proof/`](https://github.com/base/base/tree/main/crates/proof) --- # proof/preimage Source: https://basehub.org/crates/proof/preimage/ Description: Rust bindings and types for the PreimageOracle ABI used by fault proof programs. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/preimage` sub-crate (`kona-preimage`) is part of the [proof crate group](/crates/proof/overview/). It provides Rust bindings and typed wrappers over the PreimageOracle ABI, the channel through which fault proof programs read host data. ## Source --- # proof/proof Source: https://basehub.org/crates/proof/proof/ Description: OP Stack Proof SDK with KZG via ark-bls12-381, preimage oracle integration, and the full proof pipeline. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/proof` sub-crate (`kona-proof`) is part of the [proof crate group](/crates/proof/overview/). It is the OP Stack Proof SDK, wiring KZG verification via `ark-bls12-381`, the preimage oracle, and the end-to-end proof pipeline. ## Source --- # proof/std-fpvm Source: https://basehub.org/crates/proof/std-fpvm/ Description: Platform APIs and a buddy allocator for programs targeting Fault Proof VM kernels. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/std-fpvm` sub-crate (`kona-std-fpvm`) is part of the [proof crate group](/crates/proof/overview/). It exposes platform-specific APIs for Fault Proof VM kernels and ships a buddy allocator that proof programs use as their global allocator. ## Source --- # proof/std-fpvm-proc Source: https://basehub.org/crates/proof/std-fpvm-proc/ Description: Procedural macros that emit the entry point for kona-std-fpvm proof programs. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `proof/std-fpvm-proc` sub-crate (`kona-std-fpvm-proc`) is part of the [proof crate group](/crates/proof/overview/). It supplies procedural macros that generate the entry point and runtime glue for programs targeting `kona-std-fpvm`. ## Source --- # shared/access-lists Source: https://basehub.org/crates/shared/access-lists/ Description: Implements Flashblock-level Access Lists (FAL), the EIP-7928 adaptation used by Base. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/access-lists` sub-crate (`base-access-lists`) is part of the [shared crate group](/crates/shared/overview/). It implements Flashblock-level Access Lists (FAL), Base's adaptation of EIP-7928 for the OP Stack. ## Source --- # shared/bundles Source: https://basehub.org/crates/shared/bundles/ Description: Defines transaction bundle types with UUID IDs, signing, and gas estimation for ordering. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/bundles` sub-crate (`base-bundles`) is part of the [shared crate group](/crates/shared/overview/). It defines transaction bundle types, including UUID identification, signing, and gas estimation that other crates use to order bundles. ## Source --- # shared/cli-utils Source: https://basehub.org/crates/shared/cli-utils/ Description: Shared CLI helpers for tracing, Prometheus export, clap parsing, and Kona registry lookups. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/cli-utils` sub-crate (`base-cli-utils`) is part of the [shared crate group](/crates/shared/overview/). It provides shared CLI helpers across the workspace: tracing setup, Prometheus metric export, clap argument helpers, and Kona registry chain lookup. ## Source --- # shared/engine-ext Source: https://basehub.org/crates/shared/engine-ext/ Description: In-process engine client that talks directly to Reth's execution layer without going over RPC. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/engine-ext` sub-crate (`base-engine-ext`) is part of the [shared crate group](/crates/shared/overview/). It exposes an in-process engine client so consensus components can drive Reth's execution layer directly without round-tripping through JSON-RPC. ## Source --- # shared/jwt Source: https://basehub.org/crates/shared/jwt/ Description: Loads and validates JWT secrets that authenticate Engine API traffic between node components. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/jwt` sub-crate (`base-jwt`) is part of the [shared crate group](/crates/shared/overview/). It loads and validates the JWT secrets that authenticate Engine API traffic between the consensus and execution components. ## Source --- # shared/node Source: https://basehub.org/crates/shared/node/ Description: Core node harness with the types and traits used to build Base node runner extensions. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/node` sub-crate (`base-client-node`) is part of the [shared crate group](/crates/shared/overview/). It defines the core node harness, including the primitive types and traits that Base node runner extensions implement. ## Source --- # shared Source: https://basehub.org/crates/shared/overview/ Description: Foundational crates for primitives, access lists, JWT auth, bundles, CLI utilities, and RPC types. The `shared` crate group holds the foundational types and utilities used across the workspace. It defines primitives, access lists, JWT auth, and RPC extensions consumed by every other crate group. ## Sub-crates | Crate | Package Name | Purpose | |-------|-------------|---------| | [access-lists](/crates/shared/access-lists/) | `base-access-lists` | Flashblock-level Access Lists (FAL) implementation | | [bundles](/crates/shared/bundles/) | `base-bundles` | Transaction bundle types | | [cli-utils](/crates/shared/cli-utils/) | `base-cli-utils` | CLI utilities (logging, metrics, clap helpers) | | [engine-ext](/crates/shared/engine-ext/) | `base-engine-ext` | Engine API extensions | | [jwt](/crates/shared/jwt/) | `base-jwt` | JWT authentication for Engine API | | [node](/crates/shared/node/) | `base-client-node` | Shared node configuration | | [primitives](/crates/shared/primitives/) | `base-primitives` | Core primitive types (includes Solidity contracts for tests) | | [reth-rpc-types](/crates/shared/reth-rpc-types/) | `base-reth-rpc-types` | Reth-compatible RPC type definitions | | [txpool-rpc](/crates/shared/txpool-rpc/) | `base-txpool-rpc` | Transaction pool RPC extensions | ## Role in the Architecture The shared crates form the foundation layer that all other crate groups depend on: - **primitives** — Defines the core types (transactions, blocks, receipts) used everywhere. Includes Solidity contracts compiled with Foundry for testing. - **access-lists** — Implements the [FAL specification](/specifications/access-lists/) for flashblock-level access lists, adapting EIP-7928 for the OP Stack. - **cli-utils** — Provides standardized CLI setup including clap argument parsing, tracing/logging configuration, and Prometheus metrics exporting. - **jwt** — Handles JWT-based authentication for the Engine API connection between execution and consensus layers. - **engine-ext** — Extends the Engine API with Base-specific payload attributes. - **txpool-rpc** — Adds custom RPC methods for interacting with the transaction pool. - **bundles** — Defines transaction bundle types for MEV and priority ordering. - **reth-rpc-types** — Bridges Base types to Reth's RPC type system. ## Source [`crates/shared/`](https://github.com/base/base/tree/main/crates/shared) --- # shared/primitives Source: https://basehub.org/crates/shared/primitives/ Description: Shared primitive types, Brotli helpers, bundle types, and Solidity bindings used across Base. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/primitives` sub-crate (`base-primitives`) is part of the [shared crate group](/crates/shared/overview/). It defines the workspace-wide primitive types and ships Brotli helpers, bundle types, and Solidity contract bindings used by tests and runtime code. ## Source --- # shared/reth-rpc-types Source: https://basehub.org/crates/shared/reth-rpc-types/ Description: Re-exports Reth RPC types so external consumers of the Base RPC interface get a stable surface. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/reth-rpc-types` sub-crate (`base-reth-rpc-types`) is part of the [shared crate group](/crates/shared/overview/). It re-exports the Reth RPC types so external consumers of the Base RPC interface depend on one stable surface. ## Source --- # shared/txpool-rpc Source: https://basehub.org/crates/shared/txpool-rpc/ Description: Adds Base-specific RPC methods for inspecting and interacting with the transaction pool. import { LinkCard } from '@astrojs/starlight/components'; ## Overview The `shared/txpool-rpc` sub-crate (`base-txpool-rpc`) is part of the [shared crate group](/crates/shared/overview/). It extends the JSON-RPC surface with Base-specific methods for inspecting and interacting with the transaction pool. ## Source --- # App Integration Source: https://basehub.org/flashblocks/app-integration/ Description: Integrate Flashblocks for 200ms confirmations using the pending RPC tag with Wagmi, Viem, Ethers, and Flashblocks-aware node providers. import { Aside, Tabs, TabItem } from '@astrojs/starlight/components'; Choose the integration that matches your app's needs and connect through a Flashblocks-aware RPC endpoint. | Use case | Recommended approach | Documentation | |----------|----------------------|---------------| | **Apps needing instant UX** | Flashblocks-aware RPC with the `pending` tag. | [API Reference](/api-reference/flashblocks/flashblocks-api-overview/) | | **Infrastructure providers** | Host Flashblocks-aware RPC nodes. | [Enable Flashblocks](/node-operations/run-a-base-node/#enable-flashblocks) | | **Standard apps** | Continue using regular RPCs. | [JSON-RPC API Reference](/api-reference/rpc-overview/) | ## RPC endpoints For HTTP and WebSocket endpoint URLs, see the [Flashblocks API reference](/api-reference/flashblocks/flashblocks-api-overview/). Public endpoints are rate-limited; for production, route through a Flashblocks-enabled provider such as Alchemy, QuickNode, or dRPC. ## Performance characteristics | Metric | Value | |--------|-------| | Flashblock build time (P50) | ~10ms | | Preconfirmation latency | ~200ms | | Full block time | 2 seconds | | Flashblocks per block | 10 | | Reorg rate | < 0.1% | ## Gas and transaction sizing The gas budget is **cumulative**, not per-Flashblock. Each Flashblock unlocks an additional 1/10 of the total block gas: | Flashblock | Cumulative gas available | |------------|--------------------------| | 1 | 1/10 of block limit (~18.75M gas) | | 2 | 2/10 of block limit (~37.5M gas) | | 3 | 3/10 of block limit (~56.25M gas) | | ... | ... | | 10 | Full block limit (~187.5M gas) | **Implications for large transactions:** - Transactions exceeding 1/10 of block gas (~18.75M) may not land in the first Flashblock — they wait for enough cumulative capacity. - A separate **per-transaction max gas limit** applies on Base, distinct from Flashblock capacity. - For best inclusion latency, keep individual transactions below ~18.75M gas so they qualify for the first Flashblock. ## Reliability and fallback Base targets a **< 0.1% Flashblock reorg rate** — the share of preconfirmations that were streamed but missed inclusion in the final block. This is rare, but apps should plan for it. If Flashblocks become unavailable, the sequencer keeps running and confirmation falls back to standard 2-second blocks. Apps should handle both modes. ## Library examples A Flashblocks-aware RPC endpoint is required to use Flashblocks with these libraries. ### [Wagmi](https://wagmi.sh) To use Flashblocks with Wagmi, set the `basePreconf` chain in the Wagmi config (see `config.ts`). ```tsx import { useSendTransaction, useWaitForTransactionReceipt } from "wagmi"; function SendTransaction() { const { data: hash, sendTransaction } = useSendTransaction(); const { data: receipt } = useWaitForTransactionReceipt({ hash }); return (
{hash &&
Hash: {hash}
} {receipt &&
Included on block number: {receipt.blockNumber}
}
) } ```
```tsx import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { WagmiProvider, useAccount } from 'wagmi' import { config } from './config' import { Example } from './Example' const queryClient = new QueryClient() function App() { return ( ) } ``` ```tsx import { createConfig, http } from "wagmi"; import { baseSepoliaPreconf } from "wagmi/chains"; import { baseAccount } from "wagmi/connectors"; export const config = createConfig({ chains: [baseSepoliaPreconf], connectors: [baseAccount()], transports: { [baseSepoliaPreconf.id]: http(), }, }); ```
### [Viem](https://viem.sh) ```ts import { createWalletClient, http, parseEther, publicActions } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { baseSepoliaPreconf } from "viem/chains"; // Create client with the Flashblocks-aware chain. const account = privateKeyToAccount(`0x${process.env.PRIVATE_KEY}`); const client = createWalletClient({ account, chain: baseSepoliaPreconf, transport: http(), }) .extend(publicActions); const submissionTime = new Date(); console.log(`Submitting transaction at: ${submissionTime.toISOString()}`); // Send transaction. const hash = await client.sendTransaction({ to: "0x...", value: parseEther('0.0001'), }); console.log(`Transaction hash: ${hash}`); // Wait for transaction to be included. const receipt = await client.waitForTransactionReceipt({ hash }); const confirmTime = new Date(); console.log(`Transaction included at: ${confirmTime.toISOString()}`); console.log(`Time difference: ${confirmTime - submissionTime}ms`); ``` ### [Ethers](https://github.com/ethers-io/ethers.js) ```jsx const providerA = new ethers.JsonRpcProvider( "https://sepolia-preconf.base.org" ); const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, providerA); try { // Create a simple transaction (sending 0.001 ETH to a random address) const tx = { to: "", value: ethers.parseEther("0.0000001"), }; // Submit transaction const submissionTime = new Date(); const transaction = await wallet.sendTransaction(tx); console.log(`Submitting transaction at: ${submissionTime.toISOString()}`); console.log(`Transaction hash: ${transaction.hash}`); await transaction.wait(0); // Make sure to set the confirmation count to 0 console.log("Transaction confirmed"); const confirmationTime = new Date(); console.log(`Transaction confirmed at: ${confirmationTime.toISOString()}`); console.log(`Time difference: ${confirmationTime - submissionTime}ms`); } ``` Confirmation times against this endpoint should be substantially lower than the standard RPC. ## Support For feedback, support, or questions about Flashblocks, reach the team in the `#developer-chat` channel on the [Base Discord](https://base.org/discord). --- # Flashblocks Architecture Source: https://basehub.org/flashblocks/architecture/ Description: Sequencer topology and infrastructure components — rollup-boost, op-rbuilder, websocket-proxy, and base — that power Flashblocks on Base. The Flashblocks pipeline layers four new components — rollup-boost, op-rbuilder, websocket-proxy, and base — onto Base's existing high-availability sequencer. ## Before Flashblocks Base operates a high-availability sequencer with five sequencer instances: | Component | Role | |-----------|------| | **op-node** | Standard OP Stack consensus layer (CL). | | **op-geth** | Standard OP Stack execution layer (EL). | | **op-conductor** | High availability controller using Raft consensus for leader election. | One sequencer instance is the **leader** and produces blocks, propagating them over P2P. The other four follow and sync the chain. Leadership transfers when the current leader stops producing blocks. ## With Flashblocks Flashblocks add several new infrastructure components: | Component | Purpose | What it unlocks | |-----------|---------|-----------------| | **rollup-boost** | CL↔EL Engine API proxy. | Streams Flashblocks to the EL without modifying the CL. Provides a stable seam for future block-building changes such as multi-builder. | | **op-rbuilder** | Out-of-protocol builder running at 200ms cadence. | Produces sub-second Flashblocks decoupled from the EL and enables pluggable builder mechanisms. | | **websocket-proxy** | Fan-out for the Flashblocks stream. | Lets many consumers read the stream without overwhelming the builder. | | **[base](https://github.com/base/base)** | RPC surface that exposes preconfirmations. | Turns streamed Flashblocks into familiar RPC methods so apps and wallets can consume preconfirmed state. | Flashbots builds and maintains [rollup-boost](https://github.com/flashbots/rollup-boost) and [op-rbuilder](https://github.com/flashbots/op-rbuilder); Base maintains the websocket-proxy and the [base](https://github.com/base/base) component. --- ## Further reading - [Flashblocks Overview](/flashblocks/overview/) — key concepts and transaction lifecycle. - [Enable Flashblocks](/node-operations/run-a-base-node/#enable-flashblocks) — run your own Flashblocks-aware RPC node. - [API Reference](/api-reference/flashblocks/flashblocks-api-overview/) — RPC methods, WebSocket subscriptions, and infrastructure stream schema. - [Flashblocks deep dive](https://blog.base.dev/flashblocks-deep-dive) — engineering blog post with implementation details. --- # Flashblocks FAQ Source: https://basehub.org/flashblocks/faq/ Description: Answers to common questions about Flashblocks block building, WebSocket data, RPC behavior, and node setup on Base. import { Aside } from '@astrojs/starlight/components'; Common questions about Flashblocks block building, WebSocket access, RPC behavior, and node setup. ## Block building ### Are Flashblocks optional? Every block on Base is built by the Flashblocks builder, so **Flashblocks are always live**. Apps that prefer not to consume preconfirmations can keep using standard RPCs without any Flashblocks integration. ### Is transaction inclusion different for Flashblocks vs. 2-second blocks? Not in any meaningful way — both order transactions by fee. The difference is timing: Flashblocks arrive every 200ms instead of every 2 seconds. See [Block Building](/network/block-building/#flashblocks) for details. ### Can the sequencer stop publishing Flashblocks? The sequencer will not stop publishing Flashblocks unless an extreme situation makes them unsafe to operate. If that happens, preconfirmations are disabled network-wide and confirmation falls back to standard 2-second blocks. The sequencer continues operating normally. ### Why is my transaction having trouble getting included? Transactions with large gas limits (greater than ~18.75M gas, which is 1/10 of the ~187.5M block limit) can take longer to include. The builder allocates gas cumulatively — Flashblock `j` may use up to `j/10` of the total block gas limit — so large transactions are admitted once enough cumulative capacity exists. See [Gas and transaction sizing](/flashblocks/app-integration/#gas--transaction-sizing) for the full breakdown. ### How do I make sure my transaction lands in the first Flashblock? There is no way to guarantee inclusion in a specific Flashblock, just as there is no way to guarantee a specific block. To improve the odds of fast inclusion: - Set a higher priority fee. - Keep the gas limit below ~18.75M (1/10 of the block limit) so the transaction is eligible for Flashblock 1. ### Why do transactions sometimes appear out of fee order? The Flashblock builder uses a **dynamic mempool** that keeps accepting new transactions while it builds. The design favors **low inclusion latency** over strict fee ordering. **What that means in practice:** - Transactions are ordered by fee *at the moment they are selected* for inclusion. - A high-fee transaction that arrives after a lower-fee transaction has already been committed to the current Flashblock will appear after it (or in the next Flashblock). - This is expected — the builder does not "reorder" already-committed transactions. **Why this trade-off?** A "snapshot" mempool that froze the txpool at the start of each block would guarantee strict fee ordering but at the cost of higher inclusion latency. The dynamic approach gets transactions into blocks faster, occasionally at the expense of breaking strict priority gas auction (PGA) ordering. **For traders and bots:** if strict fee-based ordering is essential to your strategy, arrival timing matters as much as fee amount within any 200ms Flashblock window. ### How frequently do Flashblock reorgs happen? Base targets a Flashblock reorg rate of < 0.1%. Reorgs are rare, but applications handling critical operations should still implement fallback logic. Live metrics are at [base.org/stats](https://base.org/stats). ### What does it mean when a Flashblock is reorged? A reorg means a Flashblock was streamed as a preconfirmation but did not make it into the final block. Architectural improvements in rollup-boost prevent tail-Flashblock reorgs, so this is uncommon — but apps should still handle the case. --- ## WebSocket ### Can I connect directly to the Flashblocks WebSocket stream? **No.** The raw Flashblocks WebSocket (`wss://mainnet.flashblocks.base.org/ws`) is reserved for infrastructure-to-node data syncing. Applications should not connect to it directly. Instead, query your RPC node or node provider (QuickNode, Alchemy, Infura, dRPC, etc.) for Flashblocks data via: - **RPC API** — standard JSON-RPC methods with the `pending` tag. - **WebSocket subscriptions** — `eth_subscribe` through your node provider's WebSocket endpoint. See [App Integration](/flashblocks/app-integration/) for implementation details. ### Why are there 11 Flashblock indices (0-10)? Index 0 carries only system transactions and uses no gas budget. Indexes 1-10 are the actual Flashblocks that pull pending transactions from the txpool. ### Why are there sometimes fewer than 10 Flashblocks? Expected behavior. When the previous block takes longer to build, the system compensates by allocating less time to the next block, which leaves room for fewer Flashblocks. ### Can the Flashblock index exceed 10? Is that a bug? **Not a bug.** Indices of 10, 11, or higher show up in normal operation. The standard math — 2-second block time divided by 200ms per Flashblock — yields exactly 10 Flashblocks (indices 0-9). In practice, the transition from one full L2 block to the next is not always perfectly aligned with the 200ms timer. Two situations create extra indices: 1. **Sequencer delay.** If sealing the full block takes slightly longer than 2000ms, the Flashblock stream keeps emitting incremental updates for the current block to keep the stream live. 2. **Timing drift.** If the internal 200ms clock drifts or starts early relative to the L2 block's canonical start time, an extra update can fit inside the 2-second window. **What this means for your implementation:** - Do not hardcode `9` or `10` as the final index — the last Flashblock for a given block is not predictable by index alone. - Track `payloadId` instead. The most reliable signal that a block has finished is when `payloadId` changes, or when the full block confirms via standard RPC. All Flashblocks sharing the same `payloadId` belong to the same block, no matter how high the index goes. - Once the sequencer advances to the next block, `payloadId` resets and `index` returns to `0`. ### What encoding format is the transaction data in? Transaction data in the [`diff.transactions`](/api-reference/flashblocks/flashblocks-api-overview/#diff-object) array is Recursive Length Prefix (RLP) encoded. ### Why am I getting rate limited on the WebSocket? The public WebSocket caps the number of connections. For production use: 1. Run your own [Flashblocks-aware RPC node](/node-operations/run-a-base-node/#enable-flashblocks). 2. Use a third-party node provider with Flashblocks support. --- ## RPC ### Why am I getting rate limited using `mainnet-preconf.base.org`? The public endpoint applies explicit rate limits. For production traffic: - Use a third-party node provider with Flashblocks support (Alchemy, Infura, QuickNode, dRPC). - Run your own [Flashblocks-aware RPC node](/node-operations/run-a-base-node/#enable-flashblocks). ### Why does `eth_call "pending"` report a block number several blocks behind tip? This is expected. Flashblocks-aware nodes retain up to 5 historical blocks of Flashblocks state to avoid race conditions. When `eth_call "pending"` runs, it executes on top of that historical base, so the block number visible in the call context (such as `block.number`) may show as N-5. When `eth_call "pending"` executes, the entire block context — `block.number`, `block.timestamp`, `block.basefee`, and the rest — corresponds to that historical base block (potentially N-5), not the current chain tip. **The call result is correct** in that all received Flashblocks state has been applied on top, but contracts that depend on block context properties should be aware that those values may be several blocks behind. For nodes in regions where P2P latency is comparable to WebSocket stream latency, lowering `MAX_PENDING_BLOCKS_DEPTH` reduces this gap. The setting controls how many historical blocks of Flashblocks state the node retains; a lower value keeps the block context closer to tip at the cost of less tolerance for P2P latency spikes. ### What RPC methods support Flashblocks? The following methods are Flashblocks-enabled: | Method | Usage | |--------|-------| | `eth_getBlockByNumber` | Use the `pending` tag. | | `eth_getBalance` | Use the `pending` tag. | | `eth_getTransactionReceipt` | Returns preconfirmed receipts. | | `eth_getTransactionByHash` | Use the `pending` tag. | | `eth_getTransactionCount` | Use the `pending` tag. | | `eth_call` | Use the `pending` tag. | | `eth_simulateV1` | Use the `pending` tag. | | `eth_estimateGas` | Use the `pending` tag. | | `eth_getLogs` | Use `pending` for `toBlock`. | | `eth_subscribe` | Stream Flashblock data in real time. | | `base_transactionStatus` | Check if a transaction is in the mempool (Beta). | See the [Flashblocks API reference](/api-reference/flashblocks/flashblocks-api-overview/) for full method details and examples. --- ## Node setup ### How do I set up a Flashblocks-aware RPC node? Use the Reth binary from the [Base node repository](https://github.com/base/node/tree/main/reth). Full instructions are in [Enable Flashblocks](/node-operations/run-a-base-node/#enable-flashblocks). --- # Flashblocks Overview Source: https://basehub.org/flashblocks/overview/ Description: Flashblocks deliver 200ms preconfirmed sub-blocks on Base, streaming state updates 10x faster than the standard 2-second block cadence. import { Aside } from '@astrojs/starlight/components'; Flashblocks are 200ms preconfirmed sub-blocks streamed by the Base sequencer, giving applications fee-ordered state updates ten times per standard 2-second block. ## What are Flashblocks Flashblocks add **200ms** incremental state updates to Base, cutting perceived latency for end users. The mechanism, built with [Flashbots](https://www.flashbots.net/), streams sub-blocks inside the regular 2-second block interval. Apps see preconfirmations from the sequencer well before the full block is gossiped to the network. ### Key concepts | Term | Definition | |------|------------| | **Flashblock** | A 200ms sub-block carrying part of the full block's transactions. | | **Preconfirmation** | An ultra-fast signal that a transaction will be included, before the full block is sealed. | | **Full Block** | A sequence of 10 Flashblocks combined into the complete 2-second block. | Each block contains **10 Flashblocks** (indexes 1-10), arriving every 200ms. Index 0 exists but only carries system transactions. See [Gas and transaction sizing](/flashblocks/app-integration/#gas--transaction-sizing) for how the gas budget evolves across the window. ## Architecture For details on the sequencer system and the Flashblocks infrastructure components (rollup-boost, op-rbuilder, websocket-proxy, and base), see the [Architecture](/flashblocks/architecture/) page. ## Transaction lifecycle When a transaction is sent to Base, this is the path it takes: ### 1. Submission ``` User → DNS (mainnet.base.org) → Load Balancer → Proxyd → Mempool ``` The transaction lands in the private mempool and is added to the txpool as pending. ### 2. Distribution The mempool keeps P2P connections open with execution layers (op-reth, op-rbuilder), keeping all pending transactions in sync for block building. ### 3. Block building In each 200ms loop, op-rbuilder selects transactions using: 1. **Transaction fee** — transactions are ordered fee-first (highest first). 2. **Gas limit and remaining capacity** — Flashblock `j` may use up to `j/10` of the total block gas limit. ### 4. Block building algorithm For each 2-second block, the builder runs: ``` FOR each flashblock j FROM 0 TO 10: 1. Wait until next 200ms window 2. Calculate available gas: (j / 10) × total_block_gas_limit 3. Sort pending transactions by fee (descending) 4. Select top transactions that fit within available gas 5. Execute transactions and update state 6. Stream flashblock to websocket-proxy ``` ### 5. Preconfirmation delivery Once a transaction is included in a Flashblock, the builder streams it to the websocket-proxy. RPC nodes subscribe to that stream, so a Flashblocks-aware RPC method (such as `eth_getTransactionReceipt`) can return preconfirmed data straight from the node's cache. ## Further reading - [FAQ](/flashblocks/faq/) — common questions about Flashblocks. - [Block Building](/network/block-building/) — detailed block ordering configuration. - [Flashblocks deep dive](https://blog.base.dev/flashblocks-deep-dive) — engineering blog post with implementation details. --- # Building from Source Source: https://basehub.org/getting-started/building/ Description: Clone the base/base repository and compile binaries with Just recipes or Cargo. Building `base/base` from source means cloning the repository and compiling one or more workspace targets with Just or Cargo. Install all [prerequisites](/getting-started/prerequisites/) before continuing. ## Clone the Repository ```bash git clone https://github.com/base/base.git cd base ``` ## Standard Release Build The most common build command produces a fully optimized release binary for every binary target in the workspace: ```bash just build ``` Under the hood this runs `cargo build --release`. The compiled binaries are placed in `target/release/`. ## Maximum Performance Build For production deployments where you want every bit of throughput, use the `maxperf` profile. This enables all CPU-specific optimizations and links against jemalloc: ```bash just build-maxperf ``` This build takes longer to compile but produces a binary tuned for the machine it was compiled on. Do not distribute `maxperf` binaries to machines with different CPU micro-architectures. ## Building Individual Targets If you only need the node binary and want a faster compile: ```bash just build-node ``` Or build it directly with Cargo: ```bash cargo build --release --bin base-reth-node ``` The resulting binary is at `target/release/base-reth-node`. ## Building Solidity Test Contracts Several crates in the workspace depend on compiled Solidity contracts for their test suites. Build them with: ```bash just build-contracts ``` This changes into `crates/shared/primitives/contracts`, installs Soldeer dependencies, and runs `forge build`. You must have [Foundry](/getting-started/prerequisites/#foundry) installed for this to work. ## Debug Build (All Targets) During development you may want an unoptimized build with debug symbols for every target in the workspace: ```bash just build-all-targets ``` This compiles in debug mode, which is significantly faster to compile but produces slower binaries. Use this when you need to iterate quickly and do not care about runtime performance. ## Build Artifacts | Command | Profile | Output | |---|---|---| | `just build` | release | `target/release/*` | | `just build-maxperf` | maxperf (release + LTO + jemalloc) | `target/release/*` | | `just build-node` | release | `target/release/base-reth-node` | | `just build-all-targets` | debug | `target/debug/*` | | `just build-contracts` | N/A (Foundry) | Solidity artifacts in `crates/shared/primitives/contracts/out/` | ## Troubleshooting **Linker errors mentioning `clang` or `llvm`** -- Install `libclang-dev` (Debian/Ubuntu) or make sure Xcode Command Line Tools are installed (macOS). **Out of memory during linking** -- Release and maxperf builds with LTO can use a lot of RAM. Close other memory-heavy applications or add swap space. You can also reduce parallelism: ```bash CARGO_BUILD_JOBS=2 just build ``` **Stale Solidity artifacts** -- If contract tests fail after pulling new changes, re-run `just build-contracts` to recompile. Once the build completes, continue to [Running the Node](/getting-started/running/) or [Docker Builds](/getting-started/docker/). --- # Development Workflow Source: https://basehub.org/getting-started/development/ Description: Run the check, test, fix, and CI Just recipes used day-to-day on base/base. The `base/base` repository drives day-to-day development through [Just](https://github.com/casey/just) recipes for checking, testing, formatting, and CI parity. The recipes below cover the commands you will run most often. ## Quick Reference | Command | What it does | |---|---| | `just check` | Runs the full check suite (format, udeps, clippy, test, deny) | | `just test` | Runs the test suite via cargo-nextest | | `just fix` | Auto-fixes formatting, clippy, and zepter issues | | `just ci` | Full CI pipeline (fix, check, lychee, zepter, no-std check) | ## Running Tests The project uses [cargo-nextest](https://nexte.st/) as its test runner. Install it if you have not already: ```bash cargo install cargo-nextest ``` Run the full test suite: ```bash just test ``` This executes `cargo nextest` with all features enabled. The devnet tests are excluded by default since they require a running Docker Compose stack. To run tests for a specific crate: ```bash cargo nextest run -p base-execution-evm ``` To run a single test by name: ```bash cargo nextest run -p base-execution-evm -- test_name ``` ### Building Test Contracts Some tests depend on compiled Solidity contracts. If you see test failures related to missing contract artifacts, build them first: ```bash just build-contracts ``` See [Building from Source](/getting-started/building/#building-solidity-test-contracts) for details. ## Checking Code Quality The `check` recipe runs the full quality gate in sequence: ```bash just check ``` This is equivalent to running each of these in order: 1. **`check-format`** -- Verifies that all Rust source files match `rustfmt` style. 2. **`check-udeps`** -- Detects unused dependencies in `Cargo.toml` files. 3. **`check-clippy`** -- Runs Clippy with the project's configured lints. 4. **`test`** -- Runs the full test suite. 5. **`check-deny`** -- Checks dependencies for known vulnerabilities and license issues via `cargo-deny`. If any step fails, the pipeline stops. Fix the issue and re-run. ## Auto-Fixing Issues Most formatting and lint issues can be fixed automatically: ```bash just fix ``` This runs three fixers in sequence: 1. **`format-fix`** -- Applies `rustfmt` to all source files. 2. **`clippy-fix`** -- Applies Clippy's suggested fixes. 3. **`zepter-fix`** -- Fixes feature propagation issues detected by [zepter](https://github.com/nicknisi/zepter). Run `just fix` before committing to avoid CI failures. ## Full CI Pipeline To run the same checks that CI runs on pull requests: ```bash just ci ``` This encompasses: 1. `fix` -- auto-fix everything fixable 2. `check` -- the full quality gate 3. `lychee` -- checks for broken links in documentation 4. `zepter` -- validates Cargo feature propagation 5. `check-no-std` -- ensures `no_std` compatibility for crates that require it Running `just ci` locally before pushing is the best way to catch issues early. ## Formatting Check formatting without modifying files: ```bash just check-format ``` Auto-format all files: ```bash just format-fix ``` The project uses the standard `rustfmt` configuration. If your editor supports format-on-save with `rustfmt`, enable it for a smoother workflow. ## Clippy Run Clippy to catch common mistakes and non-idiomatic patterns: ```bash just check-clippy ``` Apply Clippy's suggestions automatically: ```bash just clippy-fix ``` ## Recommended Editor Setup For the best development experience, configure your editor with: - **rust-analyzer** -- Provides inline type hints, go-to-definition, and real-time diagnostics. - **Format on save** -- Set your editor to run `rustfmt` whenever you save a `.rs` file. - **Clippy as the check command** -- Configure rust-analyzer to use `clippy` instead of `cargo check` for richer diagnostics: ```json { "rust-analyzer.check.command": "clippy" } ``` ## Next Steps - [Local Devnet](/getting-started/devnet/) -- run a full local network for integration testing. - [Contributing](/contributing/) -- guidelines for submitting pull requests. --- # Local Devnet Source: https://basehub.org/getting-started/devnet/ Description: Start a Docker Compose devnet for integration testing, debugging, and flashblocks experiments. The Docker Compose devnet bundled with `base/base` spins up a complete local Base network for integration testing, debugging, and flashblocks experiments without touching a public testnet. Its configuration lives in `etc/docker/docker-compose.yml`. ## Prerequisites Before starting the devnet, make sure you have: - [Docker and Docker Compose](/getting-started/prerequisites/#docker-optional) installed and running. - The repository cloned and all [prerequisites](/getting-started/prerequisites/) in place. ### Pre-Pulling Images The devnet uses several Docker images. To avoid long waits on the first start, pull them ahead of time: ```bash just system-tests-pull-images ``` ## Starting the Devnet The `devnet` recipe handles the full lifecycle: it stops any existing devnet, builds fresh images, and starts the stack: ```bash just devnet ``` This is the recommended way to start or restart the devnet. It ensures you are running the latest code and that there is no stale state from a previous run. ## Stopping the Devnet To stop all containers and clean up resources: ```bash just devnet-down ``` This removes the containers and associated volumes, giving you a clean slate for the next start. ## Monitoring ### Block Status Check the current block numbers and sync status of the devnet nodes: ```bash just devnet-status ``` This prints block heights and indicates whether nodes are in sync. ### Funded Test Accounts View the pre-funded accounts available for testing: ```bash just devnet-accounts ``` These accounts come with a balance of test ETH and are ready to use for sending transactions. ### Container Logs Stream logs from one or more containers: ```bash # All containers just devnet-logs # Specific containers just devnet-logs sequencer proposer ``` Logs are streamed in real time. Press Ctrl+C to stop. ## Testing on the Devnet ### Smoke Tests Run a basic set of test transactions to verify the devnet is functioning correctly: ```bash just devnet-smoke ``` This sends a few transactions and verifies they are included in blocks. ### Combined Status and Smoke Run both status checks and smoke tests together: ```bash just devnet-checks ``` This is a convenient single command that first prints the devnet status and then runs the smoke tests. ### Load Testing Start the Contender load generator to stress-test the devnet: ```bash just devnet-load ``` This generates a sustained stream of transactions, which is useful for benchmarking block production, measuring throughput, and testing behavior under pressure. ## Flashblocks Streaming The devnet supports flashblocks -- sub-block-time transaction confirmations streamed over WebSocket. To connect and watch flashblocks: ```bash just devnet-flashblocks ``` This opens a WebSocket connection to the devnet and prints flashblock messages as they arrive (typically every 200ms). It is a quick way to verify that the flashblocks pipeline is working end-to-end. ## Typical Workflow A common development loop with the devnet looks like this: 1. Make code changes. 2. Start a fresh devnet: ```bash just devnet ``` 3. Verify it is running: ```bash just devnet-status ``` 4. Run smoke tests: ```bash just devnet-smoke ``` 5. Stream flashblocks to test your changes: ```bash just devnet-flashblocks ``` 6. Check logs for issues: ```bash just devnet-logs ``` 7. When finished, tear it down: ```bash just devnet-down ``` ## Troubleshooting **Containers fail to start** -- Make sure Docker is running and your user is in the `docker` group. Run `docker compose version` to verify the Compose plugin is installed. **Port conflicts** -- If another service is using the ports the devnet needs, stop that service first or edit `etc/docker/docker-compose.yml` to remap ports. **Stale state** -- If the devnet behaves unexpectedly after code changes, run `just devnet-down` followed by `just devnet` to start from a clean state. **Slow first start** -- The first run pulls several Docker images and may build containers from scratch. Run `just system-tests-pull-images` ahead of time to pre-pull base images. --- # Docker Builds Source: https://basehub.org/getting-started/docker/ Description: Build and run base/base from the Dockerfiles under etc/docker without installing Rust on the host. Docker builds compile `base/base` reproducibly without a host Rust toolchain. The repository ships several Dockerfiles under `etc/docker/` for the client, builder, devnet, and websocket proxy. ## Available Dockerfiles | File | Purpose | |---|---| | `etc/docker/Dockerfile.client` | Production client image containing `base-reth-node` | | `etc/docker/Dockerfile.builder` | Builder image used as a base for multi-stage builds | | `etc/docker/Dockerfile.devnet` | Devnet-specific image for local development networks | | `etc/docker/Dockerfile.websocket-proxy` | Standalone websocket proxy image | ## Building the Client Image From the repository root, build the production client image: ```bash docker build -t base-reth-node -f etc/docker/Dockerfile.client . ``` This performs a multi-stage build: it compiles the Rust binary inside a builder container and copies the resulting binary into a minimal runtime image. The build context is the repository root, so all workspace crates are available to the compiler. Depending on your hardware, the first build may take 15-30 minutes. Subsequent builds benefit from Docker layer caching. ## Running the Container Start the node with default settings: ```bash docker run -it --rm base-reth-node ``` Pass CLI options after the image name, exactly as you would with the bare binary: ```bash docker run -it --rm base-reth-node --help ``` ### Persisting Data By default, a container's filesystem is ephemeral. To persist chain data across restarts, mount a host directory to the node's data directory: ```bash docker run -it --rm \ -v /path/to/data:/data \ base-reth-node \ --datadir /data ``` ### Exposing Ports The node exposes several network ports. Map them to the host as needed: ```bash docker run -it --rm \ -v /path/to/data:/data \ -p 8545:8545 \ -p 8546:8546 \ -p 30303:30303 \ -p 30303:30303/udp \ base-reth-node \ --datadir /data \ --http \ --http.addr 0.0.0.0 \ --ws \ --ws.addr 0.0.0.0 ``` | Port | Protocol | Service | |---|---|---| | 8545 | TCP | HTTP JSON-RPC | | 8546 | TCP | WebSocket JSON-RPC | | 30303 | TCP + UDP | P2P discovery and communication | ### Running in the Background Use `-d` instead of `-it` to run detached: ```bash docker run -d --name base-node \ -v /path/to/data:/data \ -p 8545:8545 \ base-reth-node \ --datadir /data \ --http --http.addr 0.0.0.0 # View logs docker logs -f base-node # Stop docker stop base-node ``` ## Building Other Images Build the websocket proxy image: ```bash docker build -t base-websocket-proxy -f etc/docker/Dockerfile.websocket-proxy . ``` Build the devnet image (typically used by the docker-compose devnet stack rather than run directly): ```bash docker build -t base-devnet -f etc/docker/Dockerfile.devnet . ``` ## Tips - **Layer caching**: The Dockerfiles are structured so that dependency fetching is cached separately from source compilation. If you only change Rust source files, the dependency layers are reused. - **BuildKit**: Enable BuildKit for faster builds: `DOCKER_BUILDKIT=1 docker build ...` - **Cross-compilation**: If you need an `amd64` image on an ARM host (or vice versa), use `docker buildx build --platform linux/amd64 ...`. For running a full local devnet with Docker Compose, see [Local Devnet](/getting-started/devnet/). For production Docker deployments, see [Node Operations: Docker](/node-operations/docker/). --- # Prerequisites Source: https://basehub.org/getting-started/prerequisites/ Description: Install Rust, Just, Foundry, build essentials, and optionally Docker before working on base/base. Building or developing on `base/base` requires Rust, Just, Foundry, a C/C++ toolchain, and optionally Docker. Instructions below target Linux (Debian/Ubuntu); macOS users can substitute `brew install` where applicable. ## Rust The project requires **Rust 1.88 or later**. The recommended way to install and manage Rust toolchains is through [rustup](https://rustup.rs/): ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` Follow the on-screen prompts and then reload your shell: ```bash source "$HOME/.cargo/env" ``` Verify the installed version: ```bash rustc --version # rustc 1.88.0 (or later) ``` If you already have Rust installed, make sure it is up to date: ```bash rustup update ``` ## Just [Just](https://github.com/casey/just) is a command runner used throughout the project for build, test, and devnet workflows. Install it with one of: ```bash # Using cargo (works everywhere Rust is installed) cargo install just # Debian/Ubuntu sudo apt install just # macOS (Homebrew) brew install just ``` Confirm the installation: ```bash just --version ``` ## Foundry [Foundry](https://book.getfoundry.sh/) is required for compiling the Solidity test contracts used by several crates. Install via the official installer: ```bash curl -L https://foundry.paradigm.xyz | bash ``` Then run: ```bash foundryup ``` This gives you `forge`, `cast`, `anvil`, and `chisel`. Verify with: ```bash forge --version ``` ## Build Essentials A standard C/C++ toolchain and a few system libraries are needed to compile native dependencies: ```bash # Debian / Ubuntu sudo apt update sudo apt install -y git libclang-dev pkg-config curl build-essential ``` ```bash # macOS (Xcode Command Line Tools provide clang and related headers) xcode-select --install brew install pkg-config ``` ## Docker (Optional) Docker is only required if you plan to build container images or run the local devnet. Install Docker Engine by following the [official instructions](https://docs.docker.com/engine/install/) for your platform, or on Ubuntu: ```bash sudo apt install -y docker.io sudo systemctl enable --now docker sudo usermod -aG docker "$USER" ``` Log out and back in for the group change to take effect, then verify: ```bash docker --version docker compose version ``` The devnet uses Docker Compose (the `docker compose` plugin, not the legacy `docker-compose` binary). ## Quick Check Once everything is installed, you can run a quick sanity check from the repository root: ```bash rustc --version && cargo --version && just --version && forge --version && git --version ``` All five commands should succeed and print version information. With these prerequisites in place, proceed to [Building from Source](/getting-started/building/). --- # Running the Node Source: https://basehub.org/getting-started/running/ Description: Start the base-reth-node binary, configure RPC and metrics, and shut down cleanly. The `base-reth-node` binary starts the Base L2 execution client once you have a [source build](/getting-started/building/) or [Docker image](/getting-started/docker/). For production guidance, see [Node Operations](/node-operations/deployment/). ## Starting the Node Run the binary directly from the build output directory: ```bash ./target/release/base-reth-node ``` Or, if you used `just build-node`: ```bash ./target/release/base-reth-node ``` The node will begin syncing from the network. On the first run it creates a data directory (by default `~/.local/share/reth/` on Linux, `~/Library/Application Support/reth/` on macOS) and starts downloading blocks. ## CLI Help View all available options and subcommands: ```bash ./target/release/base-reth-node --help ``` This prints the full help text including every flag, option, and subcommand. It is the definitive reference for the CLI and is always in sync with the version you built. ## Common Options ### Data Directory Override the default data directory: ```bash ./target/release/base-reth-node --datadir /mnt/ssd/base-node ``` ### HTTP JSON-RPC Enable the HTTP JSON-RPC server: ```bash ./target/release/base-reth-node \ --http \ --http.addr 127.0.0.1 \ --http.port 8545 ``` By default the server only listens on localhost. Set `--http.addr 0.0.0.0` to accept connections from other machines (make sure your firewall is configured appropriately). ### WebSocket JSON-RPC Enable the WebSocket server alongside (or instead of) HTTP: ```bash ./target/release/base-reth-node \ --ws \ --ws.addr 127.0.0.1 \ --ws.port 8546 ``` ### Logging Control log verbosity with the `-v` flag (can be repeated) or the `RUST_LOG` environment variable: ```bash # Increase verbosity ./target/release/base-reth-node -vvv # Fine-grained control via RUST_LOG RUST_LOG=info,reth=debug ./target/release/base-reth-node ``` ### Metrics Enable the Prometheus metrics endpoint: ```bash ./target/release/base-reth-node \ --metrics 127.0.0.1:9001 ``` Point your Prometheus instance at `http://:9001/metrics` to scrape node metrics. ## Example: Full Node with RPC A typical invocation that enables both HTTP and WebSocket RPC, metrics, and stores data on a dedicated volume: ```bash ./target/release/base-reth-node \ --datadir /data/base-node \ --http \ --http.addr 0.0.0.0 \ --http.port 8545 \ --ws \ --ws.addr 0.0.0.0 \ --ws.port 8546 \ --metrics 0.0.0.0:9001 \ -vv ``` ## Stopping the Node Send `SIGINT` (Ctrl+C) or `SIGTERM` to gracefully shut down the node. It will flush pending state to disk before exiting. Avoid sending `SIGKILL` unless absolutely necessary, as it can leave the database in an inconsistent state requiring a repair on next startup. ## Next Steps - [Development Workflow](/getting-started/development/) -- learn the day-to-day check, test, and fix commands. - [Local Devnet](/getting-started/devnet/) -- spin up a full local network for integration testing. - [Configuration](/node-operations/configuration/) -- detailed configuration reference for production deployments. --- # Connecting to Base Source: https://basehub.org/integration-guides/connecting/ Description: Connect to Base mainnet or Sepolia using public endpoints, your own node, or a third-party provider. import CodeColumns from '../../../components/CodeColumns.astro'; Connect to Base mainnet or the Sepolia testnet using public RPC endpoints, your own node, or a third-party provider. ## Network parameters ### Base Mainnet | Parameter | Value | |-----------|-------| | Network name | Base | | Chain ID | `8453` (`0x2105`) | | Currency | ETH | | Block time | 2 seconds | | Flashblock interval | 200ms | | L1 settlement | Ethereum Mainnet | | Explorer | [basescan.org](https://basescan.org) | ### Base Sepolia (testnet) | Parameter | Value | |-----------|-------| | Network name | Base Sepolia | | Chain ID | `84532` (`0x14a34`) | | Currency | ETH (testnet) | | Block time | 2 seconds | | L1 settlement | Ethereum Sepolia | | Explorer | [sepolia.basescan.org](https://sepolia.basescan.org) | ## Public RPC endpoints Base provides public RPC endpoints for general use: | Network | HTTP Endpoint | WebSocket Endpoint | |---------|---------------|-------------------| | Mainnet | `https://mainnet.base.org` | `wss://mainnet.base.org` | | Sepolia | `https://sepolia.base.org` | `wss://sepolia.base.org` | :::note Public endpoints are rate-limited and intended for development and light usage. For production, run your own node or use a third-party provider. ::: ## Connecting with common tools ### curl
A raw JSON-RPC `POST` request returns the latest block number as a hex string. This is the lowest-common-denominator way to talk to Base — useful for sanity-checking that an endpoint is alive.
```bash curl -X POST https://mainnet.base.org \ -H "Content-Type: application/json" \ -d '{ "method": "eth_blockNumber", "params": [], "id": 1, "jsonrpc": "2.0" }' ```
### cast (Foundry)
Foundry's `cast` wraps every standard JSON-RPC method behind a clean CLI. Point it at any Base endpoint with `--rpc-url`.
```bash cast block-number --rpc-url https://mainnet.base.org cast balance 0xYourAddress --rpc-url https://mainnet.base.org cast chain-id --rpc-url https://mainnet.base.org ```
### ethers.js
`JsonRpcProvider` is the standard ethers entry point. It works against any Base endpoint — public, your own node, or a provider.
```javascript import { JsonRpcProvider } from "ethers"; const provider = new JsonRpcProvider("https://mainnet.base.org"); const blockNumber = await provider.getBlockNumber(); console.log("Current block:", blockNumber); const balance = await provider.getBalance("0xYourAddress"); console.log("Balance:", balance.toString(), "wei"); ```
### viem
viem ships chain definitions for both Base networks. `createPublicClient` selects the right RPC defaults automatically.
```typescript import { createPublicClient, http } from "viem"; import { base, baseSepolia } from "viem/chains"; const client = createPublicClient({ chain: base, transport: http(), }); const blockNumber = await client.getBlockNumber(); console.log("Current block:", blockNumber); const testnetClient = createPublicClient({ chain: baseSepolia, transport: http(), }); ```
### MetaMask / wallet configuration To add Base to a wallet manually: | Field | Mainnet | Sepolia | |-------|---------|---------| | Network Name | Base | Base Sepolia | | RPC URL | `https://mainnet.base.org` | `https://sepolia.base.org` | | Chain ID | `8453` | `84532` | | Currency Symbol | ETH | ETH | | Block Explorer URL | `https://basescan.org` | `https://sepolia.basescan.org` | ## Running your own node For production, running your own Base node gives full control over rate limits, latency, and data availability. ### Quick start The fastest path is the pre-built Docker image: ```bash docker pull ghcr.io/base/base-reth-node:latest docker run -d \ --name base-node \ -p 8545:8545 \ -p 8546:8546 \ -p 30303:30303 \ -v base-data:/data \ ghcr.io/base/base-reth-node:latest \ --http \ --http.addr 0.0.0.0 \ --http.port 8545 \ --http.api eth,net,web3,txpool \ --ws \ --ws.addr 0.0.0.0 \ --ws.port 8546 ``` For full instructions: - [Building from source](/getting-started/building/) — compile the node binary. - [Running the node](/getting-started/running/) — configuration and startup. - [Docker](/getting-started/docker/) — containerized deployment. - [Node deployment](/node-operations/deployment/) — production deployment guide. ### Node sync modes | Mode | Description | Disk usage | Sync time | |------|-------------|------------|-----------| | Full | Executes all transactions from genesis. | High | Days | | Snap | Downloads state snapshots, then follows chain tip. | Moderate | Hours | ## JSON-RPC interface Base nodes expose the standard Ethereum JSON-RPC interface. The following namespaces are available: ### Standard namespaces | Namespace | Description | |-----------|-------------| | `eth` | Core Ethereum methods — blocks, transactions, state queries, gas estimation. | | `net` | Network information — peer count, version, listening status. | | `web3` | Utility methods — client version, SHA3. | | `txpool` | Transaction pool inspection (see [Transaction Pool](/integration-guides/txpool/)). | | `debug` | Debug methods — trace transactions, get raw block data (enable with `--http.api debug`). | ### Base-specific namespaces | Namespace | Description | |-----------|-------------| | `base` | Base-specific methods including metering (see [Metering RPC](/integration-guides/metering-rpc/)). | ### Commonly used methods | Method | Description | |--------|-------------| | `eth_blockNumber` | Returns the latest block number. | | `eth_getBlockByNumber` | Returns block data by number or tag. | | `eth_getBlockByHash` | Returns block data by hash. | | `eth_getTransactionByHash` | Returns a transaction by hash. | | `eth_getTransactionReceipt` | Returns a transaction receipt. | | `eth_getBalance` | Returns account balance. | | `eth_getTransactionCount` | Returns account nonce. | | `eth_call` | Executes a call without creating a transaction. | | `eth_estimateGas` | Estimates gas for a transaction. | | `eth_sendRawTransaction` | Submits a signed transaction. | | `eth_getCode` | Returns contract bytecode. | | `eth_getStorageAt` | Returns storage value at a given position. | | `eth_getLogs` | Returns logs matching a filter. | | `eth_chainId` | Returns the chain ID. | ### Flashblocks support The `"pending"` block tag is supported across applicable methods when flashblocks are enabled. See [Flashblocks RPC](/integration-guides/flashblocks-rpc/) for details on querying preconfirmed state. ## Troubleshooting ### Common issues | Issue | Cause | Solution | |-------|-------|----------| | `429 Too Many Requests` | Rate limit exceeded on public endpoint. | Reduce request frequency or run your own node. | | Connection refused on port 8545 | Node HTTP RPC not enabled. | Start the node with `--http` and `--http.addr 0.0.0.0`. | | Empty response for `eth_getLogs` | Block range too large. | Reduce the `fromBlock`/`toBlock` range (max ~2000 blocks per query). | | Wrong chain ID | Connected to wrong network. | Verify the RPC URL matches the intended network. | | `nonce too low` | Transaction nonce already used. | Use `"pending"` tag with `eth_getTransactionCount` for the latest nonce. | ## Further reading - [Flashblocks RPC](/integration-guides/flashblocks-rpc/) — query preconfirmed state with the `"pending"` tag. - [Transaction Pool](/integration-guides/txpool/) — inspect and manage the txpool. - [Metering RPC](/integration-guides/metering-rpc/) — resource metering API. - [Node configuration](/node-operations/configuration/) — detailed node configuration options. - [Monitoring](/node-operations/monitoring/) — observability and metrics. --- # Flashblocks RPC Source: https://basehub.org/integration-guides/flashblocks-rpc/ Description: Read preconfirmed Base state and stream sub-block updates over JSON-RPC and WebSocket. import CodeColumns from '../../../components/CodeColumns.astro'; Flashblocks are sub-block preconfirmations produced every 200ms on Base. Read preconfirmed balances, nonces, receipts, and block data through standard JSON-RPC, or stream every flashblock as it lands. ## Overview A single Base block (produced every 2 seconds) is divided into ten **flashblocks** streamed at 200ms intervals. Each flashblock is a delta containing new transactions and the resulting state changes. The Flashblocks RPC exposes this preconfirmed state through the standard Ethereum JSON-RPC interface by supporting the `"pending"` block tag. ``` Block N (2s) ├── Flashblock 0 (0ms) ├── Flashblock 1 (200ms) ├── Flashblock 2 (400ms) ├── Flashblock 3 (600ms) ├── Flashblock 4 (800ms) ├── Flashblock 5 (1000ms) ├── Flashblock 6 (1200ms) ├── Flashblock 7 (1400ms) ├── Flashblock 8 (1600ms) └── Flashblock 9 (1800ms) Block N+1 (2s) └── ... ``` ## Querying preconfirmed state Pass `"pending"` to any supported JSON-RPC method to read the latest preconfirmed state. The same call against `"latest"` returns the last sealed block. ### Check an account balance
`eth_getBalance` with the `"pending"` tag returns the balance reflecting every transaction included in the most recent flashblock — usually within 200ms of the user's submission. The hex `result` is the balance in wei.
```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getBalance", "params": ["0xYourAddress", "pending"], "id": 1, "jsonrpc": "2.0" }' # { # "id": 1, # "jsonrpc": "2.0", # "result": "0x1bc16d674ec80000" # } ```
### Get a transaction receipt
After submitting a transaction, poll `eth_getTransactionReceipt` immediately — no need to wait for the next sealed block. A preconfirmed receipt is identifiable by its zero `blockHash`. Once the parent block seals, the same receipt comes back with a real block hash.
```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getTransactionReceipt", "params": ["0xYourTxHash"], "id": 1, "jsonrpc": "2.0" }' # { # "result": { # "transactionHash": "0x...", # "blockHash": "0x000...000", # "blockNumber": "0x123", # "status": "0x1", # "gasUsed": "0x5208", # "logs": [] # } # } ```
### Get the pending block
`eth_getBlockByNumber` with `"pending"` returns the in-progress block including every transaction landed in flashblocks so far. Pass `true` as the second parameter for full transaction objects, `false` for hashes only.
```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getBlockByNumber", "params": ["pending", true], "id": 1, "jsonrpc": "2.0" }' ```
### Get the pending nonce
`eth_getTransactionCount` against `"pending"` returns a nonce that already accounts for transactions sitting in flashblocks. This avoids nonce collisions when an account submits many transactions in rapid succession.
```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "eth_getTransactionCount", "params": ["0xYourAddress", "pending"], "id": 1, "jsonrpc": "2.0" }' # { # "result": "0x5" # } ```
## Using ethers.js or viem ### ethers.js
Pass `"pending"` as the block tag to any read method to get preconfirmed values. For receipts, poll `getTransactionReceipt` on a 200ms interval — that matches the flashblock cadence.
```javascript import { JsonRpcProvider } from "ethers"; const provider = new JsonRpcProvider("https://your-base-rpc-endpoint"); const balance = await provider.getBalance("0xYourAddress", "pending"); const nonce = await provider.getTransactionCount("0xYourAddress", "pending"); async function waitForFlashblockReceipt(txHash, intervalMs = 200) { while (true) { const receipt = await provider.getTransactionReceipt(txHash); if (receipt) return receipt; await new Promise((r) => setTimeout(r, intervalMs)); } } ```
### viem
viem accepts `blockTag: "pending"` on every read method. Receipts return as soon as the transaction is included in a flashblock.
```typescript import { createPublicClient, http } from "viem"; import { base } from "viem/chains"; const client = createPublicClient({ chain: base, transport: http("https://your-base-rpc-endpoint"), }); const balance = await client.getBalance({ address: "0xYourAddress", blockTag: "pending", }); const nonce = await client.getTransactionCount({ address: "0xYourAddress", blockTag: "pending", }); const receipt = await client.getTransactionReceipt({ hash: "0xYourTxHash", }); ```
## WebSocket streaming For real-time updates, connect to the WebSocket endpoint and subscribe to `flashblocks_v1`. Each flashblock arrives as it is produced — five times per second. ### Subscribing
Open a WebSocket, send an `eth_subscribe` request with the `flashblocks_v1` topic, and handle each `eth_subscription` message as it arrives. `flashblock.diff` carries the new transactions and state changes since the previous flashblock; `flashblock.index` runs from 0 to 9 within each parent block.
```javascript import WebSocket from "ws"; const ws = new WebSocket("wss://your-base-ws-endpoint"); ws.on("open", () => { ws.send( JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["flashblocks_v1"], }) ); }); ws.on("message", (data) => { const msg = JSON.parse(data); if (msg.method === "eth_subscription") { const flashblock = msg.params.result; console.log("Index:", flashblock.index); console.log("Txs:", flashblock.diff.transactions?.length ?? 0); } }); ```
### Flashblock payload structure Each streamed flashblock contains: | Field | Description | |-------|-------------| | `payload_id` | Identifier for the parent payload (block being built). | | `index` | Flashblock index within the current block (0, 1, 2, ...). | | `base` | Present only on index 0. Contains the base execution payload. | | `diff` | Delta of transactions, receipts, and state changes since the previous flashblock. | | `metadata` | Additional metadata, including the flashblock access list if enabled. | ## Error handling and fallback ### Automatic fallback When the `"pending"` tag is used but no preconfirmed data is available — for example, during sequencer downtime or between blocks — the RPC falls back to the `"latest"` confirmed state. That means: - Applications do not need special error handling for missing flashblock state. - Results are always consistent: either preconfirmed or latest confirmed. - The caller cannot distinguish a "pending equals latest" response from a fallback, so applications should not assume the data is fresher than the latest block. ### Error responses Standard JSON-RPC error codes apply: | Scenario | Behavior | |----------|----------| | Invalid method parameters | Standard JSON-RPC error response with error code and message. | | Transaction not found | `null` result (not an error). | | Block not found | `null` result (not an error). | | Flashblocks disabled | Falls back to standard RPC behavior. No error is returned. | ### Detecting preconfirmed vs. finalized
A preconfirmed receipt can be identified by its `blockHash`: - **Preconfirmed** — `blockHash` is the zero hash. - **Finalized** — `blockHash` is a real block hash.
```javascript function isPreconfirmed(receipt) { return ( receipt.blockHash === "0x0000000000000000000000000000000000000000000000000000000000000000" ); } ```
## Further reading - [Flashblocks specification](/specifications/flashblocks/) — full RPC method reference with parameter and return type details. - [Access lists specification](/specifications/access-lists/) — the FAL spec that accompanies flashblocks. - [Flashblocks pipeline](/architecture/flashblocks-pipeline/) — how flashblocks are produced and streamed internally. --- # Metering RPC Source: https://basehub.org/integration-guides/metering-rpc/ Description: Simulate transactions to return gas estimates, resource breakdowns, and builder metering metadata. The Metering API simulates a transaction against current state and returns gas estimates, per-resource consumption, and the metering metadata the builder uses to price and prioritize inclusion. ## What Metering Provides Traditional gas estimation (`eth_estimateGas`) returns a single number. The Metering API goes further by simulating transactions against the current state and reporting: - **Gas consumption** -- total gas used, broken down by execution phase. - **Resource usage** -- compute, storage reads, storage writes, and memory allocation. - **Metering metadata** -- information used by the block builder to price and prioritize transactions. This is particularly useful for: - Block builders that need to meter transactions for optimal block packing. - Applications that want to display detailed cost breakdowns to users. - MEV searchers estimating transaction costs against live state. ## Relevant Crates The metering system is implemented across two crates in the `base/base` workspace: | Crate | Description | |-------|-------------| | `base-metering` | Core metering logic -- simulates transactions and computes resource consumption metrics. | | `base-builder-metering` | Builder-specific metering integration -- connects metering to the block building pipeline. | These crates live under [`crates/builder/`](https://github.com/base/base/tree/main/crates/builder) in the repository. ## RPC Endpoints ### `base_estimateMeteredGas` Simulates a transaction and returns a detailed metering report. #### Parameters | Name | Type | Description | |------|------|-------------| | `transaction` | `Object` | Transaction call object (`from`, `to`, `data`, `value`, `gas`, etc.). | | `blockNumber` | `String` | Block tag or number. Use `"latest"` or `"pending"` for current state. | #### Returns `Object` -- Metering result containing gas estimates and resource breakdown. #### Example ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "base_estimateMeteredGas", "params": [ { "from": "0xSenderAddress", "to": "0xContractAddress", "data": "0xCalldata" }, "latest" ], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "gasUsed": "0x1a4c0", "gasLimit": "0x1e848", "computeUnits": "0x3200", "storageReads": "0x5", "storageWrites": "0x2", "success": true } } ``` ### `base_getMeteringConfig` Returns the current metering configuration parameters used by the builder. #### Parameters None. #### Returns `Object` -- Metering configuration including resource weights and limits. #### Example ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "base_getMeteringConfig", "params": [], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "computeWeight": 1, "storageReadWeight": 2, "storageWriteWeight": 5, "maxComputeUnitsPerBlock": "0x989680", "maxStorageReadsPerBlock": "0x493e0", "maxStorageWritesPerBlock": "0x186a0" } } ``` ## Usage with ethers.js ```javascript import { JsonRpcProvider } from "ethers"; const provider = new JsonRpcProvider("https://your-base-rpc-endpoint"); // Estimate metered gas for a transaction async function estimateMeteredGas(tx) { const result = await provider.send("base_estimateMeteredGas", [ { from: tx.from, to: tx.to, data: tx.data, value: tx.value ?? "0x0", }, "latest", ]); console.log("Gas used:", parseInt(result.gasUsed, 16)); console.log("Compute units:", parseInt(result.computeUnits, 16)); console.log("Storage reads:", parseInt(result.storageReads, 16)); console.log("Storage writes:", parseInt(result.storageWrites, 16)); console.log("Success:", result.success); return result; } ``` ## Usage with viem ```typescript import { createPublicClient, http } from "viem"; import { base } from "viem/chains"; const client = createPublicClient({ chain: base, transport: http("https://your-base-rpc-endpoint"), }); // Estimate metered gas const result = await client.request({ method: "base_estimateMeteredGas" as any, params: [ { from: "0xSenderAddress", to: "0xContractAddress", data: "0xCalldata", }, "latest", ], }); ``` ## How Metering Works The metering pipeline operates as follows: 1. **Transaction submission** -- a transaction (or call object) is submitted to the metering RPC. 2. **State simulation** -- the transaction is executed against the current (or specified) state using the EVM, with metering instrumentation enabled. 3. **Resource accounting** -- during simulation, the metering engine tracks compute cycles, storage operations, and memory usage. 4. **Result assembly** -- the raw resource counts are combined with the current metering configuration (weights) to produce the final metering report. 5. **Builder integration** -- when used by the block builder, metering results feed into transaction ordering and block packing decisions. ``` Transaction │ ▼ ┌──────────────────┐ │ EVM Simulation │ │ (base-metering) │ └────────┬─────────┘ │ ▼ ┌──────────────────────────┐ │ Resource Accounting │ │ compute, storage, memory │ └────────┬─────────────────┘ │ ▼ ┌──────────────────────────────┐ │ Metering Report │ │ gas, compute units, storage │ └──────────────────────────────┘ ``` ## Error Handling | Scenario | Behavior | |----------|----------| | Transaction reverts during simulation | `success: false` in the result; gas and resource fields still populated. | | Invalid transaction parameters | Standard JSON-RPC error response. | | State unavailable for requested block | JSON-RPC error with appropriate code. | ## Further Reading - [Crate Reference](/crates/overview/) -- overview of all crate groups, including the builder crates. - [Execution Pipeline](/architecture/execution-pipeline/) -- how the EVM and state management work. --- # Transaction Pool Source: https://basehub.org/integration-guides/txpool/ Description: Inspect and monitor the Base txpool through RPC extensions and tracing instrumentation. The Base transaction pool holds pending transactions until the builder includes them in a block. The `base/base` repository ships RPC extensions and tracing instrumentation for inspecting pool contents and monitoring transaction lifecycle events. ## Relevant Crates | Crate | Description | |-------|-------------| | `base-txpool-rpc` | Txpool RPC namespace extensions -- provides JSON-RPC methods for querying pool contents. | | `base-txpool-tracing` | Tracing instrumentation for txpool operations -- emits structured logs and metrics for transaction lifecycle events. | These crates live under [`crates/execution/`](https://github.com/base/base/tree/main/crates/execution) in the repository. ## How Transactions Flow Through the Pool ``` User / Application │ ▼ ┌─────────────────┐ │ JSON-RPC │ eth_sendRawTransaction │ (ingress-rpc) │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Validation │ Nonce check, balance check, gas price check │ │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Transaction │ Pending pool (ready to include) │ Pool │ Queued pool (future nonce gap) └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Block Builder │ Selects transactions for next block/flashblock │ │ └─────────────────┘ ``` 1. **Ingress** -- transactions arrive via `eth_sendRawTransaction` through the ingress RPC. 2. **Validation** -- each transaction is validated: signature verification, nonce ordering, sufficient balance for gas and value, gas price meets the minimum. 3. **Pool insertion** -- valid transactions enter the pool. Transactions with the next expected nonce go into the **pending** sub-pool (ready for inclusion). Transactions with a future nonce go into the **queued** sub-pool (waiting for the gap to be filled). 4. **Promotion** -- when a pending transaction is included in a block or flashblock, queued transactions from the same sender may be promoted to pending if the nonce gap is closed. 5. **Selection** -- the block builder pulls transactions from the pending pool, ordered by effective gas price, for inclusion in the next flashblock delta. ## RPC Methods The `base-txpool-rpc` crate extends the standard txpool namespace with the following methods. ### `txpool_status` Returns the number of transactions in each sub-pool. ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "txpool_status", "params": [], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "pending": "0x12", "queued": "0x3" } } ``` ### `txpool_content` Returns all transactions in the pool, grouped by sender address and nonce. ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "txpool_content", "params": [], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "pending": { "0xSenderAddress": { "0": { "hash": "0x...", "gasPrice": "0x...", "nonce": "0x0", "..." : "..." }, "1": { "hash": "0x...", "gasPrice": "0x...", "nonce": "0x1", "..." : "..." } } }, "queued": { "0xAnotherSender": { "5": { "hash": "0x...", "gasPrice": "0x...", "nonce": "0x5", "..." : "..." } } } } } ``` ### `txpool_inspect` Returns a text summary of all transactions in the pool (lighter-weight than `txpool_content`). ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "txpool_inspect", "params": [], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "pending": { "0xSenderAddress": { "0": "0xRecipient: 0 wei + 21000 gas x 1000000000 wei" } }, "queued": {} } } ``` ### `txpool_contentFrom` Returns transactions from a specific sender address. ```bash curl -X POST https://your-base-rpc-endpoint \ -H "Content-Type: application/json" \ -d '{ "method": "txpool_contentFrom", "params": ["0xSenderAddress"], "id": 1, "jsonrpc": "2.0" }' ``` ```json { "id": 1, "jsonrpc": "2.0", "result": { "pending": { "0": { "hash": "0x...", "nonce": "0x0", "..." : "..." } }, "queued": {} } } ``` ## Tracing and Observability The `base-txpool-tracing` crate instruments the transaction pool with structured tracing events. When enabled, it emits events for: | Event | Description | |-------|-------------| | `txpool.insert` | A transaction was inserted into the pool. Includes sender, nonce, hash, gas price. | | `txpool.promote` | A queued transaction was promoted to pending (nonce gap filled). | | `txpool.discard` | A transaction was removed from the pool (replaced, expired, or invalidated). | | `txpool.replace` | A transaction was replaced by a new one with the same nonce and higher gas price. | | `txpool.evict` | A transaction was evicted due to pool size limits. | These events can be consumed by any `tracing` subscriber -- written to stdout, sent to a logging backend, or exported as OpenTelemetry spans. ### Enabling Tracing Tracing is configured via the node's logging configuration. For example, to enable debug-level txpool tracing: ```bash RUST_LOG=base_txpool_tracing=debug base-reth-node \ --http \ --http.api eth,txpool ``` ## Practical Tips - **Nonce management** -- use `eth_getTransactionCount` with the `"pending"` tag (see [Flashblocks RPC](/integration-guides/flashblocks-rpc/)) to get the latest nonce including flashblock-preconfirmed transactions. This avoids nonce collisions when submitting transactions rapidly. - **Gas price monitoring** -- query `txpool_status` periodically to gauge pool congestion. A high pending count relative to block throughput suggests rising base fees. - **Transaction replacement** -- to speed up or cancel a pending transaction, submit a new transaction with the same nonce and a higher gas price (typically at least 10% higher to be accepted by the pool). - **Pool limits** -- the pool has configurable size limits. When full, the lowest-priced transactions are evicted first. Monitor `txpool.evict` tracing events to detect when your transactions might be at risk. ## Further Reading - [Crate Reference](/crates/overview/) -- overview of all crate groups, including the execution crates. - [Flashblocks RPC](/integration-guides/flashblocks-rpc/) -- using the `"pending"` tag for preconfirmed nonces and balances. - [Connecting to Base](/integration-guides/connecting/) -- network endpoints and chain parameters. --- # Base-Solana Bridge Source: https://basehub.org/introduction/base-solana-bridge/ Description: Bridge tokens and arbitrary messages between Base and Solana with the official Base-Solana bridge contracts and programs. import { Aside, Card, CardGrid } from '@astrojs/starlight/components'; The Base-Solana bridge moves tokens and arbitrary messages in both directions between Base and Solana, with optional contract-call execution at the destination. The bridge supports: - **Token transfers** between Base and Solana - **Arbitrary cross-chain messages** - **Combined flows** that pair a transfer with a destination contract call - **Wrapped token deployments** on either chain This page covers the bridge architecture, production contract addresses, and reference implementation patterns. ## How it works ### On Base The Base bridge contract locks or burns outgoing tokens and mints or unlocks incoming tokens. It also assembles outgoing messages into Merkle trees. Validators sign the Merkle root every ~300 finalized blocks and relay it to Solana, where users prove their message exists in the tree to complete the transfer. **Key smart contracts:** - [**Bridge Contract**](https://github.com/base/bridge/blob/main/base/src/Bridge.sol) — handles outgoing transfers - [**CrossChainERC20**](https://github.com/base/bridge/blob/main/base/src/CrossChainERC20.sol) — mintable/burnable tokens for cross-chain transfers - [**BridgeValidator**](https://github.com/base/bridge/blob/main/base/src/BridgeValidator.sol) — verifies messages with oracle signatures - [**Twin Contract**](https://github.com/base/bridge/blob/main/base/src/Twin.sol) — your personal smart contract on Base for executing calls forwarded from Solana ### On Solana The Solana bridge program manages token transfers by locking or burning the asset and emitting events. For messages, validators forward those events to Base, where execution runs through your Twin contract. **Key programs (Solana Mainnet-Beta):** - [**Bridge Program**](https://github.com/base/bridge/blob/main/solana/programs/bridge) — handles outgoing transfers and message commitments - [**Base Relayer Program**](https://github.com/base/bridge/blob/main/solana/programs/base_relayer) — optional relayer that can prepay gas on Base The full repository lives at [github.com/base/bridge](https://github.com/base/bridge). ## Bridging flows Push-based flow with an optional relayer for instant execution on Base. See [Solana to Base](#solana-to-base). Proof-based burn-and-unlock flow with full custody. See [Base to Solana](#base-to-solana). Production terminal UI for bridging plus contract calls. See [Terminally Onchain example](#terminally-onchain-example). ## Solana to Base **Flow:** Lock SOL/SPL → (optional) pay for relay → validators approve → mint and execute on Base. The Solana to Base direction uses a pull-based model with three steps: 1. **Initiate the bridge on Solana.** Lock your SOL or native SPL token in a Solana vault. 2. **Wait for validator pre-approval.** Validators verify and approve the bridge message. 3. **Execute on Base.** The approved message runs on Base to mint SOL and execute any attached calls. Reference scripts for auto-relay, token wrapping, and CLI utilities live in the `scripts/` directory of the official repository: [Solana to Base CLI scripts](https://github.com/base/bridge/tree/main/scripts/src/commands/sol/bridge). ### Auto-relay example This sample bridges SOL with auto-relay enabled. ```typescript solToBaseWithAutoRelay/index.ts expandable // Configure const TO = "0x8c1a617bdb47342f9c17ac8750e0b070c372c721"; // Base address const AMOUNT = 0.001; // SOL amount // Bridge SOL with auto-relay const ixs = [ getBridgeSolInstruction({ payer, from: payer, solVault: solVaultAddress, bridge: bridgeAccountAddress, outgoingMessage, to: toBytes(TO), remoteToken: toBytes("0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD"), // SOL on Base amount: BigInt(AMOUNT * 10**9), }), await buildPayForRelayIx(RELAYER_PROGRAM_ID, outgoingMessage, payer) ]; await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer); ``` Full handler: [Solana to Base relay script](https://github.com/base/bridge/blob/main/scripts/src/commands/sol/bridge/solana-to-base/bridge-sol.handler.ts). ### Wrap custom SPL tokens The example above bridges native SOL. To bridge custom SPL tokens, deploy wrapped ERC20 representations on Base via `CrossChainERC20Factory`. Reference: [token wrapping example](https://github.com/base/bridge/blob/main/scripts/src/commands/sol/bridge/solana-to-base/wrap-token.handler.ts). ```typescript wrapSolTokenOnBase/index.ts expandable // Deploy wrapped token on Base const mintBytes32 = getBase58Codec().encode(SOLANA_SPL_MINT_ADDRESS).toHex(); await client.writeContract({ address: "0x58207331CBF8Af87BB6453b610E6579D9878e4EA", // Factory abi: TokenFactory, functionName: "deploy", args: [`0x${mintBytes32}`, "Token Name", "SYMBOL", 9], }); ``` ## Base to Solana **Flow:** Burn ERC20 SOL on Base → wait for finalization → generate Merkle proof → execute on Solana. The return path burns the wrapped token on Base, waits for the message to become provable, then submits the proof on Solana to release the native asset. This route preserves full custody and requires a prover. Reference: [Base to Solana example](https://github.com/base/bridge/blob/main/scripts/src/internal/sol/base.ts). ```typescript bridgeSolFromBaseToSolana/index.ts expandable // Step 1: Burn SOL on Base const transfer = { localToken: "0xC5b9112382f3c87AFE8e1A28fa52452aF81085AD", // SOL (on Base) remoteToken: pubkeyToBytes32(SOL_ADDRESS), to: pubkeyToBytes32(solanaAddress), remoteAmount: BigInt(AMOUNT * 10**9), }; const txHash = await client.writeContract({ address: "0xB2068ECCDb908902C76E3f965c1712a9cF64171E", // Bridge abi: Bridge, functionName: "bridgeToken", args: [transfer, []], }); // Step 2: Wait for finalization const isProvable = await isBridgeMessageProvable(txHash); // Step 3: Generate proof const { event, rawProof } = await generateProof(txHash, baseBlockNumber); // Step 4: Execute on Solana const proveIx = getProveMessageInstruction({ nonce: event.message.nonce, sender: toBytes(event.message.sender), data: toBytes(event.message.data), proof: rawProof.map(e => toBytes(e)), messageHash: toBytes(event.messageHash), }); const relayIx = getRelayMessageInstruction({ message: messagePda }); await buildAndSendTransaction(SOLANA_RPC_URL, [proveIx, relayIx], payer); ``` ## Utilities The repository ships utilities for converting between Solana and Base address formats, loading the Solana CLI keypair for signing, and building/sending Solana transactions: [scripts/src/commands](https://github.com/base/bridge/tree/main/scripts/src/commands). ### Address conversion Convert a Solana pubkey to bytes32 for Base contracts: ```typescript example.ts // Convert Solana pubkey to bytes32 for Base contracts import { pubkeyToBytes32 } from "./utils/pubkeyToBytes32"; const bytes32Address = pubkeyToBytes32(solanaAddress); ``` ### Keypair management Load the Solana CLI keypair for signing: ```typescript example.ts import { getSolanaCliConfigKeypairSigner } from "./utils/keypair"; const payer = await getSolanaCliConfigKeypairSigner(); ``` ### Transaction building Build and submit a Solana transaction: ```typescript example.ts import { buildAndSendTransaction } from "./utils/buildAndSendTransaction"; const signature = await buildAndSendTransaction(SOLANA_RPC_URL, ixs, payer); ``` ## Terminally Onchain example Repository: [github.com/base/sol2base](https://github.com/base/sol2base). [Terminally Onchain](https://terminallyonchain.com/) is a production Next.js app that exposes the bridge through a command terminal UI. Users connect a Solana wallet and run commands that bridge value and call a contract on Base: ```bash bridge 0.0001 sol 0xYourTwin --call-contract 0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82 \ --call-selector "transfer(address,uint256)" \ --call-args 0x0000000000000000000000000000000000000000 100000000000000 ``` The workflow: 1. **Parse command.** The terminal parser resolves the asset, destination, and optional Base call (selector, args, value). 2. **Stage bridge.** `queueBridge` validates SPL overrides, ABI-encodes the Base call via `encodeFunctionData`, and stages relay overrides. 3. **Execute.** `solanaBridge.bridge()` resolves the destination (ENS or Basename), confirms balances, and calls `realBridgeImplementation` to sign and submit the Solana transaction. 4. **Relay and call.** When relay gas is prepaid, the Base Relayer immediately runs the attached call from the user's Twin contract once ERC20 SOL is minted. Key implementation references: - `src/lib/bridge.ts` — asset resolution (including mint addresses), environment-aware RPC connections, and call attachment - `src/lib/realBridgeImplementation.ts` — builds Solana transactions with `PayForRelay` plus `bridge_sol`/`bridge_spl` instructions, using per-environment PDAs and gas-fee receivers - `src/components/MainContent.tsx` — terminal UI with command staging, log viewer, and ABI encoding for arbitrary Base calls - `src/components/WalletConnection.tsx` — fetches the deterministic Twin address on Base Mainnet/Sepolia for the connected Solana wallet ### Run the terminal locally ```bash Terminal git clone https://github.com/base/sol2base.git cd sol2base npm install --legacy-peer-deps # Configure env (RPC URLs, relayer addresses, CDP API keys, etc.) cp env.template .env.local npm run dev # defaults to http://localhost:3000 ``` ## Contract addresses ### Base Mainnet ```json { "Bridge": "0x3eff766C76a1be2Ce1aCF2B69c78bCae257D5188", "BridgeValidator": "0xAF24c1c24Ff3BF1e6D882518120fC25442d6794B", "CrossChainERC20Factory": "0xDD56781d0509650f8C2981231B6C917f2d5d7dF2", "SOL": "0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82" } ``` ### Solana Mainnet ```json { "BridgeProgram": "HNCne2FkVaNghhjKXapxJzPaBvAKDG1Ge3gqhZyfVWLM", "BaseRelayerProgram": "g1et5VenhfJHJwsdJsDbxWZuotD5H4iELNG61kS4fb9" } ``` ### Base Sepolia ```json { "Bridge": "0x01824a90d32A69022DdAEcC6C5C14Ed08dB4EB9B", "BridgeValidator": "0xa80C07DF38fB1A5b3E6a4f4FAAB71E7a056a4EC7", "CrossChainERC20Factory": "0x488EB7F7cb2568e31595D48cb26F63963Cc7565D", "SOL": "0xCace0c896714DaF7098FFD8CC54aFCFe0338b4BC", "FLYWHEEL_ADDRESS": "0x00000F14AD09382841DB481403D1775ADeE1179F", "BRIDGE_CAMPAIGN_ADDRESS": "0xE2AD1C34382410C30d826B019A0B3700F5c4e6c9" } ``` ### Solana Devnet ```json { "BridgeProgram": "7c6mteAcTXaQ1MFBCrnuzoZVTTAEfZwa6wgy4bqX3KXC", "BaseRelayerProgram": "56MBBEYAtQAdjT4e1NzHD8XaoyRSTvfgbSVVcEcHj51H", "GasFeeReceiver": "AFs1LCbodhvwpgX3u3URLsud6R1XMSaMiQ5LtXw4GKYT" } ``` ## Resources Source code, contracts, programs, and scripts: [github.com/base/bridge](https://github.com/base/bridge). Inspect Solana mainnet-beta transactions at [explorer.solana.com](https://explorer.solana.com/). Inspect Base Mainnet transactions at [basescan.org](https://basescan.org/). Get help from the Base community at [base.org/discord](https://base.org/discord). --- # Connecting to Base Source: https://basehub.org/introduction/connecting-to-base/ Description: Network parameters, RPC endpoints, and wallet setup for connecting to Base Mainnet and Base Sepolia testnet. import { Aside } from '@astrojs/starlight/components'; Connect to Base Mainnet or the Sepolia testnet using the public RPC endpoints, then configure any EVM-compatible wallet to use the network. ## Base Mainnet | Name | Value | | :--- | :--- | | Network Name | Base Mainnet | | Description | The public mainnet for Base. | | RPC Endpoint | [https://mainnet.base.org](https://mainnet.base.org) — rate limited, not for production. | | Flashblocks RPC Endpoint | [https://mainnet-preconf.base.org](https://mainnet-preconf.base.org) — rate limited, not for production. | | Chain ID | 8453 | | Currency Symbol | ETH | | Block Explorer | [https://base.blockscout.com/](https://base.blockscout.com/) | ## Base Testnet (Sepolia) | Name | Value | | :--- | :--- | | Network Name | Base Sepolia | | Description | The public testnet for Base. | | RPC Endpoint | [https://sepolia.base.org](https://sepolia.base.org) — rate limited, not for production. | | Flashblocks RPC Endpoint | [https://sepolia-preconf.base.org](https://sepolia-preconf.base.org) — rate limited, not for production. | | Chain ID | 84532 | | Currency Symbol | ETH | | Block Explorer | [https://sepolia-explorer.base.org](https://sepolia-explorer.base.org) | ## Using Base with your wallet ### Coinbase Wallet The [Coinbase Wallet](https://chrome.google.com/webstore/detail/coinbase-wallet-extension/hnfanknocfeofbddgcijnmhnfnkdnaad?hl=en) browser extension supports Base out of the box. To switch to Base in Coinbase Wallet: 1. Open the Coinbase Wallet extension and sign in. 2. Connect to an app from within the wallet. 3. Click the network icon in the top right to open the network menu. 4. Choose **Base**. The active network now points at Base. ### Other wallets Base works as a custom network in any EVM-compatible wallet, including [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn). #### MetaMask To add Base as a custom network in MetaMask: 1. Open the MetaMask extension. 2. Click the network dropdown at the top of the extension. 3. Click **Add network**. 4. Click **Add a network manually**. 5. Enter the Base mainnet values: | Name | Value | | :--- | :--- | | Network Name | Base Mainnet | | Description | The public mainnet for Base. | | RPC Endpoint | [https://mainnet.base.org](https://mainnet.base.org) | | Chain ID | 8453 | | Currency Symbol | ETH | | Block Explorer | [https://base.blockscout.com/](https://base.blockscout.com/) | 6. Click **Save**. Base now appears in the network dropdown. ## Testnet #### Coinbase Wallet supports Base Sepolia by default To use Base Sepolia in Coinbase Wallet: 1. Open the Coinbase Wallet extension and sign in. 2. Connect to an app. 3. Click the network icon at the top right. 4. Click **More networks**. 5. Open the **Testnets** tab. 6. Choose **Base Sepolia**. The active network is now the Base testnet. #### Other wallets Base Sepolia can also be added as a custom network in any EVM-compatible wallet such as [MetaMask](https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn). #### MetaMask To add Base Sepolia in MetaMask: 1. Open the MetaMask extension. 2. Click the network dropdown. 3. Click **Add network**. 4. Click **Add a network manually**. 5. Enter the Base Sepolia values: | Name | Value | | :--- | :--- | | Network Name | Base Sepolia | | RPC Endpoint | [https://sepolia.base.org](https://sepolia.base.org) | | Chain ID | 84532 | | Currency Symbol | ETH | | Block Explorer | [https://sepolia-explorer.base.org](https://sepolia-explorer.base.org) | 6. Click **Save**. Base Sepolia is now selectable from the network dropdown. --- # Deploy on Base Source: https://basehub.org/introduction/deploy-on-base/ Description: Set up Foundry, configure RPC and key management, and deploy a smart contract to Base Sepolia in a single workflow. import { Aside } from '@astrojs/starlight/components'; Set up a Foundry project, point it at Base, and deploy a contract to Base Sepolia in a single end-to-end workflow. ## What you build By the end of this guide you will have: - A Foundry-based development environment configured for Base - A smart contract deployed to Base Sepolia - A connection pattern your frontend can reuse against your contracts ## Set up your development environment 1. Create a project directory. ```bash mkdir my-base-project && cd my-base-project ``` 2. Install Foundry, the framework used throughout this guide. ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` The installer pulls Foundry and updates it to the latest release. 3. Initialize a Solidity project. ```bash forge init ``` The Foundry project is ready. The starter contract sits at `src/Counter.sol` — this guide uses that contract as the deployment target. ## Configure Foundry for Base Deploying to Base requires two pieces: 1. An RPC connection to the network 2. A funded private key for signing the deployment transaction ### 1. Set up your RPC connection 1. Create a `.env` file at the project root. 2. Add the Base RPC URLs. ```bash BASE_RPC_URL="https://mainnet.base.org" BASE_SEPOLIA_RPC_URL="https://sepolia.base.org" ``` 3. Load the variables into your shell. ```bash source .env ``` ### 2. Secure your private key 1. Import your private key into Foundry's encrypted keystore. ```bash cast wallet import deployer --interactive ``` 2. Paste the key when prompted and set a password. The encrypted key is stored at `~/.foundry/keystores`, which is excluded from git. ## Deploy your contract With the environment configured, deploy to Base Sepolia. 1. (Optional) Run a dry run first to confirm the deployment is well-formed. ```bash forge create ./src/Counter.sol:Counter --rpc-url $BASE_SEPOLIA_RPC_URL --account deployer ``` This simulates the deploy without broadcasting. You will see the transaction details and ABI; nothing is written onchain. 2. Add `--broadcast` to actually deploy. ```bash forge create ./src/Counter.sol:Counter --rpc-url $BASE_SEPOLIA_RPC_URL --account deployer --broadcast ``` The contract argument follows the format `:`. 3. A successful deploy prints output similar to: ``` Deployer: 0x... Deployed to: 0x... <-- YOUR CONTRACT ADDRESS Transaction hash: 0x... ``` 4. Save the deployed address into `.env`. ```bash COUNTER_CONTRACT_ADDRESS="0x..." ``` Replace `0x...` with the address from the output. 5. Reload the variables. ```bash source .env ``` ### Verify your deployment To confirm the contract is live: 1. Look up the transaction hash on [Sepolia Basescan](https://sepolia.basescan.org/). 2. Read the contract directly with `cast`: ```bash cast call $COUNTER_CONTRACT_ADDRESS "number()(uint256)" --rpc-url $BASE_SEPOLIA_RPC_URL ``` The call returns the initial value of the Counter's `number` storage slot, which is `0`. The contract is now live on Base Sepolia. ## Next steps - Wire a frontend to your contracts using [wagmi](https://wagmi.sh) or [viem](https://viem.sh). - Dive deeper into Foundry workflows in the [Foundry deployment tutorial](https://docs.base.org/learn/foundry/deploy-with-foundry). --- # Why Base Source: https://basehub.org/introduction/why-base/ Description: Base delivers sub-cent, sub-second transactions on a global, permissionless platform with developer tooling, grants, and built-in distribution. Base is an Ethereum L2 designed for sub-second, sub-cent transactions on a permissionless platform with first-class developer tooling and built-in distribution. ## At a glance - **Open and inexpensive.** Base is a globally accessible network offering 1-second confirmations and transactions that cost less than a cent. - **First-class tooling.** Builders ship onchain experiences across AI, social, media, and entertainment with a mature developer stack. - **Funding for builders.** Base has issued grants to over 1,000 builders, with more on the way. - **Distribution channels.** Apps reach users through official Base distribution surfaces. ## A platform for new applications Base is a global onchain economy of people, builders, and businesses building the next iteration of the open internet. The chain is engineered so developers can: - Concentrate on real user problems - Ship apps that scale globally by default - Onboard new users in a single click - Take payments from anyone, anywhere It is fast, inexpensive, and permissionless — anyone can build on or use applications running on Base. The network has emerged as a hub for new use cases across media, entertainment, social, and AI. [Clanker](https://www.clanker.world), an autonomous AI agent operating on Base, generated more than $13 million in revenue in its first three months. Base is structured so developers retain more of the upside their products create. Conventional app distribution often forces developers to give up 30% of revenue to marketplaces. Those marketplaces can also drive practices that work against users — selling personal data, demanding identity disclosures, or denying access at will. A user in Nairobi, for example, may be locked out of many U.S.-based fintech services entirely. Onchain finance changes that math. Apps such as [Moonwell](https://moonwell.fi) make financial services available directly from a phone, anywhere in the world. A user in Nairobi gets the same access as a user in the United States, opening up opportunities that did not previously exist. ## Developer tooling Developers pick Base for: - An always-on, internet-speed payment rail with global reach - Per-transaction costs that are typically below a cent - A deep developer toolchain Apps on Base ship in hours instead of days or weeks, thanks to a broad set of tools — many of them open source. Two builders working from a garage can again credibly create a major business. Tools that make this practical: - **Base Account.** Onboard users quickly and securely without seed phrases. - **Coinbase Developer Platform.** Specialized services for onchain builders, including free node software, sponsored transactions, and tooling to refine your app. - **Basenames.** More than human-readable addresses — Basenames are the front door to a builder's onchain profile. - **Verifications.** Power tailored experiences for users with verified credentials. --- # Contract Addresses Source: https://basehub.org/network/base-contracts/ Description: Canonical L1 and L2 contract and admin addresses for Base Mainnet and Base Sepolia, with explorer links and notes on unused OP Stack contracts. The tables below list the canonical contract and admin addresses for Base Mainnet and Base Sepolia, with links to the corresponding block explorer. ## L2 contract addresses ### Base Mainnet | Name | Address | | :---------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | WETH9 | [0x4200000000000000000000000000000000000006](https://basescan.org/address/0x4200000000000000000000000000000000000006) | | L2CrossDomainMessenger | [0x4200000000000000000000000000000000000007](https://basescan.org/address/0x4200000000000000000000000000000000000007) | | L2StandardBridge | [0x4200000000000000000000000000000000000010](https://basescan.org/address/0x4200000000000000000000000000000000000010) | | SequencerFeeVault | [0x4200000000000000000000000000000000000011](https://basescan.org/address/0x4200000000000000000000000000000000000011) | | OptimismMintableERC20Factory | [0xF10122D428B4bc8A9d050D06a2037259b4c4B83B](https://basescan.org/address/0xF10122D428B4bc8A9d050D06a2037259b4c4B83B) | | GasPriceOracle | [0x420000000000000000000000000000000000000F](https://basescan.org/address/0x420000000000000000000000000000000000000F) | | L1Block | [0x4200000000000000000000000000000000000015](https://basescan.org/address/0x4200000000000000000000000000000000000015) | | L2ToL1MessagePasser | [0x4200000000000000000000000000000000000016](https://basescan.org/address/0x4200000000000000000000000000000000000016) | | L2ERC721Bridge | [0x4200000000000000000000000000000000000014](https://basescan.org/address/0x4200000000000000000000000000000000000014) | | OptimismMintableERC721Factory | [0x4200000000000000000000000000000000000017](https://basescan.org/address/0x4200000000000000000000000000000000000017) | | ProxyAdmin | [0x4200000000000000000000000000000000000018](https://basescan.org/address/0x4200000000000000000000000000000000000018) | | BaseFeeVault | [0x4200000000000000000000000000000000000019](https://basescan.org/address/0x4200000000000000000000000000000000000019) | | L1FeeVault | [0x420000000000000000000000000000000000001a](https://basescan.org/address/0x420000000000000000000000000000000000001a) | | EAS | [0x4200000000000000000000000000000000000021](https://basescan.org/address/0x4200000000000000000000000000000000000021) | | EASSchemaRegistry | [0x4200000000000000000000000000000000000020](https://basescan.org/address/0x4200000000000000000000000000000000000020) | | LegacyERC20ETH | [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://basescan.org/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) | ### Base Sepolia | Name | Address | | :---------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | | WETH9 | [0x4200000000000000000000000000000000000006](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000006) | | L2CrossDomainMessenger | [0x4200000000000000000000000000000000000007](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000007) | | L2StandardBridge | [0x4200000000000000000000000000000000000010](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000010) | | SequencerFeeVault | [0x4200000000000000000000000000000000000011](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000011) | | OptimismMintableERC20Factory | [0x4200000000000000000000000000000000000012](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000012) | | GasPriceOracle | [0x420000000000000000000000000000000000000F](https://sepolia.basescan.org/address/0x420000000000000000000000000000000000000F) | | L1Block | [0x4200000000000000000000000000000000000015](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000015) | | L2ToL1MessagePasser | [0x4200000000000000000000000000000000000016](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000016) | | L2ERC721Bridge | [0x4200000000000000000000000000000000000014](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000014) | | OptimismMintableERC721Factory | [0x4200000000000000000000000000000000000017](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000017) | | ProxyAdmin | [0x4200000000000000000000000000000000000018](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000018) | | BaseFeeVault | [0x4200000000000000000000000000000000000019](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000019) | | L1FeeVault | [0x420000000000000000000000000000000000001a](https://sepolia.basescan.org/address/0x420000000000000000000000000000000000001a) | | EAS | [0x4200000000000000000000000000000000000021](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000021) | | EASSchemaRegistry | [0x4200000000000000000000000000000000000020](https://sepolia.basescan.org/address/0x4200000000000000000000000000000000000020) | | LegacyERC20ETH | [0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000](https://sepolia.basescan.org/address/0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000) | L2 predeploy addresses are identical across mainnet and testnet. ## L1 contract addresses ### Ethereum Mainnet | Name | Address | | :--------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | AddressManager | [0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2](https://etherscan.io/address/0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2) | | AnchorStateRegistryProxy | [0x909f6cf47ed12f010A796527f562bFc26C7F4E72](https://etherscan.io/address/0x909f6cf47ed12f010A796527f562bFc26C7F4E72) | | DelayedWETHProxy (FDG) | [0x2453c1216e49704d84ea98a4dacd95738f2fc8ec](https://etherscan.io/address/0x2453c1216e49704d84ea98a4dacd95738f2fc8ec) | | DelayedWETHProxy (PDG) | [0x64ae5250958cdeb83f6b61f913b5ac6ebe8efd4d](https://etherscan.io/address/0x64ae5250958cdeb83f6b61f913b5ac6ebe8efd4d) | | DisputeGameFactoryProxy | [0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e](https://etherscan.io/address/0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e) | | FaultDisputeGame | [0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499](https://etherscan.io/address/0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499) | | FaultDisputeGame (Kona) | [0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499](https://etherscan.io/address/0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499) | | L1CrossDomainMessenger | [0x866E82a600A1414e583f7F13623F1aC5d58b0Afa](https://etherscan.io/address/0x866E82a600A1414e583f7F13623F1aC5d58b0Afa) | | L1ERC721Bridge | [0x608d94945A64503E642E6370Ec598e519a2C1E53](https://etherscan.io/address/0x608d94945A64503E642E6370Ec598e519a2C1E53) | | L1StandardBridge | [0x3154Cf16ccdb4C6d922629664174b904d80F2C35](https://etherscan.io/address/0x3154Cf16ccdb4C6d922629664174b904d80F2C35) | | MIPS | [0x6463dEE3828677F6270d83d45408044fc5eDB908](https://etherscan.io/address/0x6463dEE3828677F6270d83d45408044fc5eDB908) | | OptimismMintableERC20Factory | [0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84](https://etherscan.io/address/0x05cc379EBD9B30BbA19C6fA282AB29218EC61D84) | | OptimismPortal | [0x49048044D57e1C92A77f79988d21Fa8fAF74E97e](https://etherscan.io/address/0x49048044D57e1C92A77f79988d21Fa8fAF74E97e) | | PermissionedDisputeGame | [0x58bf355C5d4EdFc723eF89d99582ECCfd143266A](https://etherscan.io/address/0x58bf355C5d4EdFc723eF89d99582ECCfd143266A) | | PreimageOracle | [0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3](https://etherscan.io/address/0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3) | | ProxyAdmin | [0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E](https://etherscan.io/address/0x0475cBCAebd9CE8AfA5025828d5b98DFb67E059E) | | SystemConfig | [0x73a79Fab69143498Ed3712e519A88a918e1f4072](https://etherscan.io/address/0x73a79Fab69143498Ed3712e519A88a918e1f4072) | | SystemDictator | [0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557](https://etherscan.io/address/0x1fE3fdd1F0193Dd657C0a9AAC37314D6B479E557) | #### Unused OP Stack addresses The [OP Stack SDK](https://stack.optimism.io/docs/build/sdk/#unneeded-contract-addresses) requires the following addresses to be set even though Base does not use them. Pass the zero address for each: - `StateCommitmentChain` - `CanonicalTransactionChain` - `BondManager` ### Ethereum Sepolia | Name | Address | | :----------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | | AddressManager | [0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B](https://sepolia.etherscan.io/address/0x709c2B8ef4A9feFc629A8a2C1AF424Dc5BD6ad1B) | | AggregateVerifier (Multiproof) | [0x498313fB340CD5055c5568546364008299A47517](https://sepolia.etherscan.io/address/0x498313fB340CD5055c5568546364008299A47517) | | AnchorStateRegistryProxy | [0x2fF5cC82dBf333Ea30D8ee462178ab1707315355](https://sepolia.etherscan.io/address/0x2fF5cC82dBf333Ea30D8ee462178ab1707315355) | | DelayedWETHProxy (FDG) | [0xd3683e4947A7769603Ab6418eC02f000CE3cF30b](https://sepolia.etherscan.io/address/0xd3683e4947A7769603Ab6418eC02f000CE3cF30b) | | DelayedWETHProxy (Multiproof) | [0xD6e2d9D4f1f8865AC983eE848983fb1979429914](https://sepolia.etherscan.io/address/0xD6e2d9D4f1f8865AC983eE848983fb1979429914) | | DelayedWETHProxy (PDG) | [0x32cE910d9C6c8F78dc6779c1499aB05F281A054e](https://sepolia.etherscan.io/address/0x32cE910d9C6c8F78dc6779c1499aB05F281A054e) | | DisputeGameFactoryProxy | [0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1](https://sepolia.etherscan.io/address/0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1) | | FaultDisputeGame | [0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499](https://sepolia.etherscan.io/address/0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499) | | FaultDisputeGame (Kona) | [0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499](https://sepolia.etherscan.io/address/0x6dDBa09bc4cCB0D6Ca9Fc5350580f74165707499) | | L1CrossDomainMessenger | [0xC34855F4De64F1840e5686e64278da901e261f20](https://sepolia.etherscan.io/address/0xC34855F4De64F1840e5686e64278da901e261f20) | | L1ERC721Bridge | [0x21eFD066e581FA55Ef105170Cc04d74386a09190](https://sepolia.etherscan.io/address/0x21eFD066e581FA55Ef105170Cc04d74386a09190) | | L1StandardBridge | [0xfd0Bf71F60660E2f608ed56e1659C450eB113120](https://sepolia.etherscan.io/address/0xfd0Bf71F60660E2f608ed56e1659C450eB113120) | | MIPS | [0x6463dEE3828677F6270d83d45408044fc5eDB908](https://sepolia.etherscan.io/address/0x6463dEE3828677F6270d83d45408044fc5eDB908) | | NitroEnclaveVerifier | [0x7D8EA07DB94128DBEe66bAfa3eBAa9668B413d72](https://sepolia.etherscan.io/address/0x7D8EA07DB94128DBEe66bAfa3eBAa9668B413d72) | | OptimismMintableERC20Factory | [0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37](https://sepolia.etherscan.io/address/0xb1efB9650aD6d0CC1ed3Ac4a0B7f1D5732696D37) | | OptimismPortal | [0x49f53e41452C74589E85cA1677426Ba426459e85](https://sepolia.etherscan.io/address/0x49f53e41452C74589E85cA1677426Ba426459e85) | | PermissionedDisputeGame | [0x58bf355C5d4EdFc723eF89d99582ECCfd143266A](https://sepolia.etherscan.io/address/0x58bf355C5d4EdFc723eF89d99582ECCfd143266A) | | PreimageOracle | [0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3](https://sepolia.etherscan.io/address/0x1fb8cdFc6831fc866Ed9C51aF8817Da5c287aDD3) | | ProxyAdmin | [0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3](https://sepolia.etherscan.io/address/0x0389E59Aa0a41E4A413Ae70f0008e76CAA34b1F3) | | SystemConfig | [0xf272670eb55e895584501d564AfEB048bEd26194](https://sepolia.etherscan.io/address/0xf272670eb55e895584501d564AfEB048bEd26194) | | TEEProverRegistryProxy | [0xf0d7E15673fBA052e83d7f2b26BB6071E86b972e](https://sepolia.etherscan.io/address/0xf0d7E15673fBA052e83d7f2b26BB6071E86b972e) | | TEEVerifier | [0x92F6dD3501E51B8b20C77b959becaaebeB210e17](https://sepolia.etherscan.io/address/0x92F6dD3501E51B8b20C77b959becaaebeB210e17) | ## Base admin addresses ### Base Mainnet | Admin Role | Address | Type of Key | | :--------------------- | :-------------------------------------------------------------------------------------------------------------------- | :----------------------------------- | | Batch Sender | [0x5050f69a9786f081509234f1a7f4684b5e5b76c9](https://etherscan.io/address/0x5050f69a9786f081509234f1a7f4684b5e5b76c9) | EOA managed by Coinbase Technologies | | Batch Inbox | [0xff00000000000000000000000000000000008453](https://etherscan.io/address/0xff00000000000000000000000000000000008453) | EOA (with no known private key) | | Output Proposer | [0x642229f238fb9de03374be34b0ed8d9de80752c5](https://etherscan.io/address/0x642229f238fb9de03374be34b0ed8d9de80752c5) | EOA managed by Coinbase Technologies | | Proxy Admin Owner (L1) | [0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c](https://etherscan.io/address/0x7bB41C3008B3f03FE483B28b8DB90e19Cf07595c) | Gnosis Safe | | Challenger | [0x8Ca1E12404d16373Aef756179B185F27b2994F3a](https://etherscan.io/address/0x8Ca1E12404d16373Aef756179B185F27b2994F3a) | EOA managed by Coinbase Technologies | | SystemConfig owner | [0x14536667Cd30e52C0b458BaACcB9faDA7046E056](https://etherscan.io/address/0x14536667Cd30e52C0b458BaACcB9faDA7046E056) | Gnosis Safe | | Guardian | [0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2](https://etherscan.io/address/0x09f7150D8c019BeF34450d6920f6B3608ceFdAf2) | Gnosis Safe | ### Base Sepolia | Admin Role | Address | Type of Key | | :--------------------- | :---------------------------------------------------------------------------------------------------------------------------- | :----------------------------------- | | Batch Sender | [0x6CDEbe940BC0F26850285cacA097C11c33103E47](https://sepolia.etherscan.io/address/0x6CDEbe940BC0F26850285cacA097C11c33103E47) | EOA managed by Coinbase Technologies | | Batch Inbox | [0xff00000000000000000000000000000000084532](https://sepolia.etherscan.io/address/0xff00000000000000000000000000000000084532) | EOA (with no known private key) | | Output Proposer | [0xdb84125f2f4229c81c579f41bc129c71b174eb58](https://sepolia.etherscan.io/address/0xdb84125f2f4229c81c579f41bc129c71b174eb58) | EOA managed by Coinbase Technologies | | Proxy Admin Owner (L1) | [0x0fe884546476dDd290eC46318785046ef68a0BA9](https://sepolia.etherscan.io/address/0x0fe884546476dDd290eC46318785046ef68a0BA9) | Gnosis Safe | | Challenger | [0xadc09b63a3ac57a2ce86d946617a18df9db029a1](https://sepolia.etherscan.io/address/0xadc09b63a3ac57a2ce86d946617a18df9db029a1) | EOA managed by Coinbase Technologies | | SystemConfig owner | [0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f](https://sepolia.etherscan.io/address/0x5dfEB066334B67355A15dc9b67317fD2a2e1f77f) | Gnosis Safe | | Guardian | [0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E](https://sepolia.etherscan.io/address/0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E) | EOA managed by Coinbase Technologies | --- # Block Building Source: https://basehub.org/network/block-building/ Description: How Base orders transactions inside blocks, including Flashblocks 200ms preconfirmations and the per-transaction gas cap enforced by the mempool. import { Aside } from '@astrojs/starlight/components'; Base block ordering is independent of the user-facing experience: the sequencer can build sub-block updates without exposing them, and the underlying ordering rules continue to apply. ## Current configuration | Network | Active configuration | Upcoming | |--------------|---------------------------------------------------------------------------------------|----------| | Base Mainnet | [Flashblocks](#flashblocks) and [per-transaction gas maximum](#per-transaction-gas-maximum) | | | Base Sepolia | [Flashblocks](#flashblocks) and [per-transaction gas maximum](#per-transaction-gas-maximum) | | The [configuration changelog](/network/configuration-changelog/) records every change to block building parameters and other network-level settings. ## Flashblocks Blocks are produced by [op-rbuilder](https://github.com/flashbots/op-rbuilder), with a fresh priority fee auction running every **200ms**. The auction shortens effective block times from 2 seconds to 200 milliseconds via preconfirmations. Three properties distinguish Flashblocks from vanilla ordering: 1. **Timing** — The builder emits one Flashblock every 200ms, sealing a slice of the eventual block. Once a Flashblock is broadcast, its ordering is final; later transactions with higher priority fees cannot displace transactions already committed to an earlier Flashblock. 2. **Gas allocation** — Each Flashblock has a progressively larger gas budget. Flashblock 1 may consume up to one tenth of the block gas limit, Flashblock 2 up to two tenths, and so on through Flashblock 10, which may use the full limit. | Flashblock | Available gas | |------------|---------------| | 1 | ~14M gas (1/10) | | 2 | ~28M gas (2/10) | | 3 | ~42M gas (3/10) | | ... | ... | | 10 | ~140M gas (full) | 3. **Dynamic mempool** — The builder keeps accepting new transactions while a Flashblock is being assembled. This minimizes inclusion latency, but transactions are ordered by fee *at the moment of selection*, not against every transaction that arrived during the 200ms window. A high-fee transaction that arrives late may appear after a lower-fee transaction that was already committed. ## Per-transaction gas maximum Base caps individual transactions at **25,000,000 gas**. Any transaction submitting a higher gas limit is **rejected by the mempool before it can be included**. `eth_sendTransaction` and `eth_sendRawTransaction` return a JSON-RPC error such as `exceeds maximum per-transaction gas limit`. This cap does **not** alter the block gas limit or the block validity rules. Fusaka's [EIP 7825](https://eips.ethereum.org/EIPS/eip-7825) **will** modify the block validity conditions and lower the per-transaction gas cap to 16,777,216 gas (2^24). OP Stack chains are expected to adopt the change around January 2026. Smart-account bundlers must size their bundles to remain under the cap. ## Vanilla ordering Under the legacy configuration, [op-geth](https://github.com/ethereum-optimism/op-geth) builds a block every 2 seconds and orders transactions inside the block by priority fee. See the [reference implementation](https://github.com/ethereum-optimism/op-geth/blob/optimism/miner/worker.go#L627). --- # Bridges Source: https://basehub.org/network/bridges/ Description: Third-party bridges for moving assets between Base and Ethereum, Solana, or Bitcoin, plus contract addresses for the Base-Solana bridge. import { Aside, Card, CardGrid } from '@astrojs/starlight/components'; Base supports asset transfers from Ethereum, Solana, and Bitcoin through a network of third-party bridge providers. The Base-operated bridge at bridge.base.org is no longer available; the providers below cover the same asset flows. For frequently asked questions, jump to the [FAQ](#faq). ## Ethereum and Base ### Superbridge Superbridge moves ETH and other supported assets between Ethereum mainnet (L1) and Base. Supported networks: - [Base Mainnet](https://superbridge.app/base) - [Base Sepolia (Testnet)](https://superbridge.app/base-sepolia) ### Brid.gg Brid.gg also bridges ETH and supported assets between Ethereum mainnet (L1) and Base. Supported networks: - [Base Mainnet](https://brid.gg/base) - [Base Sepolia (Testnet)](https://testnet.brid.gg/base-sepolia) ### Programmatic bridging from Ethereum The [sample code repository](https://github.com/base-org/guides/tree/main/bridge/native) demonstrates how to bridge ETH and ERC-20s from Ethereum to Base. ### Token issuers If you have an ERC-20 deployed on Ethereum and want to make it bridgeable to Base, follow the [bridge-an-L1-token guide](https://docs.base.org/base-chain/quickstart/bridge-token). It walks through deploying via the standard bridge contracts and adding your token to the Superchain token list. ## Solana and Base The Base-Solana bridge supports two-way token transfers and arbitrary message passing between Base and Solana. Capabilities include: - Transferring SOL and SPL tokens to and from Base - Sending arbitrary cross-chain messages - Deploying wrapped tokens on either side - Optional auto-relay for instant settlement [Complete bridge guide with code samples and contract addresses](/introduction/base-solana-bridge/) [Production terminal UI for bridging and contract calls](https://terminallyonchain.com/) ### Contract addresses | Network | Contract | Address | |---------|----------|---------| | Base Mainnet | Bridge | `0x3eff766C76a1be2Ce1aCF2B69c78bCae257D5188` | | Base Mainnet | SOL Token | `0x311935Cd80B76769bF2ecC9D8Ab7635b2139cf82` | | Solana Mainnet | Bridge Program | `HNCne2FkVaNghhjKXapxJzPaBvAKDG1Ge3gqhZyfVWLM` | ## Bitcoin to Base ### Garden Garden is a fast, non-custodial bridge that moves BTC and supported assets from Ethereum, Solana, and other chains directly to Base. Supported networks: - [Base Mainnet](https://app.garden.finance/?output-chain=base&output-asset=cbBTC) - [Base Sepolia (Testnet)](https://testnet.garden.finance/?output-chain=base_sepolia&output-asset=USDT) ## Disclaimer Coinbase Technologies, Inc. links to these independent providers for convenience and accepts no responsibility for their operations. Any interaction with a listed provider is solely between you and that provider. ## FAQ **Can I still use the bridge on bridge.base.org?** No. The bridge at bridge.base.org has been deprecated. **I used bridge.base.org previously — how do I find my deposit or withdrawal?** Look up your transaction on one of the Superchain Bridges listed above. **Why was the bridge on bridge.base.org deprecated?** Base is committed to decentralization and the Superchain. Handing bridging off to community-operated providers strengthens censorship resistance and reduces single points of control. **Who runs the Superchain Bridges (Garden.finance, Superbridge.app, Brid.gg)?** Superchain Bridges are operated by independent third parties, not by Coinbase Technologies, Inc. ("Coinbase"). Coinbase does not control or operate them and assumes no responsibility for their performance. Each provider may require you to accept its terms of service and privacy policy — review them before using a bridge. Listing a bridge here is not an endorsement. **How does the Base-Solana bridge work?** A validator set verifies cross-chain messages. Bridging from Solana to Base locks the source tokens on Solana and mints wrapped tokens on Base. Bridging from Base to Solana burns the wrapped tokens on Base and releases the originals on Solana. The [full bridge documentation](/introduction/base-solana-bridge/) covers the implementation. **Where can I get help if I have a question or problem?** The [Base Discord](https://base.org/discord) is staffed around the clock. Open a ticket in the `#general-support` channel for assistance. --- # Configuration Changelog Source: https://basehub.org/network/configuration-changelog/ Description: A dated log of block-building, fee, and other network parameter changes for Base Mainnet and Base Sepolia. The tables below track network parameter changes — block building, fees, and other operational settings — for Base Mainnet and Base Sepolia. ## Base Mainnet | Date | Change | Documentation | |------|--------|---------------| | February 19, 2026 | Increased Minimum Base Fee to 5,000,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | February 4, 2026 | Increased EIP-1559 Denominator to 125 | [EIP-1559 Fee Parameters](/network/network-fees/#eip-1559-fee-parameters) | | February 2, 2026 | Increased Minimum Base Fee to 2,000,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | January 22, 2026 | Increased Minimum Base Fee to 1,000,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | December 18, 2025 | Increased Minimum Base Fee to 500,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | December 4, 2025 | Enabled Minimum Base Fee (200,000 wei) | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | September 17, 2025 | Enabled Per-Transaction Gas Maximum | [Per-Transaction Gas Maximum](/network/block-building/#per-transaction-gas-maximum) | | September 11, 2025 | Ended testing Per-Transaction Gas Maximum | [Per-Transaction Gas Maximum](/network/block-building/#per-transaction-gas-maximum) | | September 10, 2025 | Started testing Per-Transaction Gas Maximum | [Per-Transaction Gas Maximum](/network/block-building/#per-transaction-gas-maximum) | | July 7, 2025 | Enabled Flashblocks | [Flashblocks](/network/block-building/#flashblocks) | | May 15, 2025 | Ended testing Flashblocks | [Flashblocks](/network/block-building/#flashblocks) | | May 15, 2025 | Started testing Flashblocks | [Flashblocks](/network/block-building/#flashblocks) | ## Base Sepolia | Date | Change | Documentation | |------|--------|---------------| | February 19, 2026 | Increased Minimum Base Fee to 5,000,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | February 10, 2026 | Increased EIP-1559 Denominator to 125 | [EIP-1559 Fee Parameters](/network/network-fees/#eip-1559-fee-parameters) | | February 10, 2026 | Increased Minimum Base Fee to 2,000,000 wei | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | November 20, 2025 | Enabled Minimum Base Fee (200,000 wei) | [Minimum Base Fee](/network/network-fees/#minimum-base-fee) | | September 3, 2025 | Enabled Per-Transaction Gas Maximum | [Per-Transaction Gas Maximum](/network/block-building/#per-transaction-gas-maximum) | | February 25, 2025 | Enabled Flashblocks | [Flashblocks](/network/block-building/#flashblocks) | --- # Differences Between Ethereum and Base Source: https://basehub.org/network/diffs-ethereum-base/ Description: Short reference to the protocol-level differences developers encounter when moving apps from Ethereum to Base. Base targets full compatibility with Ethereum, so most apps port over without modification. A small set of behavioral differences are worth knowing before you ship. The notable differences are: - [Flashblocks](/flashblocks/app-integration/) - [Minimum base fee](/network/network-fees/#minimum-base-fee) - [Bridging](https://docs.optimism.io/stack/differences#bridging) - [Opcodes](https://docs.optimism.io/stack/differences#opcodes) - [Address aliasing](https://docs.optimism.io/stack/differences#address-aliasing) - [Transaction costs](https://docs.optimism.io/stack/differences#transaction-fees) - [Chain finality](https://docs.optimism.io/stack/differences#chain-finality) --- # Ecosystem Contracts Source: https://basehub.org/network/ecosystem-contracts/ Description: Deployed addresses for Multicall3, Uniswap v2, and Uniswap v3 on Base Mainnet and Base Sepolia, with block explorer links. import { Aside } from '@astrojs/starlight/components'; The tables below list deployment addresses for widely used onchain apps on Base. ## Base Mainnet ### Multicall3 | Contract | Address | | :--------- | :-------------------------------------------------------------------------------------------------------------------- | | Multicall3 | [0xcA11bde05977b3631167028862bE2a173976CA11](https://basescan.org/address/0xcA11bde05977b3631167028862bE2a173976CA11) | ### Uniswap v3 | Contract | Address | | :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | `Permit2` | [0x000000000022D473030F116dDEE9F6B43aC78BA3](https://basescan.org/address/0x000000000022D473030F116dDEE9F6B43aC78BA3) | | `universal router` | [0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC](https://basescan.org/address/0x198EF79F1F515F02dFE9e3115eD9fC07183f02fC) | | `v3CoreFactory` | [0x33128a8fC17869897dcE68Ed026d694621f6FDfD](https://basescan.org/address/0x33128a8fC17869897dcE68Ed026d694621f6FDfD) | | `multicall` | [0x091e99cb1C49331a94dD62755D168E941AbD0693](https://basescan.org/address/0x091e99cb1C49331a94dD62755D168E941AbD0693) | | `proxyAdmin` | [0x3334d83e224aF5ef9C2E7DDA7c7C98Efd9621fA9](https://basescan.org/address/0x3334d83e224aF5ef9C2E7DDA7c7C98Efd9621fA9) | | `tickLens` | [0x0CdeE061c75D43c82520eD998C23ac2991c9ac6d](https://basescan.org/address/0x0CdeE061c75D43c82520eD998C23ac2991c9ac6d) | | `nftDescriptor` | [0xF9d1077fd35670d4ACbD27af82652a8d84577d9F](https://basescan.org/address/0xF9d1077fd35670d4ACbD27af82652a8d84577d9F) | | `nonfungibleTokenPositionDescriptor` | [0x4f225937EDc33EFD6109c4ceF7b560B2D6401009](https://basescan.org/address/0x4f225937EDc33EFD6109c4ceF7b560B2D6401009) | | `descriptorProxy` | [0x4615C383F85D0a2BbED973d83ccecf5CB7121463](https://basescan.org/address/0x4615C383F85D0a2BbED973d83ccecf5CB7121463) | | `nonfungibleTokenPositionManager` | [0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1](https://basescan.org/address/0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1) | | `v3Migrator` | [0x23cF10b1ee3AdfCA73B0eF17C07F7577e7ACd2d7](https://basescan.org/address/0x23cF10b1ee3AdfCA73B0eF17C07F7577e7ACd2d7) | | `v3Staker` | [0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1](https://basescan.org/address/0x42bE4D6527829FeFA1493e1fb9F3676d2425C3C1) | | `quoterV2` | [0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a](https://basescan.org/address/0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a) | | `swapRouter` | [0x2626664c2603336E57B271c5C0b26F421741e481](https://basescan.org/address/0x2626664c2603336E57B271c5C0b26F421741e481) | ### Uniswap v2 | Contract | Address | | :-------- | :-------------------------------------------------------------------------------------------------------------------- | | `Factory` | [0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6](https://basescan.org/address/0x8909Dc15e40173Ff4699343b6eB8132c65e18eC6) | | `Router` | [0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24](https://basescan.org/address/0x4752ba5dbc23f44d87826276bf6fd6b1c372ad24) | ## Base Sepolia ### Multicall3 | Contract | Address | | :--------- | :---------------------------------------------------------------------------------------------------------------------------- | | Multicall3 | [0xcA11bde05977b3631167028862bE2a173976CA11](https://sepolia.basescan.org/address/0xcA11bde05977b3631167028862bE2a173976CA11) | ### Uniswap v3 | Contract | Address | | :----------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | | `Permit2` | [0x000000000022d473030f116ddee9f6b43ac78ba3](https://sepolia.basescan.org/address/0x000000000022d473030f116ddee9f6b43ac78ba3) | | `universal router` | [0x050E797f3625EC8785265e1d9BDd4799b97528A1](https://sepolia.basescan.org/address/0x050E797f3625EC8785265e1d9BDd4799b97528A1) | | `v3CoreFactory` | [0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24](https://sepolia.basescan.org/address/0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24) | | `multicall` | [0xd867e273eAbD6c853fCd0Ca0bFB6a3aE6491d2C1](https://sepolia.basescan.org/address/0xd867e273eAbD6c853fCd0Ca0bFB6a3aE6491d2C1) | | `proxyAdmin` | [0xD7303474Baca835743B54D73799688990f24a79D](https://sepolia.basescan.org/address/0xD7303474Baca835743B54D73799688990f24a79D) | | `tickLens` | [0xedf6066a2b290C185783862C7F4776A2C8077AD1](https://sepolia.basescan.org/address/0xedf6066a2b290C185783862C7F4776A2C8077AD1) | | `nftDescriptor` | [0x4e0caFF1Df1cCd7CF782FDdeD77f020699B57f1a](https://sepolia.basescan.org/address/0x4e0caFF1Df1cCd7CF782FDdeD77f020699B57f1a) | | `nonfungibleTokenPositionDescriptor` | [0xd7c6e867591608D32Fe476d0DbDc95d0cf584c8F](https://sepolia.basescan.org/address/0xd7c6e867591608D32Fe476d0DbDc95d0cf584c8F) | | `nonfungibleTokenPositionManager` | [0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2](https://sepolia.basescan.org/address/0x27F971cb582BF9E50F397e4d29a5C7A34f11faA2) | | `v3Migrator` | [0xCbf8b7f80800bd4888Fbc7bf1713B80FE4E23E10](https://sepolia.basescan.org/address/0xCbf8b7f80800bd4888Fbc7bf1713B80FE4E23E10) | | `v3Staker` | [0x62725F55f50bdE240aCa3e740D47298CAc8d57D5](https://sepolia.basescan.org/address/0x62725F55f50bdE240aCa3e740D47298CAc8d57D5) | | `quoterV2` | [0xC5290058841028F1614F3A6F0F5816cAd0df5E27](https://sepolia.basescan.org/address/0xC5290058841028F1614F3A6F0F5816cAd0df5E27) | | `swapRouter` | [0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4](https://sepolia.basescan.org/address/0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4) | #### Testnet interfaces ### Uniswap v2 | Contract | Address | | :-------- | :---------------------------------------------------------------------------------------------------------------------------- | | `Factory` | [0x7Ae58f10f7849cA6F5fB71b7f45CB416c9204b1e](https://sepolia.basescan.org/address/0x7Ae58f10f7849cA6F5fB71b7f45CB416c9204b1e) | | `Router` | [0x1689E7B1F10000AE47eBfE339a4f69dECd19F602](https://sepolia.basescan.org/address/0x1689E7B1F10000AE47eBfE339a4f69dECd19F602) | --- # Network Faucets Source: https://basehub.org/network/network-faucets/ Description: Testnet ETH faucets for Base Sepolia from Coinbase Developer Platform, Alchemy, QuickNode, Chainstack, and other providers. import { Aside } from '@astrojs/starlight/components'; Multiple providers dispense free Base Sepolia testnet ETH (and a few support mainnet drips for contract deployment). Supported assets, claim limits, and authentication requirements vary by provider. ## Coinbase Developer Platform The [Coinbase Developer Platform Faucet](https://portal.cdp.coinbase.com/products/faucet) hands out up to 0.1 testnet ETH per 24 hours on Base Sepolia, and also drips USDC, EURC, and cbBTC. ## thirdweb The [thirdweb Faucet](https://thirdweb.com/base-sepolia-testnet) provides free Base Sepolia ETH with a single claim per 24 hours. ## Alchemy The [Alchemy Faucet](https://basefaucet.com/) requires a free Alchemy account and dispenses Base Sepolia testnet ETH. ## Bware Labs The [Bware Labs Faucet](https://bwarelabs.com/faucets) requires no registration and dispenses Base Sepolia ETH. ## Chainstack The [Chainstack Faucet](https://faucet.chainstack.com/) drips Base ETH against your Chainstack platform API key. ## ethfaucet.com [ethfaucet.com](https://ethfaucet.com/networks/base) provides free Base Sepolia testnet ETH and small mainnet drips for contract deployment. The faucet is operated by [BringID](https://www.bringid.org/). ## QuickNode The [QuickNode Faucet](https://faucet.quicknode.com/drip) is a multi-chain faucet that dispenses Base Sepolia testnet ETH. ## LearnWeb3 The [LearnWeb3 Faucet](https://learnweb3.io/faucets/base_sepolia) is a multi-chain faucet that dispenses Base Sepolia testnet ETH. ## Ethereum Ecosystem The [Base Sepolia Faucet](https://www.ethereum-ecosystem.com/faucets/base-sepolia) is operated by [Ethereum Ecosystem](https://www.ethereum-ecosystem.com) and requires no login. --- # Network Fees Source: https://basehub.org/network/network-fees/ Description: How Base fees are split between L2 execution and L1 data, plus the minimum base fee, EIP-1559 parameters, and the GasPriceOracle. Every Base transaction pays an L2 execution fee plus an L1 security fee — the cost of posting transaction data back to Ethereum. The L1 component is typically the larger of the two. ## How fees work The L1 fee fluctuates with Ethereum gas conditions. If your transaction timing is flexible, submitting during quieter L1 windows (such as weekends) can reduce overall cost. The L2 fee responds to demand on Base itself, using the same EIP-1559 mechanism Ethereum uses. For background, see Coinbase's [EIP-1559 explainer](https://help.coinbase.com/en/coinbase/getting-started/crypto-education/eip-1559). For lower-level details on fee composition, refer to the [OP Stack fee documentation](https://docs.optimism.io/stack/transactions/fees). ## Minimum base fee The [Jovian upgrade](https://docs.optimism.io/notices/upgrade-17) introduced a minimum base fee — a floor that prevents the L2 base fee from collapsing during quiet periods. Base Mainnet's minimum base fee is currently 5,000,000 wei (0.005 gwei). The value may be adjusted over time as data accumulates. As a reference point, a 0.005 gwei base fee costs about $0.002 for a 200,000-gas transaction at an ETH price of $2,000. ### Benefits - **Faster inclusion.** Without a floor, low-activity periods drove the base fee toward zero, and demand spikes could then take a long time to clear the resulting backlog. With a floor, transactions clear faster and most users do not need to manually bump priority fees. - **More predictable fees.** Base fees sit at or near the minimum during normal operation and rise above it during congestion — a surge-pricing pattern. - **Spam mitigation.** Very low fees make spam transactions cheap. The floor prices out that activity while keeping legitimate use affordable. ### Current configuration | Network | Minimum base fee | |--------------|------------------| | Base Mainnet | 5,000,000 wei (0.005 gwei) | | Base Sepolia | 5,000,000 wei (0.005 gwei) | The [configuration changelog](/network/configuration-changelog/) tracks every change to the minimum base fee and other parameters. ## EIP-1559 fee parameters Base uses the OP Stack implementation of EIP-1559 to adjust the L2 base fee in response to demand. Two parameters drive the dynamics. ### Elasticity multiplier The **elasticity multiplier** sets the maximum block gas relative to the target. With elasticity 6, a block can hold up to 6× the target gas, absorbing short demand spikes. ### Base fee change denominator The **base fee change denominator** controls how aggressively the base fee moves between blocks. Larger denominators yield smoother changes; with a denominator of 125, the fee adjusts more gradually than under lower values. ### Maximum rate of change Per-block change is capped at: **Max increase per block = (Elasticity − 1) / Denominator** With the current parameters (Elasticity = 6, Denominator = 125): - Maximum increase per block: (6 − 1) / 125 = **4%** - Minimum time to double the base fee: 18 blocks × 2 seconds = **36 seconds** The smoothed adjustment limits fee volatility during traffic spikes while still letting the network track sustained demand. ### Current configuration | Network | Elasticity | Denominator | Max change per block | |--------------|------------|-------------|----------------------| | Base Mainnet | 6 | 125 | 4% | | Base Sepolia | 6 | 125 | 4% | ## Querying the L1 fee The **GasPriceOracle** predeploy at `0x420000000000000000000000000000000000000F` (see [Contract Addresses](/network/base-contracts/)) lets callers estimate the L1 component before signing. | Method | Returns | | ------ | ------- | | `getL1Fee(bytes)` | Exact L1 fee for a fully serialized (RLP-encoded) transaction | | `getL1FeeUpperBound(uint256 txSize)` | Upper-bound L1 fee estimated from approximate transaction byte length | | `l1BaseFee()` | Current Ethereum L1 base fee as observed by Base | | `blobBaseFee()` | Current EIP-4844 blob base fee | | `baseFeeScalar()` | Scalar applied to the L1 base fee component | | `blobBaseFeeScalar()` | Scalar applied to the blob base fee component | Use `getL1FeeUpperBound` for a quick estimate before the transaction is fully built. Use `getL1Fee` with the complete serialized transaction for an exact pre-sign value. --- # Transaction Finality Source: https://basehub.org/network/transaction-finality/ Description: The four finality stages for Base L2 transactions and the 7-day window that applies only to withdrawals back to Ethereum. import { Aside } from '@astrojs/starlight/components'; Finality is the point at which a Base transaction becomes irreversible. The behavior differs for transactions that update L2 state versus transactions that withdraw funds from Base L2 to Ethereum L1. ## Finality for Base L2 transactions This section covers every Base transaction except withdrawals back to Ethereum. Finality is layered: each successive stage strengthens the security guarantee. ### Flashblock inclusion: ~200ms After about 200 milliseconds, the Base sequencer includes the transaction in a preconfirmation block (a Flashblock). Reorg probability is below 0.001%. Flashblocks reorg less than 0.001% of the time; the [public stats page](https://base.org/stats) records the reorg history. ### L2 block inclusion: ~2s After roughly 2 seconds, the sequencer has packaged the transaction into a sealed L2 block and propagated it to validator nodes. Reorg probability is effectively 0%. Only one Base L2 block has ever reorged, accounting for 0.0000003% of transactions. The data is visible on [Blockscout](https://base.blockscout.com/blocks?tab=reorgs). ### L1 batch inclusion: ~2m After about 2 minutes, a Base batch containing the transaction has been posted to Ethereum. Reorg probability is effectively 0%. No L2 blocks that have been batched to Ethereum L1 have ever reorged. **An Ethereum L1 reorg does not force a Base L2 reorg.** The sequencer and validator nodes maintain a configurable lag from the L1 tip, so typical L1 reorgs have no impact. If a deeper L1 reorg occurs, Base can resubmit batch data without altering the sequenced L2 blocks. ### L1 batch finality: ~20m The Ethereum batch carrying the transaction is older than 2 epochs (64 L1 blocks). Reorg probability is effectively 0%. L2 blocks past L1 batch finality enjoy the same protection as Ethereum-finalized blocks and are practically impossible to reverse. ## Finality for withdrawals **Withdrawals from Base to Ethereum must wait 7 days before funds can be released to the L1 recipient.** The delay enables Base's Fault Proof system to provide strong security for bridged funds. ### What happens during the 7 days When a withdrawal is initiated, the funds are debited from the Base account immediately. A permissionless "proposer" must then provide Ethereum with proof that Base contains the withdrawal. Ethereum cannot independently confirm Base state — they are separate chains — so a 7-day window opens during which a permissionless "challenger" may dispute a proposal it considers malicious. If no challenge arrives, the withdrawal can be proven against the finalized output root and released on L1. If a challenge is filed, the proposer and challenger play the Fault Dispute Game, escalating bonds until a winner emerges. A winning proposer locks in the output root for use in withdrawal proofs; a winning challenger invalidates the output proposal. The system is secure as long as a single honest party participates. Base will always run an honest proposer and an honest challenger. A successful challenge does not reorg the L2 chain. The output proposal is marked invalid, and any withdrawals proven against it must be re-proven against a different, valid output root. ## FAQ **If Ethereum reorgs, will Base reorg?** Almost never. Base resubmits batch data to Ethereum transparently while the L2 chain continues forward. **How long do deposit transactions take to finalize?** Deposits are initiated on Ethereum and are typically picked up by the Base sequencer within 3 minutes. **If a challenger wins a dispute game, will the L2 chain reorg?** No. The challenged output proposal is marked invalid, and any actions that depended on its output root must use a valid replacement. In practice, withdrawals proven against the invalid proposal must be re-proven against a different one. --- # Troubleshooting Transactions Source: https://basehub.org/network/troubleshooting-transactions/ Description: Diagnose pending, rejected, failed, or slow Base transactions, with fixes for fee, nonce, gas, and Flashblocks issues. import { Aside } from '@astrojs/starlight/components'; This guide walks through the common reasons Base transactions stall, fail, or revert, and explains how to fix each one. ## Pending transactions If a transaction is sitting in the mempool longer than expected, work through the following. ### `maxFeePerGas` too low If your `maxFeePerGas` is below the current base fee, the transaction stays pending until the base fee drops below your value. **Fix:** `maxFeePerGas` must cover both the base fee and the priority fee. Because the base fee can move between blocks, set `maxFeePerGas` high enough to remain valid even if the base fee climbs while the transaction is queued. A common formula: ``` maxFeePerGas = baseFee * 2 + maxPriorityFeePerGas ``` This pattern (used by [ethers.js](https://github.com/ethers-io/ethers.js/blob/98c49d091eb84a9146dfba8476f18e4c3e3d1d31/src.ts/providers/abstract-provider.ts#L945-L950)) provides headroom for the base fee to double before the transaction becomes uneconomical. You only pay the actual base fee at inclusion, not the maximum. ### Priority fee too low When the network is busy, transactions compete for inclusion via priority fees. Submitting a low priority fee against active demand delays inclusion. **Fix:** Most users wait for congestion to ease. For time-sensitive transactions, query `eth_maxPriorityFeePerGas` for an estimate that should outbid recent transactions. ### Nonce gap A pending transaction at nonce N blocks every transaction at nonce N+1 or higher, regardless of fees. **Fix:** Wait for the pending transaction, or replace it by submitting a new transaction with the same nonce and a fee bump of at least 10% on both `maxPriorityFeePerGas` and `maxFeePerGas`. ### Nonce too low Submitting a transaction with a nonce that has already been used results in a rejection. **Fix:** Query the next available nonce with `eth_getTransactionCount` and the `pending` tag. ## Rejected transactions ### Gas limit exceeds the maximum Base enforces a [per-transaction gas maximum](/network/block-building/#per-transaction-gas-maximum) of **25,000,000 gas**. Higher limits are rejected by the mempool before inclusion. **Error:** `exceeds maximum per-transaction gas limit` **Fix:** Reduce the gas limit to 25,000,000 or lower. If the transaction genuinely needs more gas, split it into multiple transactions. ## Included but failed transactions ### Out of gas The transaction exhausted its gas during execution. **Fix:** Increase the gas limit. Estimate with `eth_estimateGas` and add a safety margin (for example, 20%) to absorb variability. ### Reverted by contract Contract logic triggered a revert. **Fix:** Inspect the transaction on [Basescan](https://basescan.org) to find the revert reason. Common causes include failed `require` checks, arithmetic errors, and invalid state transitions. ## Slow confirmations ### Confirmation tiers Base produces an L2 block every 2 seconds, while [Flashblocks](/flashblocks/app-integration/) emit preconfirmations every 200ms. | Confirmation level | Time | Description | |--------------------|------|-------------| | Flashblock preconfirmation | ~200ms | Transaction included in a preconfirmation | | L2 block inclusion | ~2s | Transaction included in a sealed L2 block | | L1 batch inclusion | ~2m | Transaction posted to Ethereum | | L1 finality | ~20m | Ethereum batch is finalized | See [Transaction Finality](/network/transaction-finality/) for the full breakdown. ### Use a Flashblocks-aware endpoint For the fastest possible confirmation, point your client at the Flashblocks RPC endpoint: | Network | Flashblocks RPC | |---------|-----------------| | Mainnet | `https://mainnet-preconf.base.org` | | Sepolia | `https://sepolia-preconf.base.org` | These endpoints return receipts as soon as the transaction lands in a Flashblock instead of waiting for the full L2 block. ## Debugging tools - **[Basescan](https://basescan.org)** — Inspect status, logs, and revert reasons - **[Tenderly](https://tenderly.co)** — Simulate and debug transactions - **`eth_call`** — Test contract calls without submitting a transaction - **`eth_estimateGas`** — Estimate gas usage before submitting ## Getting help If you are still stuck, ask in the `#developer-chat` channel on the [Base Discord](https://base.org/discord). --- # Base Azul Upgrade Source: https://basehub.org/node-operations/base-v1-upgrade/ Description: Migrate Base nodes to base-reth-node and base-consensus ahead of the Azul network upgrade, with environment variable mappings and timelines. import { Aside } from '@astrojs/starlight/components'; The Base Azul upgrade activates Osaka features on Base alongside the TEE/ZK proof systems and requires every node operator to migrate to Base-native clients. The full scope is documented in the [Azul specification](https://specs.base.org/upgrades/azul/overview). ## Activation timeline | Network | Date | Timestamp | |---------|------|-----------| | Sepolia | April 20, 2026 18:00 UTC | `1776708000` | | Mainnet | Early May 2026 | TBD | ## Required software | Layer | Software | Version | |-------|----------|---------| | Execution (EL) | [`base-reth-node`](https://github.com/base/base/releases/tag/v0.7.0) | v0.7.0+ | | Consensus (CL) | [`base-consensus`](https://github.com/base/base/releases/tag/v0.7.0) | v0.7.0+ | ## Migrating the execution layer ### From OP Reth If you already run OP Reth via [base/node](https://github.com/base/node), updating to the latest release switches you to `base-reth-node` automatically. Your existing `./reth-data` directory is fully compatible — no resync or snapshot restore required. 1. Stop the node: ```bash docker compose down ``` 2. Pull the latest [base/node](https://github.com/base/node): ```bash git pull origin main ``` 3. Start the node: ```bash docker compose up ``` 4. Confirm the client version with `web3_clientVersion` — the response should include `base` (for example, `reth/v1.11.3-.../base/v0.7.0`). ### From other clients `op-geth` and `nethermind` are no longer supported. You must restart from a clean `base-reth-node` setup. 1. Stop the node: ```bash docker compose down ``` 2. Pull the latest [base/node](https://github.com/base/node): ```bash git pull origin main ``` 3. Remove the existing client data directory (for example, `./geth-data` or `./nethermind-data`). 4. Edit `.env.mainnet` or `.env.sepolia` to match your preferences. 5. Bootstrap from a [Reth snapshot](/node-operations/snapshots/) to skip a full sync. 6. Start the node: ```bash docker compose up ``` ## Migrating the consensus layer Replace `op-node` with `base-consensus` by updating your environment variables. 1. Set `USE_BASE_CONSENSUS=true` in your `.env` file. 2. Update `.env` with the new `BASE_NODE_*` variables (see the mapping below). 3. Restart: ```bash docker compose up ``` 4. Verify: - Tail consensus logs: `docker compose logs -f node` - Confirm sync status: `optimism_syncStatus` continues to work ### Environment variable mapping If you use [base/node](https://github.com/base/node), most variables are already populated in `.env.mainnet` and `.env.sepolia`. If you build from [base/base](https://github.com/base/base), use the table below to translate `op-node` variables to `base-consensus`. Most are optional. Run `base-consensus node --help` for the full list. | `op-node` | `base-consensus` | |-----------|-------------------| | `OP_NODE_NETWORK` | `BASE_NODE_NETWORK` | | `OP_NODE_ROLLUP_CONFIG` | `BASE_NODE_ROLLUP_CONFIG` | | — | `BASE_NODE_LOG_VERBOSITY` | | — | `BASE_NODE_LOG_FORMAT` | | `OP_NODE_L1_ETH_RPC` | `BASE_NODE_L1_ETH_RPC` | | `OP_NODE_L1_BEACON` | `BASE_NODE_L1_BEACON` | | `OP_NODE_L1_TRUST_RPC` | `BASE_NODE_L1_TRUST_RPC` | | `OP_NODE_L2_ENGINE_RPC` | `BASE_NODE_L2_ENGINE_RPC` | | `OP_NODE_L2_ENGINE_AUTH` | `BASE_NODE_L2_ENGINE_AUTH` | | — | `BASE_NODE_L2_ENGINE_AUTH_ENCODED` | | `OP_NODE_P2P_BOOTNODES` | `BASE_NODE_P2P_BOOTNODES` | | `OP_NODE_P2P_LISTEN_IP` | `BASE_NODE_P2P_LISTEN_IP` | | `OP_NODE_P2P_LISTEN_TCP_PORT` | `BASE_NODE_P2P_LISTEN_TCP_PORT` | | `OP_NODE_P2P_LISTEN_UDP_PORT` | `BASE_NODE_P2P_LISTEN_UDP_PORT` | | `OP_NODE_P2P_ADVERTISE_IP` | `BASE_NODE_P2P_ADVERTISE_IP` | | `OP_NODE_P2P_ADVERTISE_TCP` | `BASE_NODE_P2P_ADVERTISE_TCP_PORT` | | `OP_NODE_P2P_ADVERTISE_UDP` | `BASE_NODE_P2P_ADVERTISE_UDP_PORT` | | `OP_NODE_P2P_PRIV_PATH` | `BASE_NODE_P2P_PRIV_PATH` | | `OP_NODE_P2P_PEER_SCORING` | `BASE_NODE_P2P_SCORING` | | `OP_NODE_P2P_PEER_BANNING` | `BASE_NODE_P2P_BAN_PEERS` | | `OP_NODE_P2P_PEER_BANNING_THRESHOLD` | `BASE_NODE_P2P_BAN_THRESHOLD` | | `OP_NODE_P2P_PEER_BANNING_DURATION` | `BASE_NODE_P2P_BAN_DURATION` | | `OP_NODE_METRICS_ENABLED` | `BASE_NODE_METRICS_ENABLED` | | `OP_NODE_METRICS_ADDR` | `BASE_NODE_METRICS_ADDR` | | `OP_NODE_METRICS_PORT` | `BASE_NODE_METRICS_PORT` | | `OP_NODE_RPC_ADDR` | `BASE_NODE_RPC_ADDR` | | `OP_NODE_RPC_PORT` | `BASE_NODE_RPC_PORT` | | `OP_NODE_RPC_ENABLE_ADMIN` | `BASE_NODE_RPC_ENABLE_ADMIN` | | `OP_NODE_RPC_ADMIN_STATE` | `BASE_NODE_RPC_ADMIN_STATE` | | `OP_NODE_SAFEDB_PATH` | `BASE_NODE_SAFEDB_PATH` | | `OP_NODE_SYNCMODE` | — | | `OP_NODE_VERIFIER_L1_CONFS` | — | | `OP_NODE_L2_ENGINE_KIND` | — | | `OP_NODE_L1_RPC_KIND` | — | | `OP_NODE_L1_BEACON_FETCH_ALL_SIDECARS` | — | | `OP_NODE_L1_BEACON_FALLBACKS` | — | | `OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS` | — | | `OP_NODE_P2P_STATIC` | — | | `OP_NODE_P2P_DISABLE` | — | | `OP_NODE_P2P_NAT` | — | ## FAQ - **Do I need to resync?** No, if you already run OP Reth — existing data is compatible. - **What if I'm on `op-geth` or `nethermind`?** Switch to `base-reth-node` and bootstrap from a [Reth snapshot](/node-operations/snapshots/). - **Do OP namespace RPCs still work?** Yes, all existing RPCs remain supported. --- # basectl Source: https://basehub.org/node-operations/basectl/ Description: Configure and inspect Base nodes across mainnet, sepolia, devnet, and custom configs. `basectl` configures and inspects Base nodes across mainnet, Sepolia, devnet, and custom config targets. It ships with the workspace and runs via `cargo` or the `just basectl` recipe. ## Usage ```bash # Build and run with a configuration target cargo run -p basectl --release -- -c ``` Supported configurations: | Config | Network | |--------|---------| | `mainnet` | Base Mainnet | | `sepolia` | Base Sepolia Testnet | | `devnet` | Local Development Network | | `` | Custom configuration file | ## Examples ```bash # Mainnet configuration just basectl mainnet # Sepolia testnet just basectl sepolia # Local devnet just basectl devnet ``` ## Architecture `basectl` is split into two crates: - **`basectl-cli`** ([`crates/infra/basectl`](https://github.com/base/base/tree/main/crates/infra/basectl)) — The library with configuration logic - **`basectl`** ([`bin/basectl`](https://github.com/base/base/tree/main/bin/basectl)) — The binary entry point The binary depends on `basectl-cli`, `clap` for argument parsing, `anyhow` for error handling, and `tokio` for async runtime. --- # Configuration Reference Source: https://basehub.org/node-operations/configuration/ Description: CLI flags, environment variables, and Cargo build profiles for base-reth-node. ## CLI Options The Base Reth Node inherits Reth's comprehensive CLI. View all options: ```bash ./target/release/base-reth-node --help ``` Key option categories: - **Network** — Chain selection, bootnodes, P2P port - **RPC** — HTTP/WS endpoints, CORS, API namespaces - **Database** — Data directory, state pruning - **Metrics** — Prometheus endpoint - **Engine API** — JWT secret, engine API endpoint - **Logging** — Log level, log format ## Environment Variables Configuration can also be set via environment variables. The devnet uses `etc/docker/devnet-env` for its environment. ## Build Profiles The workspace defines several Cargo build profiles: | Profile | Use Case | Key Settings | |---------|---------|-------------| | `dev` | Development | `debug = "line-tables-only"`, `incremental = false` | | `release` | Production | `opt-level = 3`, `lto = "thin"`, `strip = "symbols"` | | `maxperf` | Maximum performance | `lto = "fat"`, `codegen-units = 1` | | `profiling` | Performance analysis | `debug = "line-tables-only"`, `frame-pointers = true` | | `ci` | CI builds | `debug = false`, minimal disk usage | ## basectl The [`basectl`](/node-operations/basectl/) utility provides configuration management for different network targets: ```bash # Mainnet configuration cargo run -p basectl --release -- -c mainnet # Sepolia testnet cargo run -p basectl --release -- -c sepolia # Local devnet cargo run -p basectl --release -- -c devnet ``` --- # Deployment Source: https://basehub.org/node-operations/deployment/ Description: Run base-reth-node in production via the official Docker image or a custom source build. import { Aside } from '@astrojs/starlight/components'; ## Production Images The recommended way to run Base Reth Node in production is via the official Docker image from [base/node](https://github.com/base/node): ```bash docker pull ghcr.io/base/node-reth:latest ``` This image bundles both vanilla Reth and Base Reth and can be toggled with the `NODE_TYPE` environment variable: ```bash # Run Base Reth docker run ghcr.io/base/node-reth -e NODE_TYPE=base # Run vanilla Reth docker run ghcr.io/base/node-reth -e NODE_TYPE=vanilla ``` ## Building from Source for Deployment If you need a custom build: ```bash # Standard release build just build # Maximum performance (LTO fat, single codegen unit, jemalloc) just build-maxperf ``` The `maxperf` profile enables: - Full LTO (`lto = "fat"`) - Single codegen unit (`codegen-units = 1`) - jemalloc memory allocator The resulting binary is at `target/release/base-reth-node` (or `target/maxperf/base-reth-node` for maxperf). ## Hardware Requirements Base Reth Node requires: - **CPU:** Multi-core processor (4+ cores recommended) - **Memory:** 16 GB+ RAM - **Storage:** NVMe SSD with sufficient space for chain state - **Network:** Stable, high-bandwidth connection ## Configuration See the [Configuration Reference](/node-operations/configuration/) for all available options, or run: ```bash ./target/release/base-reth-node --help ``` --- # Docker Operations Source: https://basehub.org/node-operations/docker/ Description: Build and run base-reth-node, the builder, and the websocket proxy with Docker. ## Dockerfiles The repository provides several Dockerfiles in [`etc/docker/`](https://github.com/base/base/tree/main/etc/docker): | Dockerfile | Purpose | |-----------|---------| | `Dockerfile.client` | Main Base Reth Node client | | `Dockerfile.builder` | Block builder service | | `Dockerfile.devnet` | Local development network setup | | `Dockerfile.websocket-proxy` | WebSocket proxy for flashblock streaming | ## Building Images ### Client Node ```bash docker build -t base-reth-node -f etc/docker/Dockerfile.client . ``` ### Builder ```bash docker build -t base-builder -f etc/docker/Dockerfile.builder . ``` ### WebSocket Proxy ```bash docker build -t websocket-proxy -f etc/docker/Dockerfile.websocket-proxy . ``` ## Running Containers ```bash docker run -it --rm \ -p 8545:8545 \ -p 8546:8546 \ -p 30303:30303 \ -v /path/to/data:/data \ base-reth-node [OPTIONS] ``` Common flags: - `-p 8545:8545` — HTTP JSON-RPC - `-p 8546:8546` — WebSocket JSON-RPC - `-p 30303:30303` — P2P networking - `-v /path/to/data:/data` — Persistent data volume ## Docker Compose The repository includes a Docker Compose configuration for running a local devnet: ```bash docker compose --env-file etc/docker/devnet-env \ -f etc/docker/docker-compose.yml up -d --build ``` See [Local Devnet](/getting-started/devnet/) for the full devnet setup guide. ## Production Images For production use, the official images are published at: ``` ghcr.io/base/node-reth ``` See the [base/node repository](https://github.com/base/node) for release tags and configuration. --- # Monitoring Source: https://basehub.org/node-operations/monitoring/ Description: Prometheus metrics, devnet status commands, log streaming, and profiling for base-reth-node. ## Prometheus Metrics The Base Reth Node exports Prometheus-compatible metrics. The `base-cli-utils` crate sets up a metrics HTTP listener using `metrics-exporter-prometheus`. Key metric categories: - **Process metrics** — CPU, memory, file descriptors (via `metrics-process`) - **RPC metrics** — Request counts, latencies, error rates - **Transaction pool** — Pool size, pending/queued counts - **Sync progress** — Block height, peer count - **Flashblocks** — Flashblock production rate, latency ## Devnet Monitoring The devnet includes built-in monitoring commands: ```bash # Check block numbers and sync status across all nodes just devnet-status # View funded test accounts with balances and nonces just devnet-accounts # Run smoke tests (send test transactions to L1 and L2) just devnet-smoke # Full check suite just devnet-checks ``` ## Log Streaming Stream logs from devnet containers: ```bash # All containers just devnet-logs # Specific containers just devnet-logs l2-node builder ``` ## Profiling For performance profiling, build with the `profiling` profile: ```bash just devnet-profiling ``` This starts the devnet with Pyroscope integration and optimized builds that retain frame pointers for accurate profiling. The profiling profile settings: - Inherits from `release` - LTO disabled for faster builds - Debug info: line tables only - Frame pointers forced on - Symbols not stripped --- # Node Providers Source: https://basehub.org/node-operations/node-providers/ Description: Hosted RPC providers for Base Mainnet and Base Sepolia, including Coinbase Developer Platform, Alchemy, QuickNode, and others. A range of providers offer hosted RPC endpoints for Base Mainnet and Base Sepolia. Capabilities, networks, and pricing tiers vary — links below point to each provider's documentation and pricing pages. ## Coinbase Developer Platform (CDP) [CDP](https://portal.cdp.coinbase.com/) exposes an RPC endpoint that runs on the same node infrastructure powering Coinbase's retail exchange. The free tier is rate-limited and ready for early development. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## 1RPC [1RPC](https://1rpc.io/) is an on-chain attested, privacy-preserving RPC that minimizes metadata exposure when interacting with chains. Free and [paid plans](https://www.1rpc.io/#pricing) are available. Supported networks: - Base Mainnet ## Alchemy [Alchemy](https://dashboard.alchemy.com/?utm_source=chain_partner&utm_medium=referral&utm_campaign=base) provides a developer platform with SDKs, [JSON-RPC APIs](https://docs.alchemy.com/reference/base-api-quickstart), and hosted Base mainnet and testnet nodes on a free tier. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## All That Node [All That Node](https://www.allthatnode.com/base.dsrv) is a multi-chain development platform with free and [paid plans](https://www.allthatnode.com/pricing.dsrv). Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## Ankr [Ankr](https://www.ankr.com/rpc/base/) offers private and public Base RPC endpoints backed by a globally distributed node network. Free and [paid plans](https://www.ankr.com/rpc/pricing/) are available. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## Blast [Blast](https://blastapi.io/public-api/base) provides decentralized blockchain APIs via partnerships with third-party node providers. Users can [generate dedicated Base RPC endpoints](https://blastapi.io/login). Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## Blockdaemon [Blockdaemon](https://www.blockdaemon.com/protocols/base/) hosts Base nodes with a free tier via the Ubiquity Data API Suite. Usage above the free tier incurs additional charges. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## BlockPI [BlockPI](https://blockpi.io/) provides Base RPC access with [free and paid plans](https://docs.blockpi.io/pricing/pricing-and-rate-limit). Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## Chainstack [Chainstack](https://chainstack.com/build-better-with-base/) provisions elastic Base RPC nodes with personal, geographically diverse endpoints, plus archive nodes for full history queries. See the [free and paid plans](https://chainstack.com/pricing/). Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## dRPC NodeCloud [dRPC NodeCloud](https://drpc.org/nodecloud-multichain-rpc-management) offers Base Mainnet and Base Sepolia endpoints alongside 180+ networks, with smart routing, analytics, key management, and front-end protection. Backed by 40 providers across 9 geoclusters. Free tier with flat-rate pricing from $10. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## GetBlock [GetBlock](https://getblock.io/nodes/base/) is a Blockchain-as-a-Service platform offering instant API access to full Base nodes with free, pay-per-use, and unlimited tiers. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## NodeReal [NodeReal](https://nodereal.io/) supplies Base node API access for blockchain infrastructure use cases. Supported networks: - Base Mainnet ## Nodies DLB [Nodies DLB](https://nodies.app) operates high-performance RPC for Base and other OP Stack chains, with public free endpoints, pay-as-you-go, and enterprise plans. Supported networks: - Base Mainnet - Base Testnet (available on request) ## NOWNodes [NOWNodes](https://nownodes.io/nodes/basechain-base) provides shared and dedicated Base RPC access without rate limits. Supported networks: - Base Mainnet ## OnFinality [OnFinality](https://onfinality.io) offers high-performance archive access to Base Mainnet and Base Sepolia. The free tier carries generous limits, and Trace and Debug APIs are available on [paid plans](https://onfinality.io/pricing). Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## QuickNode [QuickNode](https://www.quicknode.com/chains/base) supports Base with Flashblocks and archive data, plus trace/debug capabilities for transaction analysis. Streams and Webhooks cover event-driven and data-streaming workloads, and the Marketplace includes add-ons such as the [Aerodrome Swap API](https://marketplace.quicknode.com/add-on/aerodrome-swap-api). See the [QuickNode Base docs](https://www.quicknode.com/docs/base) for setup. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## RockX [RockX](https://access.rockx.com) operates a global node network with developer tooling. The free [Base RPC](https://access.rockx.com/product/base-blockchain-api-for-web3-builders) tier provides institutional-grade access. Supported networks: - Base Mainnet ## Stackup [Stackup](https://www.stackup.sh/) is an ERC-4337 infrastructure platform offering hosted Base nodes plus [account abstraction tooling](https://docs.stackup.sh/docs) such as bundlers and paymasters. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## SubQuery [SubQuery](https://subquery.network/rpc) is a decentralized RPC network with public free endpoints and Flex Plans for higher access. Supported networks: - Base Mainnet ## Tenderly Web3 Gateway [Tenderly Web3 Gateway](https://tenderly.co/web3-gateway) is a hosted node solution with developer tooling spanning the full lifecycle — develop, test, deploy, and monitor on Base. [Free and paid plans](https://tenderly.co/pricing) are available. Supported networks: - Base Mainnet - Base Sepolia (Testnet) ## Unifra [Unifra](https://www.unifra.io) provides Web3 developer tooling, APIs, and Base node infrastructure. Supported networks: - Base Mainnet ## Validation Cloud [Validation Cloud](https://app.validationcloud.io/) offers low-latency Base RPC with 50 million compute units available on the free tier (no credit card required) and a scale tier without rate limits. Supported networks: - Base Mainnet --- # Performance Tuning Source: https://basehub.org/node-operations/performance-tuning/ Description: Hardware, storage, and client recommendations for high-performance Base nodes, including production configurations and sync guidance. import { Aside } from '@astrojs/starlight/components'; This guide covers the hardware, storage, and client choices that yield the best Base node performance. ## Hardware A performant Base node needs adequate hardware. Recommended minimums: 1. A modern multi-core CPU with strong single-core performance. 2. At least 32 GB of RAM (64 GB preferred). 3. A locally attached NVMe SSD. RAID 0 layouts can boost throughput. 4. Sufficient capacity, sized as: ``` (2 × [current chain size] + [snapshot size] + 20% buffer) ``` The formula reserves room for chain growth and snapshot restoration. See [Base Stats](https://base.org/stats) for the current chain size and [Base Chain Data](https://basechaindata.vercel.app) for snapshot size. ### Production hardware Base production nodes use the following hardware: - **Reth archive node** - Instance: AWS `i7i.12xlarge` or larger - Storage: RAID 0 across all local NVMe drives (`/dev/nvme*`) - Filesystem: ext4 ## Initial sync Restore from a recent [snapshot](/node-operations/snapshots/) to dramatically shorten initial sync. ## Client software The [Base Node](https://github.com/base/node) repository carries the current stable client configurations and run instructions. Reth is currently the most performant Base client, and ongoing optimization work is concentrated there. Background on the move to Reth: [Scaling Base with Reth](https://blog.base.dev/scaling-base-with-reth). --- # Release Process Source: https://basehub.org/node-operations/release-process/ Description: How base/base releases are produced — Start Release, automatic RC builds on push, and Publish Release for the final tag. Releases of `base/base` are produced through two manual workflows and one automatic trigger: - **Start Release** — choose a bump type (major / minor / patch) and the release branch is created automatically. - **Publish Release** — choose a version and the final tag, Docker images, and binaries are published. - **Auto-RC** — every commit to a `releases/v*` branch (after the version sync PR is merged) automatically creates an RC tag and builds Docker images and binaries. ## Step by step ### 1. Start a release Run the **Start Release** workflow (`Actions → Start Release → Run workflow`): - Select the bump type: `minor` (new feature release), `patch` (bug fixes), or `major` (breaking changes). - The workflow computes the next version from the latest final tag and creates the `releases/vX.Y.Z` branch. - For `patch` bumps, the base is the most recent `releases/vX.Y.*` branch; for `major` and `minor`, the base is `main`. Once the branch is created, the **Release Version Sync** workflow fires automatically and opens a PR to update `Cargo.toml` to the new version. ### 2. Merge the version sync PR Review and merge the auto-generated version sync PR targeting the release branch. Merging unblocks auto-RC creation. ### 3. Build release candidates (automatic) Every commit pushed to the release branch triggers the **Create RC** workflow, which: - Skips silently if `Cargo.toml` is still `0.0.0` (the version sync PR has not been merged yet). - Otherwise creates the next RC tag (for example, `v0.6.0-rc.1`, `v0.6.0-rc.2`, …). - Builds multi-arch Docker images and native binaries. - Pushes the Docker image tagged with the RC tag only (not `latest`). To produce additional RCs, push more commits — bug fixes or backports — to the release branch. ### 4. Publish the final release Once you are satisfied with an RC, run the **Publish Release** workflow (`Actions → Publish Release → Run workflow`): - Enter the version number (for example, `0.6.0` — no `v` prefix, no `releases/` prefix). - The workflow validates that the release branch exists and `Cargo.toml` is not `0.0.0`. - Creates the final tag `vX.Y.Z` on the release branch. - Builds Docker images tagged as `vX.Y.Z`, `X.Y`, `X`, and `latest`. - Creates a draft GitHub release with auto-generated changelog and uploads binaries. - Review and publish the draft release on GitHub. ## Auto-RC behavior The **Create RC** workflow runs on every push to any `releases/v*` branch. It is safe to push before the version sync PR is merged — the workflow detects `0.0.0` and skips with a notice rather than failing. RC tags follow the pattern `vX.Y.Z-rc.N`, where `N` increments automatically based on existing tags. ## Quick reference | Action | Workflow | Trigger | Output | |--------|----------|---------|--------| | Create release branch | **Start Release** | Manual (bump type) | `releases/vX.Y.Z` branch | | Sync `Cargo.toml` version | **Release Version Sync** | Automatic on branch creation | PR targeting release branch | | Build RC | **Create RC** | Automatic on push to `releases/v*` | RC tag + Docker image + binaries | | Publish final release | **Publish Release** | Manual (version number) | Final tag + Docker images + draft GitHub release | ## Workflows - **Start Release** — Creates the release branch from a bump-type dropdown. - **Release Version Sync** — Opens a PR to update `Cargo.toml` when a release branch is created. - **Create RC** — Triggered on push to `releases/v*`; creates RC tags and builds artifacts. - **Build Release** — Reusable workflow (called by Create RC and Publish Release) that builds Docker images and binaries. - **Publish Release** — Manual workflow to create the final tag and publish the release. --- # Releases Source: https://basehub.org/node-operations/releases/ Description: Versioning, the pinned Reth tag, production image registry, and the GitHub Actions release flow. import { Aside } from '@astrojs/starlight/components'; ## Versioning The workspace version is `0.0.0` (development). All crates share the workspace version defined in the root `Cargo.toml`: ```toml [workspace.package] version = "0.0.0" edition = "2024" rust-version = "1.88" ``` ## Reth Version Base Reth Node tracks a specific Reth release. The current pinned version: ``` reth v1.11.0 ``` This is specified in the workspace dependencies as a git dependency with a tag: ```toml reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.0" } ``` ## Production Docker Images Production images are published at: ``` ghcr.io/base/node-reth ``` These are managed in the [base/node](https://github.com/base/node) repository and include both vanilla Reth and Base Reth, selectable via `NODE_TYPE`. ## Release Process Release branches follow the `releases/v` naming convention. The process uses GitHub Actions workflows: 1. **Release candidates** are created via the "Create Release" workflow with `rc` type. RC versions are auto-numbered (e.g., `v1.0.0-rc.1`, `v1.0.0-rc.2`). 2. **Final releases** are created with `final` type, which tags Docker images as `v1.0.0`, `1.0`, `1`, and `latest`. ### Workflows | Workflow | Trigger | Purpose | |----------|---------|---------| | Release Version Sync | Automatic | Updates `Cargo.toml` versions on release branches | | Create Release | Manual | Creates RC or final release tags | | Release | Tag push | Builds Docker images, creates GitHub release | ## Default Build Targets The workspace defines default members that are built by `cargo build`: - `bin/based` - `bin/node` (produces `base-reth-node`) - `bin/basectl` - `bin/builder` - `bin/consensus` - `bin/ingress-rpc` - `bin/audit-archiver` - `bin/mempool-rebroadcaster` --- # Snapshots Source: https://basehub.org/node-operations/snapshots/ Description: Restore Base nodes from official Reth and proofs snapshots for Base Mainnet and Base Sepolia to skip the initial sync window. import { Aside } from '@astrojs/starlight/components'; Restoring from a snapshot drastically reduces initial Base node sync time. Snapshots are refreshed regularly. ## Restoring from a snapshot These steps assume you are inside the cloned `node` directory (the one containing `docker-compose.yml`). 1. **Prepare the data directory.** - **Before launching Docker for the first time**, create the host directory that will be mapped into the container. The path must match the `volumes` entry in `docker-compose.yml`: ```bash mkdir ./reth-data ``` - If a previous run left an existing data directory, **stop the node first** (`docker compose down`), wipe the contents (for example, `rm -rf ./reth-data/*`), then continue. 2. **Download the snapshot.** Pick the row that matches your network and client, and download into the `node` directory using `wget` or equivalent. | Network | Snapshot type | Download command (`wget …`) | | -------- | -------------------- | ----------------------------------------------------------------------------------------------------------------- | | Testnet | Archive (recommended)| `wget -c https://sepolia-reth-archive-snapshots.base.org/$(curl https://sepolia-reth-archive-snapshots.base.org/latest)` | | Testnet | Pruned | `wget -c https://sepolia-reth-pruned-snapshots.base.org/$(curl https://sepolia-reth-pruned-snapshots.base.org/latest)` | | Mainnet | Archive (recommended)| `wget -c https://mainnet-reth-archive-snapshots.base.org/$(curl https://mainnet-reth-archive-snapshots.base.org/latest)` | | Mainnet | Pruned | `wget -c https://mainnet-reth-pruned-snapshots.base.org/$(curl https://mainnet-reth-pruned-snapshots.base.org/latest)` | 3. **Extract the snapshot.** Replace `snapshot-filename` with the actual download: ```bash tar -xzvf # For .tar.zst tar -I zstd -xvf ``` 4. **Move the data into place.** Extraction typically produces a `reth/` directory. - Move its contents into the data directory created in step 1: ```bash mv ./reth/* ./reth-data/ rm -rf ./reth # remove the now-empty extracted folder ``` - The chain data subdirectories (`chaindata`, `nodes`, `segments`, etc.) must sit directly under `./reth-data` — not in a nested folder. 5. **Start the node.** Return to the root of your Base node folder and bring it up: ```bash cd .. docker compose up --build ``` The node should pick up syncing from the last block recorded in the snapshot. 6. **Verify and clean up.** Tail the logs (`docker compose logs -f `) or use the [sync monitoring](/getting-started/running/) command to confirm the node starts at the snapshot's block height. Once verified, delete the downloaded archive (`.tar.gz`) to reclaim disk space. ## Proofs snapshots If you run the [historical proofs ExEx](/getting-started/running/), proof database snapshots are available so you can skip the 24–48 hour backfill. | Network | Download command (`wget …`) | | ------- | --------------------------- | | Testnet | `wget -c https://sepolia-reth-proofs-snapshots.base.org/$(curl https://sepolia-reth-proofs-snapshots.base.org/latest)` | | Mainnet | `wget -c https://mainnet-reth-proofs-snapshots.base.org/$(curl https://mainnet-reth-proofs-snapshots.base.org/latest)` | The restore process matches the steps above — follow [Restoring from a snapshot](#restoring-from-a-snapshot) using this archive. --- # Node Troubleshooting Source: https://basehub.org/node-operations/troubleshooting/ Description: Diagnose setup, sync, performance, snapshot, and networking issues for Base nodes running the official Docker setup. This guide covers the most common issues operators hit when running a Base node from the official [Docker setup](https://github.com/base/node), with steps to diagnose and resolve each one. ## General troubleshooting Before chasing specific issues, work through these baseline checks. 1. **Inspect container logs.** Tail the relevant container with `docker compose logs -f `: - L2 client (Reth): `docker compose logs -f execution` - Rollup node: `docker compose logs -f node`. Look for errors, warnings, or repeated messages. 2. **Check container status.** Confirm the right containers are running with `docker compose ps`. Restart loops or exited containers warrant a log review. 3. **Watch resource usage.** CPU, RAM, disk I/O, and network usage are common bottlenecks. `htop`, `iostat`, and `iftop` are useful starting points. 4. **Verify RPC endpoints.** Use `curl` to confirm the L2 client's RPC is responding (see [running a Base node](/getting-started/running/)). Confirm L1 endpoints are correct and reachable from the node host. 5. **Check the L1 node.** Ensure the configured L1 execution and consensus clients are fully synced, healthy, and accessible. L1 issues block L2 sync. ## Common issues ### Setup and configuration - **Issue:** The Docker command (`docker compose up ...`) fails. - **Check:** Is Docker (and Docker Compose) installed and the daemon running? - **Check:** Are you in the correct directory (the cloned `node` directory containing `docker-compose.yml`)? - **Check:** Command syntax — typos in `NETWORK_ENV` or `CLIENT` are common. - **Issue:** A container fails to start with `.env` or environment variable errors. - **Check:** Did you set the L1 endpoints (`OP_NODE_L1_ETH_RPC`, `OP_NODE_L1_BEACON`) in the right `.env` file (`.env.mainnet` or `.env.sepolia`)? - **Check:** Is `OP_NODE_L1_BEACON_ARCHIVER` set if your configuration or L1 node requires it? - **Check:** Is `OP_NODE_L1_RPC_KIND` set correctly for your L1 provider? - **Check:** (Reth) Are `RETH_CHAIN` and `RETH_SEQUENCER_HTTP` correctly configured in `.env`? - **Issue:** JWT secret or auth errors between `op-node` and the L2 client. - **Check:** Avoid hand-editing `OP_NODE_L2_ENGINE_AUTH` or the JWT file path (`$OP_NODE_L2_ENGINE_AUTH`) unless you know what you are doing — `docker-compose` handles this automatically. - **Issue:** Permission errors against the data volume (`./reth-data`). - **Check:** The user running `docker compose` must have write access to the cloned repo so Docker can write into `./reth-data`. Avoid `sudo`-running Docker commands; instead, add your user to the `docker` group. ### Syncing - **Issue:** The node never starts syncing or block height stalls. - **Check:** `op-node` logs for L1 endpoint or L2 client connection errors. - **Check:** Execution client logs for Engine API issues on port `8551` or P2P errors. - **Check:** L1 node health — is it accessible and fully synced? - **Check:** System time. Run `ntp` or `chrony`; significant clock drift breaks P2P. - **Issue:** Sync is unusually slow. - **Check:** Hardware against the [performance tuning](/node-operations/performance-tuning/) recommendations, especially RAM and **NVMe SSD**. Disk I/O is usually the bottleneck. - **Check:** L1 RPC responsiveness. A slow L1 node throttles L2 sync. - **Check:** Network bandwidth and connection quality. - **Check:** `op-node` and L2 client logs for performance warnings or errors. - **Issue:** `optimism_syncStatus` (port `7545` on `op-node`) reports a large time delta or errors. - **Action:** Inspect rollup node and L2 execution client logs around the time of the check to identify the cause (often L1 connectivity or L2 client problems). - **Issue:** `Error: nonce has already been used` when sending transactions. - **Cause:** The node is still catching up to the chain head. - **Action:** Wait for full sync. Track progress via `optimism_syncStatus` or logs. ### Performance - **Issue:** High CPU, RAM, or disk I/O usage. - **Check:** Hardware against the [performance tuning](/node-operations/performance-tuning/) recommendations, and upgrade if needed. Local NVMe SSDs are critical. - **Check:** Client logs for specific bottlenecks or errors. ### Snapshot restoration Refer to the [Snapshots](/node-operations/snapshots/) guide for the canonical procedure. - **Issue:** `wget` fails or the snapshot download is corrupted. - **Check:** Network connectivity. - **Check:** Available disk space. - **Action:** Retry the download and verify the URL. - **Issue:** `tar` extraction fails. - **Check:** Downloaded file integrity. - **Check:** Available disk space — extraction needs much more than the download itself. - **Check:** `tar` command syntax. - **Issue:** The node fails to start after restoring a snapshot, with database errors or missing files. - **Check:** Did you run `docker compose down` before touching the data directory? - **Check:** Did you remove the contents of the old data directory (`./reth-data/*`) before extracting and moving the new data? - **Check:** Is the chain data directly inside `./reth-data` rather than in a nested folder (for example, `./reth-data/reth/...`)? Verify the structure. - **Issue:** Out of disk space during download or extraction. - **Action:** Free space or attach a larger volume. Use the storage formula: ``` (2 * chain_size + snapshot_size + 20% buffer) ``` ### Networking and connectivity - **Issue:** RPC or WS connection refused (e.g., `curl localhost:8545` fails). - **Check:** Is the L2 client container running (`docker compose ps`)? - **Check:** Are you using the correct port (`8545` HTTP, `8546` WS by default)? - **Check:** L2 client logs — did the RPC server fail to start? - **Check:** Are `--http.addr` and `--ws.addr` set to `0.0.0.0` in the client config or entrypoint so external connections work within the Docker network? - **Issue:** Low peer count. - **Check:** P2P port accessibility. Ensure `30303` (TCP/UDP) and `9222` (TCP/UDP for Reth discv5) are not blocked by firewalls on the host or upstream network. - **Check:** Node logs for P2P errors. - **Action:** Behind NAT, set `--nat=extip:` via `ADDITIONAL_ARGS` in `.env` (see [advanced configuration](/getting-started/running/)). - **Issue:** Port conflicts in logs or `docker compose up` fails. - **Check:** Other host services using the default ports (`8545`, `8546`, `8551`, `6060`, `7545`, `30303`): ```bash sudo lsof -i -P -n | grep LISTEN sudo netstat -tulpn | grep LISTEN ``` - **Action:** Stop the conflicting service or remap the Base container ports in `docker-compose.yml`, then update the related variables (`$RPC_PORT`, `$WS_PORT`, etc.) in `.env`. ## Getting more help If you have worked through this guide and the issue persists: - **Discord:** Join the [Base Discord](https://discord.gg/buildonbase) and post in `#node-operators` with details of your setup, the issue, and relevant logs. - **GitHub:** Browse the [Base Node repository issues](https://github.com/base/node/issues), or open a new one if you suspect a bug. --- # Adding a New Network Upgrade Source: https://basehub.org/node-operations/upgrades/ Description: Every code change required to land a new Base network upgrade — config, traits, RollupConfig methods, EVM spec resolution, and precompile routing. import { Aside } from '@astrojs/starlight/components'; This guide enumerates every code change required to introduce a new network upgrade to [`base/base`](https://github.com/base/base). The work is split into changes required for every upgrade and changes required only when the upgrade alters EVM execution. The Azul upgrade is the running example. Substitute `Azul`, `azul`, and `BASE_AZUL` with the actual upgrade name. For broader context on the codebase, see the [architecture overview](/architecture/overview/). ## Architecture overview Upgrade activation flows through three layers: 1. **Config layer** — `HardForkConfig` stores an optional activation timestamp per upgrade. `RollupConfig` embeds it and exposes `is_X_active(timestamp)` helpers. 2. **Trait layer** — the `BaseUpgrade` enum and `BaseUpgrades` trait provide typed, generic activation checks used by both the consensus and execution layers. 3. **Execution layer** — `OpSpecId` maps the active upgrade to an EVM spec. `spec_by_timestamp_after_bedrock` and `RollupConfig::spec_id` resolve which spec to use. `BasePrecompiles` routes to the correct precompile set. ## Part 1 — Required for every upgrade ### 1. Add the variant to the `BaseUpgrade` enum **File:** [`crates/common/chains/src/upgrade.rs`](https://github.com/base/base/blob/main/crates/common/chains/src/upgrade.rs) Inside the `hardfork!` macro, append the new variant after the current last entry: ```rust hardfork!( #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Default)] BaseUpgrade { // ... existing variants ... /// Jovian: Jovian, /// Azul: First Base-specific network upgrade. Azul, // <-- add here } ); ``` Then update all four chain config array methods from `[(Self, ForkCondition); N]` to `N+1` and append the new entry. Mainnet and sepolia use `ForkCondition::Never` until the upgrade is scheduled; the generic devnet uses `ForkCondition::ZERO_TIMESTAMP`: ```rust pub const fn mainnet() -> [(Self, ForkCondition); 10] { [ // ... existing entries ... (Self::Azul, ForkCondition::Never), ] } pub const fn devnet() -> [(Self, ForkCondition); 10] { [ // ... existing entries ... (Self::Azul, ForkCondition::ZERO_TIMESTAMP), ] } ``` For named devnets like `base_devnet_0_sepolia_dev_0`, reuse the previous upgrade's timestamp instead of `ZERO_TIMESTAMP` so the new upgrade does not activate before the one it follows: ```rust pub const fn base_devnet_0_sepolia_dev_0() -> [(Self, ForkCondition); 10] { [ // ... existing entries ... (Self::Jovian, ForkCondition::Timestamp(BASE_DEVNET_0_SEPOLIA_DEV_0_JOVIAN_TIMESTAMP)), (Self::Azul, ForkCondition::Timestamp(BASE_DEVNET_0_SEPOLIA_DEV_0_JOVIAN_TIMESTAMP)), ] } ``` Update `check_base_upgrade_from_str` in the test module to include the new variant. ### 2. Add the `BaseChainUpgrades` index arm **File:** [`crates/common/chains/src/chain.rs`](https://github.com/base/base/blob/main/crates/common/chains/src/chain.rs) Add `Azul` to the `use BaseUpgrade::{...}` import and add a match arm to `Index`: ```rust use BaseUpgrade::{ Azul, Bedrock, Canyon, Ecotone, Fjord, Granite, Holocene, Isthmus, Jovian, Regolith, }; impl Index for BaseChainUpgrades { fn index(&self, hf: BaseUpgrade) -> &Self::Output { match hf { // ... existing arms ... Jovian => &self.forks[Jovian.idx()].1, Azul => &self.forks[Azul.idx()].1, // <-- add } } } ``` ### 3. Add the config field and nested struct **File:** [`crates/consensus/genesis/src/chain/hardfork.rs`](https://github.com/base/base/blob/main/crates/consensus/genesis/src/chain/hardfork.rs) For standard upgrades (flat timestamp field), add directly to `HardForkConfig`: ```rust /// `azul_time` sets the activation time for the Base Azul network upgrade. #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub azul_time: Option, ``` For namespaced upgrades with the `{ "base": { "azul": } }` JSON shape, define a sub-struct and embed it: ```rust /// Hardfork configuration for Base-specific upgrades. #[derive(Debug, Copy, Clone, Default, Hash, Eq, PartialEq)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] pub struct BaseHardforkConfig { #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub azul: Option, } pub struct HardForkConfig { // ... existing fields ... #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub base: Option, } ``` Update `HardForkConfig::iter()` to include the new entry, and re-export any new public types from `crates/consensus/genesis/src/chain/mod.rs` and `crates/consensus/genesis/src/lib.rs`. ### 4. Add activation methods to `RollupConfig` **File:** [`crates/consensus/genesis/src/rollup.rs`](https://github.com/base/base/blob/main/crates/consensus/genesis/src/rollup.rs) Add `is_X_active` and `is_first_X_block` after the previous upgrade's methods. There are two patterns depending on whether the new upgrade is **standalone** or **cascading**. **Standalone** (e.g. `pectra_blob_schedule`, `Azul`) — activated independently and never implied by a later upgrade. Use this pattern when the upgrade affects only protocol-level behavior and is not a prerequisite for the next upgrade: ```rust /// Returns true if Base Azul is active at the given timestamp. pub fn is_base_azul_active(&self, timestamp: u64) -> bool { self.hardforks.base.as_ref().and_then(|b| b.azul).is_some_and(|t| timestamp >= t) } /// Returns true if the timestamp marks the first Base Azul block. pub fn is_first_base_azul_block(&self, timestamp: u64) -> bool { self.is_base_azul_active(timestamp) && !self.is_base_azul_active(timestamp.saturating_sub(self.block_time)) } ``` The previous terminal upgrade's `is_X_active` method is left unchanged (no cascade added). **Cascading** (e.g. `Canyon`, `Ecotone`, `Isthmus`) — the previous upgrade is considered active whenever the new one is. Update the previous terminal upgrade's method and add the new one: ```rust /// Returns true if Jovian is active at the given timestamp. pub fn is_jovian_active(&self, timestamp: u64) -> bool { self.hardforks.jovian_time.is_some_and(|t| timestamp >= t) || self.is_next_active(timestamp) // <-- cascade to next fork } /// Returns true if Next is active at the given timestamp. pub fn is_next_active(&self, timestamp: u64) -> bool { self.hardforks.next_time.is_some_and(|t| timestamp >= t) } ``` Also update `upgrade_activation` in `impl BaseUpgrades for RollupConfig` to add the new arm. For **standalone** upgrades, the previous arm keeps `unwrap_or(ForkCondition::Never)`: ```rust BaseUpgrade::Jovian => self .hardforks .jovian_time .map(ForkCondition::Timestamp) .unwrap_or(ForkCondition::Never), // standalone: no cascade BaseUpgrade::Azul => self .hardforks .base .as_ref() .and_then(|b| b.azul) .map(ForkCondition::Timestamp) .unwrap_or(ForkCondition::Never), _ => ForkCondition::Never, // required: BaseUpgrade is #[non_exhaustive] ``` For **cascading** upgrades, replace the previous arm's `unwrap_or(ForkCondition::Never)` with `.unwrap_or_else(|| self.upgrade_activation(BaseUpgrade::Next))`. ### 5. Add the trait method **File:** [`crates/common/chains/src/upgrades.rs`](https://github.com/base/base/blob/main/crates/common/chains/src/upgrades.rs) ```rust /// Returns `true` if [`Azul`](BaseUpgrade::Azul) is active at given block timestamp. fn is_base_azul_active_at_timestamp(&self, timestamp: u64) -> bool { self.upgrade_activation(BaseUpgrade::Azul).active_at_timestamp(timestamp) } ``` ### 6. Update timestamp constants and test fixtures **Files:** - [`crates/common/chains/src/upgrade.rs`](https://github.com/base/base/blob/main/crates/common/chains/src/upgrade.rs) (mainnet, sepolia, devnet constants) - [`crates/common/chains/src/lib.rs`](https://github.com/base/base/blob/main/crates/common/chains/src/lib.rs) - [`crates/consensus/registry/src/test_utils/mod.rs`](https://github.com/base/base/blob/main/crates/consensus/registry/src/test_utils/mod.rs) Add named constants once an activation timestamp is confirmed: ```rust // mainnet.rs /// Base Azul mainnet activation timestamp. pub const BASE_MAINNET_BASE_AZUL_TIMESTAMP: u64 = ; // sepolia.rs /// Base Azul sepolia activation timestamp. pub const BASE_SEPOLIA_BASE_AZUL_TIMESTAMP: u64 = ; ``` Re-export from `lib.rs` alongside the other timestamp constants. Update the `HardForkConfig` literal in both registry fixture files: ```rust hardforks: HardForkConfig { // ... existing fields ... jovian_time: Some(BASE_MAINNET_JOVIAN_TIMESTAMP), base: Some(BaseHardforkConfig { azul: Some(BASE_MAINNET_BASE_AZUL_TIMESTAMP) }), }, ``` Until an activation timestamp is confirmed, leave `base: None` and the chain arrays at `ForkCondition::Never`. ### 7. Update the default rollup config **File:** [`crates/consensus/registry/src/test_utils/mod.rs`](https://github.com/base/base/blob/main/crates/consensus/registry/src/test_utils/mod.rs) The `default_rollup_config()` function activates every upgrade at genesis for dev use. Add the new upgrade: ```rust hardforks: HardForkConfig { // ... existing fields ... jovian_time: Some(0), base: Some(BaseHardforkConfig { azul: Some(0) }), }, ``` ### 8. Verify the upgrade consistency tests **File:** [`crates/consensus/registry/tests/hardfork_consistency.rs`](https://github.com/base/base/blob/main/crates/consensus/registry/tests/hardfork_consistency.rs) These tests assert that `BaseChainConfig::mainnet().upgrade_activation(fork)` matches `BaseChainUpgrades::mainnet().upgrade_activation(fork)` for every `BaseUpgrade` variant. They should pass without changes as long as both sides consistently return `ForkCondition::Never` for an unscheduled upgrade or the same timestamp once scheduled. If a known discrepancy exists (for example, the cascade causes a mismatch for an unset upgrade), add a skip with an explanatory comment as done for `Regolith`: ```rust if *fork == BaseUpgrade::Azul { continue; // explanation of why the two sides differ } ``` ## Part 2 — Required when the upgrade changes EVM execution Skip this section if the upgrade only affects protocol-level behavior (batch decoding, derivation rules, system config) without introducing new EVM opcodes, precompile addresses, or gas rule changes. ### 9. Add the `OpSpecId` variant **File:** [`crates/common/evm/src/spec.rs`](https://github.com/base/base/blob/main/crates/common/evm/src/spec.rs) ```rust pub enum OpSpecId { // ... existing variants ... JOVIAN, AZUL, // <-- add OSAKA, } ``` Extend `into_eth_spec()` — if no new Ethereum EL upgrade is paired, reuse the previous mapping: ```rust Self::ISTHMUS | Self::JOVIAN | Self::AZUL => SpecId::PRAGUE, ``` Add a `#[strum(serialize = "...")]` attribute on the new variant with its canonical string name: ```rust /// Base Azul spec id. #[strum(serialize = "Azul")] AZUL, ``` `FromStr` and `From for &'static str` are derived automatically. ### 10. Route precompiles **File:** [`crates/common/evm/src/precompiles/provider.rs`](https://github.com/base/base/blob/main/crates/common/evm/src/precompiles/provider.rs) If the upgrade introduces new precompiles, add a new `pub fn azul()` method on `BasePrecompiles`. If it reuses the previous set, extend the existing arm in `new_with_spec`: ```rust // Reuse previous precompile set OpSpecId::JOVIAN | OpSpecId::AZUL => Self::jovian(), // Or add a new set OpSpecId::AZUL => Self::azul(), ``` ### 11. Update spec resolution **File:** [`crates/common/evm/src/spec.rs`](https://github.com/base/base/blob/main/crates/common/evm/src/spec.rs) Add the new upgrade as the first check (newest upgrade wins): ```rust pub fn spec_by_timestamp_after_bedrock(chain_spec: impl BaseUpgrades, timestamp: u64) -> OpSpecId { if chain_spec.is_base_azul_active_at_timestamp(timestamp) { OpSpecId::AZUL } else if chain_spec.is_jovian_active_at_timestamp(timestamp) { OpSpecId::JOVIAN } // ... remaining checks unchanged } ``` **File:** [`crates/consensus/genesis/src/rollup.rs`](https://github.com/base/base/blob/main/crates/consensus/genesis/src/rollup.rs) Apply the same pattern in the `#[cfg(feature = "revm")] impl RollupConfig` block: ```rust pub fn spec_id(&self, timestamp: u64) -> base_revm::OpSpecId { if self.is_base_azul_active(timestamp) { base_revm::OpSpecId::AZUL } else if self.is_jovian_active(timestamp) { base_revm::OpSpecId::JOVIAN } // ... remaining checks unchanged } ``` ### 12. Update the Reth `ChainHardforks` builder **File:** [`crates/execution/upgrades/src/chain.rs`](https://github.com/base/base/blob/main/crates/execution/upgrades/src/chain.rs) Append the new upgrade in `to_chain_hardforks()`. If it pairs with a new Ethereum upgrade (like Canyon→Shanghai), push both; if not, push only the Base upgrade entry: ```rust // No paired Ethereum hardfork forks.push((BaseUpgrade::Jovian.boxed(), self[BaseUpgrade::Jovian])); forks.push((BaseUpgrade::Azul.boxed(), self[BaseUpgrade::Azul])); // <-- add ``` ## Checklist ### Always required - [ ] `BaseUpgrade` variant added in `upgrade.rs`; all four chain arrays updated - [ ] `Index` arm added in `chain.rs` - [ ] Config field (flat or nested struct) added to `HardForkConfig` in `upgrade.rs`; `iter()` updated; new types re-exported - [ ] `is_X_active` and `is_first_X_block` added to `RollupConfig`; `upgrade_activation` arm added; previous terminal upgrade cascades to new one (unless standalone) - [ ] `is_X_active_at_timestamp` added to `BaseUpgrades` trait - [ ] Timestamp constants added to `mainnet.rs`, `sepolia.rs`, `devnet_0_sepolia_dev_0.rs`; re-exported from `lib.rs` - [ ] Registry fixtures (`test_utils/mod.rs`) updated - [ ] Default rollup config updated (`defaults.rs`) - [ ] Upgrade consistency tests pass ### Required when EVM execution changes - [ ] `OpSpecId` variant added with `into_eth_spec` mapping and `#[strum(serialize = "...")]` attribute - [ ] Precompile match arm updated (or new precompile set added) - [ ] `spec_by_timestamp_after_bedrock` updated (`common/evm/src/spec.rs`) - [ ] `RollupConfig::spec_id` updated (`consensus/genesis/src/rollup.rs`) - [ ] `to_chain_hardforks` updated (`execution/upgrades/src/chain.rs`) --- # Avoid Malicious Flags Source: https://basehub.org/security/avoid-malicious-flags/ Description: Practical steps to keep your Base app from being flagged as malicious — verify contracts, request verification, and follow UX best practices. Keep your app from being flagged as malicious by verifying contracts, requesting verification with trusted ecosystem sources, and following standard UX practices. ## 1. Verify and reduce the risk of your smart contract - **Verify the contract source.** Publish verified source code for your contracts on [block explorers](/network/block-explorers/). For example, verification is available on [Etherscan](https://etherscan.io/verifyContract) and [Basescan](https://basescan.org/verifyContract) under "Verify Contract". - **Limit user-fund exposure.** Design contracts to keep user funds out of unnecessary risk paths. Request only the minimum amount needed to complete each transaction. ## 2. Submit a verification request After verifying your contract source, submit a [verification request](https://report.blockaid.io/). Verification helps ecosystem signal providers recognize your app as safe. ## 3. Follow app best practices - **Accessibility across regions.** Avoid geo-blocking or other access restrictions that lock out specific regions or countries. If legal or compliance requirements force restrictions, note them in the verification request. - **Consistent behavior.** Avoid sudden or unexplained UI changes that erode user trust in your app's reliability. - **Transparent onchain interactions.** The onchain action should match the UI. A "Mint" button should clearly emit a mint transaction. - **Standard sign-in methods.** Offer the standard wallet connection options — WalletConnect, Coinbase Wallet SDK, and the popular browser extension wallets. - **Audit your contracts.** Have your contracts audited by a reputable firm, publish the report, and link to it from your app so users can find it. An audit signals that you have invested in securing the codebase. Following these recommendations significantly reduces the chance of your app being flagged as malicious and helps maintain a secure, trustworthy environment for users. --- **Still flagged?** Coinbase Wallet may produce false positives. Confirm you have completed the actions above first. If your app remains flagged as suspicious or malicious, [report it to Blockaid](https://report.blockaid.io/mistake). --- # Bug Bounty Source: https://basehub.org/security/bug-bounty/ Description: Coinbase's million-dollar HackerOne bug bounty program covers Base, the Base bridge contracts, and Base infrastructure. The Coinbase HackerOne bug bounty program covers the Base network, the Base bridge contracts, and Base infrastructure, with vulnerability reports triaged around the clock. ## Program coverage In line with Base's strategy of being the safest way for users to access crypto, Coinbase extends its [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to: - The Base network - The Base bridge contracts - Base infrastructure Coinbase's program runs alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/), which covers the open-source [Bedrock](https://docs.optimism.io/stack/getting-started) OP Stack framework. ## Submitting a report All potential vulnerabilities should be submitted via the [HackerOne platform](https://hackerone.com/coinbase). Reports are triaged by Coinbase engineers with relevant domain expertise, ensuring rapid SLAs and high-quality review. For program scope, eligibility, and reward details, see the [security program policies](https://hackerone.com/coinbase?view_policy=true). ## Related - [Reporting Vulnerabilities](/security/report-vulnerability/) — full procedure for submitting a vulnerability report. - [Security Council for Base](/security/security-council/) — the multi-party group that signs off on Base contract upgrades. --- # Reporting Vulnerabilities Source: https://basehub.org/security/report-vulnerability/ Description: Submit Base vulnerability reports through the Coinbase HackerOne program for centralized triage and bug bounty coverage. Submit any potential vulnerability in Base, the Base bridge contracts, or Base infrastructure through the [Coinbase HackerOne program](https://hackerone.com/coinbase). HackerOne provides a single, centralized intake that the team uses to deliver consistent SLAs and outcomes. Every report is triaged around the clock by Coinbase engineers with the relevant domain expertise, keeping review quality high. ## Bug bounty program In keeping with the goal of making Base the safest way to access crypto: - Coinbase extends its [best-in-industry](https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program) million-dollar [HackerOne bug bounty program](https://hackerone.com/coinbase?type=team) to cover the Base network, the Base bridge contracts, and Base infrastructure. - Coinbase's bug bounty program runs alongside Optimism's existing [Immunefi Bedrock bounty program](https://immunefi.com/bounty/optimism/), which supports the open-source [Bedrock](https://docs.optimism.io/stack/getting-started) OP Stack framework. For full reporting procedures and program details, see the Coinbase [security program policies](https://hackerone.com/coinbase?view_policy=true). --- # Security Council for Base Source: https://basehub.org/security/security-council/ Description: Composition, quorum rules, member criteria, and responsibilities of the Security Council that approves Base contract upgrades. The Security Council for Base is the multi-party group of independent entities and individuals whose signatures are required to approve Base Chain contract upgrades. ## Purpose Base's mission is to build a global onchain economy that increases innovation, creativity, and freedom. That mission is only possible on a decentralized platform. Base is therefore (1) built on Ethereum, the most secure and decentralized L1; (2) built in the [open](https://github.com/base/base); and (3) committed to a clear set of [Neutrality Principles](https://www.coinbase.com/blog/coinbases-neutrality-principles-for-base). As part of the ongoing decentralization roadmap, Base launched [permissionless fault proofs](https://base.mirror.xyz/eOsedW4tm8MU5OhdGK107A9wsn-aU7MAb8f3edgX5Tk) in October 2024, [decentralized control of contract upgrades](https://base.mirror.xyz/tWDMlGp48fF0MeADcLQruUBq1Qxkou4O5x3ax8Rm3jA) via a Security Council in April 2025, and has now reached Stage 1 Decentralization. Reaching **Stage 1** means Base offers stronger security guarantees and fewer trust assumptions. Builders gain infrastructure certainty (no surprise rule changes), and there is no single point of failure — anyone can participate in verifying and securing the network. ## Structure **Composition and quorum** Stage 1 Decentralization requires that the group approving Base Chain contract upgrades contain: - at least 8 participants - a ≥75% quorum - a quorum-blocking group outside the main rollup operator (Base) In addition to Coinbase, the Security Council includes 11 independent entities and individuals from geographically diverse regions. To meet the ≥75% quorum, 9 of the 12 entities (the 11 Security Council members plus Coinbase) must approve any Base upgrade. Upgrades cannot take effect until that quorum signs and approves them. This composition meets all requirements. **Member selection criteria** - Representation across diverse geographic regions and international territories - Strong alignment with [Base's mission and values](https://base.mirror.xyz/jjQnUq_UNTQOk7psnGBFOsShi7FlrRp8xevQUipG_Gk) - Diverse organizations — each member represents a separate entity - Proven track record in the Base and Ethereum ecosystem and good standing in upholding professional and ethical standards in the community - Technical competency and good security practices — completed screening processes including background checks, with demonstrated ability to securely store and use sensitive key material **Current roster** This list stays current with membership. As of February 2026, the Security Council includes the following entities and individuals, based in the listed jurisdictions: - [Entity] Aerodrome — signer based in Japan - [Aerodrome](https://aerodrome.finance/) is a decentralized exchange on Base where users swap, earn rewards, and participate in the onchain economy. - `0xa5959a39cA67b9fb473E4A3A898C611EEAc9CB73` - [Entity] Moonwell — signer based in Brazil - [Moonwell](https://moonwell.fi/) is a decentralized lending and borrowing platform built on Base. - `0x21C7D1e6A81Daca071bA94839ab74C39A25f851F` - [Entity] Blackbird — signer based in USA - [Blackbird](https://www.blackbird.xyz/) is a loyalty and payments platform built specifically for the restaurant industry, powered by Base. - `0xA5657B88A0130a626fcDd6aAA59522373438CdFE` - [Entity] ChainSafe — signer based in Canada - [ChainSafe](https://chainsafe.io/) is a blockchain R&D firm focused on decentralized infrastructure. - `0x1C56A6d2A6Af643cea4E62e72B75B9bDe8d62e2B` - [Entity] Talent Protocol — signer based in Portugal - [Talent Protocol](https://app.talentprotocol.com/) brings professional reputation onchain to help Base builders showcase their skills and get the recognition they deserve. - `0x5ff5C78ff194acc24C22DAaDdE4D639ebF18ACC6` - [Entity] Moshicam — signer based in USA - [Moshicam](https://moshi.cam/) is a community-based photo editing app built on Base. - `0xa8ee754FD1d069fb4B5d652730A0ca5e07a3fb06` - [Individual] Seneca — based in USA - Seneca is the co-founder of [Rounds](https://rounds.wtf/), a social platform that has [powered](https://x.com/jessepollak/status/1781069700652523725) grant distribution to Base builders. - `0x82C80F34C4b5c153dB76122a11AaD2F77C99E766` - [Individual] Juan Suarez — based in USA - Juan is an active member of the Base ecosystem and has advised a number of key Base projects. He is a former member of the Coinbase Legal Team. - `0x99DB5BbA0db16e9aD05e3ff53310683CC3C971D2` - [Individual] Toady Hawk — based in Canada - [Toady Hawk](https://farcaster.xyz/toadyhawk.eth) is the founder of [Zero Rights Media](https://farcaster.xyz/zerorightsmedia), an open-source onchain media org on Base (producers of ZEROPOD), and [The Yellow Collective](https://farcaster.xyz/basedandyellow), an onchain culture club for artists and creators on Base. - `0x0E8A99738a50D523871739c6d676554b0E34252f` - [Individual] Roberto Bayardo — based in USA - [Roberto Bayardo](https://farcaster.xyz/bayardo.eth) is an engineer at Commonware, building a framework for high-performance blockchains. He is a former core Base contributor. - `0x18e982274f8C5B548D5aAc7aBef44D61504e1b3E` - [Individual] Yele Bademosi — based in the UK - [Yele Bademosi](https://x.com/YeleBademosi) is the co-founder of [Onboard](https://www.onboard.xyz/) and a longtime builder in the Base ecosystem, previously founding Bundle and investing in early-stage technology companies via Microtraction. The individual representatives for each entity are not published, to protect personal privacy and improve security. **Member terms** The Security Council for Base operates on a staggered "cohort" model: - Cohort 1 — current term lasts until October 2026 - Cohort 2 — current term lasts until January 2027 ## Roles and responsibilities **Review and approve changes** - Members are notified of proposed upgrades and must verify, approve, and sign them. - Members must verify, approve, and sign role changes (key rotations for lost devices, member rotations, and similar). Any key rotations are designed not to disrupt quorum or security. **Maintain availability and lines of communication** - Be reachable for scheduled signings, coordination calls, and emergencies. - Coordinate with other members to resolve urgent issues. **Preserve key security** - Generate and store key material securely. - Use the keys only for activities directly tied to the Security Council role (upgrades and ownership changes). - Report any suspected loss of access or compromise immediately. - Complete onchain safety and security training at the start of each term. - Participate in periodic liveness checks by signing a message to confirm continued control of the key. **Act in good faith** - Avoid conflicts of interest and disclose any potential conflicts. - Help remove or replace dysfunctional signers without compromising security. ## The future The Security Council for Base is a meaningful step toward a more decentralized, resilient, and secure Base network. Distributing key responsibilities across trusted, independent participants — combined with permissionless fault proofs — reduces reliance on any single entity and strengthens guarantees for users, builders, and the broader ecosystem. This is the start, not the end. As Base evolves, the Security Council's role will be progressively minimized, opening the path to even more trustless infrastructure beyond Stage 1 — Stage 2 — and broader community control. The mission stays the same: build a global onchain economy that empowers innovation, creativity, and freedom on a foundation everyone can rely on. Base is for everyone. --- # Access Lists Specification Source: https://basehub.org/specifications/access-lists/ Description: Flashblock-Level Access Lists (FAL) — adapting EIP-7928 for flashblock chains. Flashblock-Level Access Lists (FAL) adapt [EIP-7928](https://eips.ethereum.org/EIPS/eip-7928) Block-Level Access Lists for chains that emit flashblocks, including Base. This specification defines their data structures, recording semantics, and validation rules. :::note The canonical source is [`docs/specs/access-lists.md`](https://github.com/base/base/blob/main/docs/specs/access-lists.md) in the base/base repository. ::: ## Abstract FAL records every account and storage location accessed during flashblock execution, along with post-execution values. This enables parallel disk reads, parallel transaction validation, and state reconstruction without full re-execution. ## Motivation Standard BAL (EIP-7928) targets L1 Ethereum where blocks are atomic units. Base produces **flashblocks** -- incremental sub-block deltas streamed at 200ms intervals. FAL adapts the access-list concept to this architecture by: - Operating on incremental flashblock deltas rather than complete blocks. - Handling OP Stack-specific transaction types (L1 attributes, L1-to-L2 deposits). - Tracking three separate fee vaults instead of a single `COINBASE`. - Omitting beacon chain features absent from the OP Stack (EIP-4895 withdrawals, EIP-4788 beacon root, EIP-7002/7251 validator operations). ## Key Differences from BAL | Aspect | BAL (EIP-7928) | FAL | |--------|----------------|-----| | Unit of operation | Complete block | Flashblock delta (incremental) | | Hash storage | Block header | Flashblock metadata | | Fee recipient | Single `COINBASE` | Three OP Stack fee vaults | | Transaction types | Standard + withdrawals | Standard + L1 attributes + L1-to-L2 deposits | | Beacon chain features | Included | Omitted | ### OP Stack Fee Vaults Instead of recording balance changes against `COINBASE`, FAL tracks three separate fee vault addresses: | Vault | Address | Purpose | |-------|---------|---------| | Sequencer Fee Vault | `0x4200000000000000000000000000000000000011` | Priority fees | | Base Fee Vault | `0x4200000000000000000000000000000000000019` | Base fees | | L1 Fee Vault | `0x420000000000000000000000000000000000001a` | L1 data fees | ### L1 Attributes Transaction The first transaction in each block (index 0) is the L1 attributes transaction. It updates the L1Block contract (`0x4200000000000000000000000000000000000015`) storage slots: | Slot | Content | |------|---------| | 0 | L1 block number | | 1 | L1 base fee | | 2 | L1 timestamp | | 3 | Batcher hash | | 4 | Sequence number | | 5 | Blob base fee | | 6 | L1 block hash | ### L1-to-L2 User Deposits L1-to-L2 deposits are treated as regular transactions with block access indices `1..n`. The FAL records sender and recipient addresses with their balance changes. --- ## Specification ### Data Structures #### FlashblocksPayloadV1 ```rust pub struct FlashblocksPayloadV1 { pub payload_id: PayloadId, pub index: u64, pub base: Option, pub diff: ExecutionPayloadFlashblockDeltaV1, pub metadata: Value, // Contains "flashblock_access_list" } ``` #### FlashblockAccessList ```rust pub struct FlashblockAccessList { pub min_tx_index: u64, // Inclusive starting transaction index pub max_tx_index: u64, // Exclusive ending transaction index pub account_changes: Vec, // All account state changes pub fal_hash: B256, // Keccak-256 of RLP-encoded changes } ``` ### RLP Data Structures The following Python-style type aliases define the RLP encoding: ```python Address = bytes # 20-byte Ethereum address StorageKey = bytes # 32-byte storage slot key StorageValue = bytes # 32-byte storage value CodeData = bytes # Variable-length bytecode BlockAccessIndex = uint16 Balance = uint256 Nonce = uint64 # Constants (OP Stack adapted) MAX_TXS = 30_000 MAX_SLOTS = 300_000 MAX_ACCOUNTS = 300_000 MAX_CODE_SIZE = 24_576 MAX_CODE_CHANGES = 1 # Change structures StorageChange = [BlockAccessIndex, StorageValue] BalanceChange = [BlockAccessIndex, Balance] NonceChange = [BlockAccessIndex, Nonce] CodeChange = [BlockAccessIndex, CodeData] SlotChanges = [StorageKey, List[StorageChange]] AccountChanges = [ Address, List[SlotChanges], # storage_changes List[StorageKey], # storage_reads List[BalanceChange], # balance_changes List[NonceChange], # nonce_changes List[CodeChange] # code_changes ] FlashblockAccessList = List[AccountChanges] ``` ### Scope and Inclusion Rules The following must be included in the `FlashblockAccessList`: - **Addresses with state changes** -- any account whose storage, balance, nonce, or code was modified. - **Inspection targets** -- targets of `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, `EXTCODEHASH`. - **Call targets** -- targets of `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`. - **Creation targets** -- addresses produced by `CREATE` and `CREATE2`. - **Transaction parties** -- senders and recipients of every transaction. - **Fee vault addresses** -- all three OP Stack fee vaults listed above. - **`SELFDESTRUCT` beneficiaries** -- addresses receiving self-destructed balances. - **System contracts** -- L1Block contract (`0x4200...0015`) and EIP-2935 block hash contract. - **L1-to-L2 deposit recipients** -- recipients of cross-chain deposits. - **Precompiled contracts** -- when accessed during execution. - **L1Block during L1 attributes execution** -- always included in the first flashblock. Addresses without state changes must still appear with empty change lists. ### Ordering and Determinism To ensure deterministic encoding: - **Addresses** are sorted lexicographically (bytewise ascending). - **Storage keys** are sorted lexicographically within each account. - **Block access indices** are sorted in ascending order within each change list. ### BlockAccessIndex Assignment | Index Value | Assigned To | |-------------|-------------| | `0` | Pre-execution system contracts and L1 attributes transaction (first flashblock only, where `min_tx_index = 0`). | | `min_tx_index` ... `max_tx_index - 1` | Transactions within the flashblock, including L1-to-L2 deposits and regular transactions. | | `n + 1` | Post-execution system contracts (final flashblock only). | ### Recording Semantics #### Storage **Writes** (recorded in `storage_changes`): - Any value change where the post-execution value differs from the pre-execution value. - Zeroing a slot (pre-execution value exists, post-execution value is zero). **Reads** (recorded in `storage_reads`): - `SLOAD` without a corresponding write. - No-op writes where `SSTORE` is called but the post-execution value equals the pre-execution value. #### Balance Changes Post-transaction balances are recorded for: - **Senders** -- after gas cost, transferred value, and L1 data fee are deducted (including gas refunds). - **Recipients** -- only when transferred value is greater than zero. - **Fee vaults** -- updated balance after each transaction. - **`SELFDESTRUCT` / `SENDALL` beneficiaries** -- balance after receiving funds. - **Deposit recipients** -- balance after the deposit is credited. For zero-value transfers, the address is included but omitted from `balance_changes`. #### Code Changes Post-transaction runtime bytecode is recorded for: - Contracts deployed via `CREATE` or `CREATE2`. - Contracts modified via `SELFDESTRUCT` (if applicable). - EIP-7702 delegation indicators. #### Nonce Changes Post-transaction nonces are recorded for: - EOA senders (incremented by transaction execution). - Successful `CREATE` performers (nonce incremented). - Newly deployed contracts (nonce set to 1). - EIP-7702 authorities (nonce incremented on successful delegation). ### OP Stack Edge Cases - **Precompiles**: Include when accessed. Record a balance change if the precompile receives value. - **`SENDALL`**: Record both sender (balance to zero) and beneficiary (balance increased). - **`SELFDESTRUCT`**: Include without nonce/code changes. Record balance-to-zero if pre-transaction balance was positive. Include storage reads. - **Gas refunds**: The final sender balance (after refunds) is the recorded value. - **Exceptional halts (reverts/out-of-gas)**: Record the final nonce and balance of the sender and fee vaults. Include all accessed addresses even if execution was reverted. - **EIP-7702**: The authority address must be included with nonce/code changes after a successful delegation operation, and with empty changes if the delegation fails. ### Empty State When no state changes exist in a flashblock: - `account_changes` is an empty list. - `fal_hash` equals the Keccak-256 of an empty RLP list: `0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347`. ### Validation The following pseudocode describes FAL validation: ```python def validate_fal(flashblock, provided_fal): # 1. Extract the FAL from flashblock metadata fal = extract_fal(flashblock.metadata) # 2. Verify the provided hash matches the encoded account_changes encoded = rlp_encode(fal.account_changes) expected_hash = keccak256(encoded) assert fal.fal_hash == expected_hash, "FAL hash mismatch" # 3. Execute the flashblock and collect actual accesses actual_accesses = execute_flashblock(flashblock) actual_encoded = rlp_encode(actual_accesses) actual_hash = keccak256(actual_encoded) # 4. Verify actual execution matches the provided FAL assert actual_hash == fal.fal_hash, "Execution mismatch" return True ``` --- ## Performance FAL enables the following optimizations: - **Parallel disk reads** -- storage slots and account data can be prefetched across transactions. - **Parallel transaction validation** -- independent transactions can be validated concurrently. - **State reconstruction without execution** -- post-state can be derived from the access list alone. - **Compact representation** -- expected size is approximately 40--50 KiB compressed on average, comparable to BAL. ## Source Canonical specification: [docs/specs/access-lists.md](https://github.com/base/base/blob/main/docs/specs/access-lists.md) --- # Flashblocks Specification Source: https://basehub.org/specifications/flashblocks/ Description: JSON-RPC methods, parameters, and return types exposed by the Flashblocks RPC provider. The Flashblocks RPC provider extends standard Ethereum JSON-RPC methods to query preconfirmed flashblock state via the `pending` tag. The methods, parameters, and return types are specified below. :::note This document serves as a reference for the current implementation and may differ from the full Flashblocks specification in terms of scope and methods implemented. The canonical source is [`docs/specs/flashblocks.md`](https://github.com/base/base/blob/main/docs/specs/flashblocks.md) in the base/base repository. ::: ## Type Definitions All types used in these RPC methods are identical to the standard OP Stack RPC types. No modifications have been made to the existing type definitions. ## Modified Ethereum JSON-RPC Methods The following standard Ethereum JSON-RPC methods are enhanced to support the `pending` tag for querying preconfirmed state. ### `eth_getBlockByNumber` Returns block information for the specified block number. #### Parameters | Name | Type | Description | |------|------|-------------| | `blockNumber` | `String` | Block number (hex) or tag. Use `"pending"` for preconfirmed state. | | `fullTransactions` | `Boolean` | If `true`, returns full transaction objects; if `false`, returns transaction hashes. | #### Returns `Object` -- Block object, or `null` if the block does not exist. #### Example ```json // Request { "method": "eth_getBlockByNumber", "params": ["pending", false], "id": 1, "jsonrpc": "2.0" } // Response { "id": 1, "jsonrpc": "2.0", "result": { "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", "parentHash": "0x...", "stateRoot": "0x...", "transactionsRoot": "0x...", "receiptsRoot": "0x...", "number": "0x123", "gasUsed": "0x5208", "gasLimit": "0x1c9c380", "timestamp": "0x...", "extraData": "0x", "mixHash": "0x...", "nonce": "0x0", "transactions": ["0x..."] } } ``` #### Response Fields | Field | Description | |-------|-------------| | `hash` | Block hash calculated from the current flashblock header. | | `parentHash` | Hash of the parent block. | | `stateRoot` | Current state root from the latest flashblock. | | `transactionsRoot` | Transactions trie root. | | `receiptsRoot` | Receipts trie root. | | `number` | Block number being built. | | `gasUsed` | Cumulative gas used by all transactions. | | `gasLimit` | Block gas limit. | | `timestamp` | Block timestamp. | | `extraData` | Extra data bytes. | | `mixHash` | Mix hash value. | | `nonce` | Block nonce value. | | `transactions` | Array of transaction hashes or full transaction objects. | --- ### `eth_getTransactionReceipt` Returns the receipt for a transaction. When the transaction exists only in the preconfirmed (flashblock) state, the receipt is still returned -- enabling callers to confirm inclusion before the block is finalized. #### Parameters | Name | Type | Description | |------|------|-------------| | `transactionHash` | `String` | Hash of the transaction. | #### Returns `Object` -- Transaction receipt, or `null` if the transaction is not found. #### Example ```json // Request { "method": "eth_getTransactionReceipt", "params": ["0x..."], "id": 1, "jsonrpc": "2.0" } // Response { "id": 1, "jsonrpc": "2.0", "result": { "transactionHash": "0x...", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x123", "transactionIndex": "0x0", "from": "0x...", "to": "0x...", "gasUsed": "0x5208", "cumulativeGasUsed": "0x5208", "effectiveGasPrice": "0x...", "status": "0x1", "contractAddress": null, "logs": [], "logsBloom": "0x..." } } ``` #### Response Fields | Field | Description | |-------|-------------| | `transactionHash` | Hash of the transaction. | | `blockHash` | Zero hash (`0x000...000`) for preconfirmed transactions. | | `blockNumber` | Block number containing the transaction. | | `transactionIndex` | Index of the transaction in the block. | | `from` | Sender address. | | `to` | Recipient address. | | `gasUsed` | Gas used by this transaction. | | `cumulativeGasUsed` | Total gas used up to and including this transaction. | | `effectiveGasPrice` | Effective gas price paid. | | `status` | `0x1` for success, `0x0` for failure. | | `contractAddress` | Address of created contract (for contract creation transactions), otherwise `null`. | | `logs` | Array of log objects emitted by the transaction. | | `logsBloom` | Bloom filter for the logs. | --- ### `eth_getBalance` Returns the balance of an account. #### Parameters | Name | Type | Description | |------|------|-------------| | `address` | `String` | Address to query. | | `blockNumber` | `String` | Block number (hex) or tag. Use `"pending"` for preconfirmed state. | #### Returns `String` -- Account balance in wei, hex-encoded. #### Example ```json // Request { "method": "eth_getBalance", "params": ["0x...", "pending"], "id": 1, "jsonrpc": "2.0" } // Response { "id": 1, "jsonrpc": "2.0", "result": "0x1bc16d674ec80000" } ``` --- ### `eth_getTransactionCount` Returns the number of transactions sent from an address (the account nonce). #### Parameters | Name | Type | Description | |------|------|-------------| | `address` | `String` | Address to query. | | `blockNumber` | `String` | Block number (hex) or tag. Use `"pending"` for preconfirmed state. | #### Returns `String` -- Transaction count (nonce), hex-encoded. #### Example ```json // Request { "method": "eth_getTransactionCount", "params": ["0x...", "pending"], "id": 1, "jsonrpc": "2.0" } // Response { "id": 1, "jsonrpc": "2.0", "result": "0x5" } ``` --- ## Behavior Notes ### Pending Tag Usage - When `"pending"` is used as the block tag, the method queries preconfirmed state from the flashblocks cache. - If no preconfirmed data is available, the method falls back to the latest confirmed state. - For non-pending queries (e.g., `"latest"`, `"finalized"`, or a specific block number), the method behaves identically to standard Ethereum JSON-RPC. ### Error Handling - Standard JSON-RPC error responses are returned for invalid requests. - `null` is returned for non-existent transactions or blocks. - When flashblocks are disabled or unavailable, the RPC falls back to standard behavior transparently. ## Source Canonical specification: [docs/specs/flashblocks.md](https://github.com/base/base/blob/main/docs/specs/flashblocks.md) --- # P2P Networking Stack Source: https://basehub.org/specifications/p2p/ Description: How Base nodes discover peers and gossip blocks across two independent P2P stacks — discv5 plus libp2p on the consensus layer and DevP2P plus RLPx on execution. import { Aside } from '@astrojs/starlight/components'; Base nodes run two independent peer-to-peer networks — one for the consensus layer (CL) and one for the execution layer (EL) — and bridge them locally through the Engine API. This guide walks through both stacks, why they exist, and where the relevant code lives in [`base/base`](https://github.com/base/base). ## Why P2P matters A blockchain is a network of computers that must coordinate without a central server. Peer-to-peer networking provides that coordination. Each node connects to a handful of peers, and those peers connect to others, forming a mesh — a web of overlapping links where every node can reach every other node by some path. When a node sees a new block or transaction, it relays it to its neighbors, and within seconds the entire network has converged. This propagation pattern is gossip. P2P networking solves three problems: 1. **Discovery** — how a fresh node finds peers to connect to. 2. **Transport** — how two nodes establish a secure session and exchange data. 3. **Gossip** — how connected nodes broadcast new information efficiently without flooding the network. ## Why Ethereum has two P2P layers Before The Merge in September 2022, Ethereum ran a single P2P network. Every node ran one execution client (such as Geth) that handled discovery, transaction gossip, block propagation, and proof-of-work consensus. The networking stack was DevP2P, a custom protocol suite designed for Ethereum starting in 2014. The Merge introduced a second binary: the consensus client. Consensus clients follow the beacon chain — a separate chain coordinating proof-of-stake — and decide which blocks are canonical. The beacon chain was designed from scratch on libp2p rather than DevP2P because libp2p is more modular and better suited to the publish/subscribe patterns required for attestation and block gossip in proof-of-stake. Merging the stacks would have been a massive undertaking with little practical benefit, so Ethereum kept them separate and bridged them with a local API. After The Merge, every Ethereum node runs two processes with two separate P2P networks. The execution layer continues to use DevP2P over RLPx (an encrypted transport described later) for transaction and historical block exchange. The consensus layer uses libp2p with gossipsub (a broadcast protocol described later) for beacon blocks and attestations. The two layers communicate locally through the Engine API — JSON-RPC over HTTP or WebSocket on localhost. A rollup like Base inherits the same two-layer architecture but ships different payloads. Where Ethereum L1 gossips beacon blocks and attestations from hundreds of thousands of validators, Base's CL gossips L2 execution payloads — the new blocks produced by the sequencer (the single designated node that orders and produces L2 blocks). The sequencer signs each block with its private key so other nodes can verify it came from the authorized producer rather than from an attacker. It then publishes the signed block to the CL gossip network, and every Base node picks it up from there. This is a latency optimization, not a security mechanism. Rollup security comes entirely from L1: batch data posted to Ethereum L1 is the canonical source of truth, and the derivation pipeline (software that reconstructs L2 state from L1 batch data) can rebuild the entire L2 chain from L1 alone. P2P gossip lets nodes see new L2 blocks several minutes before the corresponding batch lands on L1, reducing user-visible latency. The EL still runs a DevP2P network for transaction pool gossip and historical sync, though in practice the sequencer often receives transactions directly rather than through EL gossip. ## How the CL and EL communicate: the Engine API Before walking through each stack, it helps to know how they connect. The consensus and execution clients do not share a P2P network — they share a local RPC bridge called the Engine API: a JSON-RPC interface exposed by the execution client (typically on port 8551) and secured with JWT authentication, a shared-secret mechanism that proves the caller is authorized. Only the co-located consensus client can issue these calls. The Engine API has three core methods. Think of it as a three-step exchange: "start building a block," "give me what you built," and "here's a block someone else built — check it." `engine_forkchoiceUpdated` tells the execution client which block is the current head, the latest safe block, and the latest finalized block. When the consensus client also passes optional payload attributes (timestamp, fee recipient, and other parameters describing the block to build), the call additionally instructs the execution client to begin assembling a new block. `engine_getPayload` retrieves the block the execution client has been assembling from its mempool. `engine_newPayload` sends an execution payload received from gossip to the execution client for validation and execution. The execution client re-executes all transactions, verifies the state root (a cryptographic fingerprint of the entire blockchain state after executing the block's transactions), and responds with VALID, INVALID, or SYNCING (meaning the node has not caught up to the chain tip yet and cannot validate the block). For block production on Base, the flow is: the sequencer's CL calls `engine_forkchoiceUpdated` with payload attributes to start building, waits, calls `engine_getPayload` to retrieve the built payload, signs it, and publishes it to the CL gossip network. For block validation, the flow is reversed: the CL receives a signed block from gossip, validates the signature, sends the execution payload to the EL via `engine_newPayload`, and uses the validity response to accept or reject the block. This separation lets each layer evolve its networking independently. It also means implementations are swappable — any CL and EL that speak the Engine API can be paired. ## The consensus layer P2P stack The Base consensus P2P stack lives under [`crates/consensus/`](https://github.com/base/base/tree/main/crates/consensus) and is composed of four crates that layer on top of one another: peers, disc, gossip, and the network actor in the service crate. ### Peers — the foundation The [`base-consensus-peers`](https://github.com/base/base/tree/main/crates/consensus/peers) crate provides the fundamental types for identifying and managing peers on the consensus network. The central concept is the ENR (Ethereum Node Record), defined in [EIP-778](https://eips.ethereum.org/EIPS/eip-778). An ENR is a compact, self-describing identity document a node uses to advertise itself. It is encoded with RLP (Recursive Length Prefix, Ethereum's standard binary serialization format) and contains a cryptographic signature, a monotonically increasing sequence number (so newer records always rank higher), and a sorted set of key-value pairs. Predefined keys include `id` (the identity scheme — currently "v4" for secp256k1, the elliptic curve Ethereum uses for public-key cryptography), `secp256k1` (the node's compressed 33-byte public key), `ip` (IPv4 address), and `tcp`/`udp` (port numbers). When a node's information changes (for example, its IP address rotates), it bumps the sequence number and re-signs the record; the signature ensures records cannot be tampered with. ENRs are deliberately small (300 bytes maximum) because they propagate frequently and may need to fit in constrained transports such as DNS TXT records. Different layers of the Ethereum stack use ENR extension keys for chain-specific metadata. Ethereum L1's execution layer carries an `eth` key with fork ID information. The L1 consensus layer carries an `eth2` key with the fork digest and attestation subnet bitfield. On Base — and OP Stack chains in general — every ENR includes an `opstack` key encoding the L2 chain ID and a version number. This is how nodes on different chains (Base Mainnet versus Base Sepolia) tell each other apart during discovery. ENRs are typically displayed as a base64-encoded string prefixed with `enr:`. The [`BaseEnr`](https://github.com/base/base/blob/main/crates/consensus/peers/src/enr.rs) struct handles this encoding: ```rust /// The unique L2 network identifier pub struct BaseEnr { /// Chain ID pub chain_id: u64, /// The version. Always set to 0. pub version: u64, } impl BaseEnr { /// The ENR key literal string for the consensus layer. pub const OP_CL_KEY: &str = "opstack"; /// Constructs a BaseEnr from a chain id. pub const fn from_chain_id(chain_id: u64) -> Self { Self { chain_id, version: 0 } } } ``` When a node discovers another node's ENR, [`EnrValidation`](https://github.com/base/base/blob/main/crates/consensus/peers/src/enr.rs) checks that the `opstack` key is present, decodes correctly, and that the chain ID matches. If a Base Mainnet node (chain ID 8453) sees an ENR for a different chain, it ignores it. The peers crate also provides a [`BootStore`](https://github.com/base/base/blob/main/crates/consensus/peers/src/store.rs), a JSON file that persists discovered ENRs to disk so the node does not need to bootstrap discovery from scratch on every restart. The store caps at 2048 entries and prunes the oldest when full. ### Discovery — finding peers with discv5 The [`base-consensus-disc`](https://github.com/base/base/tree/main/crates/consensus/disc) crate implements peer discovery using discv5. Discv5 is a UDP-based protocol that maintains a distributed hash table (DHT) of node records. It succeeds discv4 (used by the EL) and was designed for the consensus layer's needs. Discv5 is inspired by Kademlia, an academic DHT protocol from 2002. A DHT is a system where many computers collectively maintain a lookup directory without a central coordinator. The Kademlia insight is using XOR as a distance metric. Every node has a 256-bit ID derived from its public key; the "distance" between two nodes is the XOR of their IDs interpreted as a number. The metric is symmetric (distance A→B equals B→A) and unrelated to physical or network distance. Two nodes with similar IDs can sit on opposite sides of the planet. Think of comparing two phone numbers digit by digit: numbers sharing a long prefix are "close" in Kademlia space even if the people holding them live in different countries. Each node maintains a routing table organized into 256 "k-buckets" — one per possible bit-length of XOR distance. Bucket 0 holds nodes whose IDs differ from the local ID only in the least significant bit; bucket 255 holds nodes that differ in the most significant bit. Each bucket holds up to k entries (typically k=16). Imagine sorting your contacts into folders by how their IDs differ from yours — most contacts end up in "close" folders and fewer in the "far" folders, which is the right shape for efficient lookups. To discover new peers, a node performs an iterative lookup: it picks a target ID (often random, to populate its routing table), finds the closest nodes it already knows, and sends them FINDNODE requests. Unlike discv4, which asks for nodes "near" a specific ID, discv5 FINDNODE requests specify a logarithmic distance — a number from 0 to 256 representing the bit position where IDs first differ ("give me all nodes at XOR distance 2^n from you"). It is more efficient and harder to abuse. The node receives lists of nodes at that distance, queries those newly learned nodes, and gets progressively closer to the target with each round. Fresh nodes bootstrap by connecting to a small set of well-known bootnodes whose addresses are hardcoded into the client. The bootnode responds to FINDNODE requests, giving the new node its first set of peers. From there the new node performs a few random lookups to fill its routing table and within minutes has a healthy set of diverse peers. The [`Discv5Driver`](https://github.com/base/base/blob/main/crates/consensus/disc/src/driver.rs) orchestrates discovery. On startup it initializes the discv5 UDP service with exponential backoff retries (waiting progressively longer between attempts — for example 1s, 2s, 4s, 8s). Once that succeeds, it starts the event stream, retrying up to 10 times with 2-second delays if initialization fails. Then it bootstraps by loading the boot store from disk and adding hardcoded boot nodes. Each ENR is validated against the expected chain ID before being added to the routing table: ```rust let validation = EnrValidation::validate(&enr, chain_id); if validation.is_invalid() { trace!(target: "discovery::bootstrap", enr = ?enr, validation = ?validation, "Ignoring Invalid Bootnode ENR"); continue; } if let Err(e) = disc.add_enr(enr.clone()) { debug!(target: "discovery::bootstrap", error = ?e, "Failed to add enr"); continue; } store.add_enr(enr); ``` After bootstrapping, the driver enters its main loop, doing several things concurrently via `tokio::select!` (a Rust macro that waits on multiple async operations and runs the code for whichever completes first). It runs periodic random node queries (every 5 seconds by default) to keep discovering peers. It listens for discv5 events such as `Discovered`, `SessionEstablished`, and `UnverifiableEnr`, and when it sees a valid ENR it forwards it through an `mpsc` (multi-producer, single-consumer) channel to the gossip layer so it can dial the peer. An `mpsc` channel is a thread-safe queue where multiple senders push to a single receiver — the primary way components communicate in async Rust. The driver also persists the current set of known ENRs to the boot store every 60 seconds. The driver communicates with the rest of the system through a [`Discv5Handler`](https://github.com/base/base/blob/main/crates/consensus/disc/src/handler.rs), a thin wrapper around an `mpsc::Sender`. Other parts of the system can request metrics, peer lists, the local ENR, or ask discovery to ban specific addresses. This channel-based design avoids shared mutable state across async boundaries. ### Gossip — broadcasting blocks with libp2p and gossipsub The [`base-consensus-gossip`](https://github.com/base/base/tree/main/crates/consensus/gossip) crate is where the action happens — this is the layer that actually receives and broadcasts L2 blocks across the network. Gossipsub is a publish/subscribe protocol on libp2p that solves the problem of distributing messages efficiently in a decentralized network where no node can be trusted. The naive approach (floodsub) forwards every message to every peer — it works but consumes huge bandwidth because every node receives each message from multiple sources. Gossipsub instead builds a sparse "mesh" overlay per topic. When a node subscribes to a topic, it announces the subscription to its peers. It then selects D peers (the "desired mesh degree") that are also subscribed to the topic and establishes mesh links by sending GRAFT control messages. Mesh links are symmetric: if A grafts B, B also considers A part of its mesh. When a message is published, it flows eagerly through these links — each receiving node forwards the message to all of its mesh peers for that topic (except the sender). The result is a connected overlay where messages propagate in O(log N) hops with bounded bandwidth per node. The protocol layers reliability on top of the mesh. Every heartbeat interval, each node sends IHAVE control messages to a random subset of non-mesh peers, listing recently seen message IDs. If a peer has not seen one of those messages (perhaps a mesh path failed or was slow), it replies with IWANT and the original node sends the full message. This lazy repair ensures messages reach everyone within a few heartbeat rounds even if the mesh is partitioned or a peer drops out. PRUNE messages are the inverse of GRAFT: a node sends PRUNE to remove a peer from its mesh, either because the mesh is too large or the peer's score is poor. Pruned peers are not disconnected — they simply move from the eager-push mesh to the lazy-gossip pool. Gossipsub v1.1, which Base uses, adds a peer scoring system. Each node evaluates its peers based on behavior (whether they deliver valid messages promptly, whether they spam duplicates) and preferentially keeps well-scored peers in the mesh while pruning poorly scored ones. A peer that repeatedly sends invalid messages accumulates a negative score, and once it crosses a configurable threshold it is pruned and eventually disconnected. v1.1 also added flood publishing (where the original publisher sends to all connected peers, not just mesh peers), though Base disables this by default to conserve bandwidth. The gossipsub configuration in Base lives in [`gossip/src/config.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/config.rs): ```rust pub const DEFAULT_MESH_D: usize = 8; // target peers in mesh pub const DEFAULT_MESH_DLO: usize = 6; // minimum before mesh repair pub const DEFAULT_MESH_DHI: usize = 12; // maximum before pruning pub const DEFAULT_MESH_DLAZY: usize = 6; // peers for lazy gossip pub const GOSSIP_HEARTBEAT: Duration = Duration::from_millis(500); pub const MAX_GOSSIP_SIZE: usize = 10 * (1 << 20); // 10 MB ``` In practice, each node aims for 8 peers in its mesh per topic. If it falls below 6 it grafts new peers; above 12 it prunes some. Every 500ms the heartbeat fires and the protocol checks mesh health. The lazy gossip parameter means that for messages a node has seen but did not forward via the mesh, it still tells 6 additional peers via lightweight metadata so they can request them if needed. Messages are compressed with Snappy (a fast compression algorithm prioritizing speed over ratio) before being sent, and each message ID is computed by SHA-256 hashing (a cryptographic hash function that produces a unique fixed-size fingerprint of arbitrary data) the decompressed content with a domain prefix (a few extra bytes prepended before hashing to distinguish valid from invalid encodings). This is how the network deduplicates messages. The gossip topics are where Base's L2-specific design becomes visible. The [`BlockHandler`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/handler.rs) manages four versioned topics, one per protocol version: ```rust blocks_v1_topic: IdentTopic::new(format!("/optimism/{chain_id}/0/blocks")), blocks_v2_topic: IdentTopic::new(format!("/optimism/{chain_id}/1/blocks")), blocks_v3_topic: IdentTopic::new(format!("/optimism/{chain_id}/2/blocks")), blocks_v4_topic: IdentTopic::new(format!("/optimism/{chain_id}/3/blocks")), ``` For Base Mainnet (chain ID 8453), these resolve to `/optimism/8453/0/blocks` through `/optimism/8453/3/blocks`. The version is selected based on the active hardfork (a protocol upgrade that changes network rules, activated at a specific timestamp) at the block's timestamp. V1 covers pre-Canyon blocks, V2 Canyon/Delta, V3 Ecotone, and V4 Isthmus. Each version uses a slightly different encoding for the execution payload envelope. When a node subscribes to gossip, it subscribes to all four topics simultaneously so it can handle blocks from any active version. The `BlockHandler` implements the [`Handler`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/handler.rs) trait, with two methods: `handle()` for processing incoming messages and `topics()` for declaring which topics it cares about. When a gossip message arrives, the handler first checks the topic to choose the decoder, then decodes the payload, then validates it: ```rust fn handle(&mut self, msg: Message) -> (MessageAcceptance, Option) { let decoded = if msg.topic == self.blocks_v1_topic.hash() { NetworkPayloadEnvelope::decode_v1(&msg.data) } else if msg.topic == self.blocks_v2_topic.hash() { NetworkPayloadEnvelope::decode_v2(&msg.data) } else if msg.topic == self.blocks_v3_topic.hash() { NetworkPayloadEnvelope::decode_v3(&msg.data) } else if msg.topic == self.blocks_v4_topic.hash() { NetworkPayloadEnvelope::decode_v4(&msg.data) } else { return (MessageAcceptance::Reject, None); }; match decoded { Ok(envelope) => match self.block_valid(&envelope) { Ok(()) => (MessageAcceptance::Accept, Some(envelope)), Err(err) => (err.into(), None), }, Err(err) => (MessageAcceptance::Reject, None), } } ``` The `MessageAcceptance` result feeds back into gossipsub's peer scoring. `Accept` means the message was valid and the peer earns credit. `Reject` means the message was invalid and the peer's score takes a hit. `Ignore` is used for already-seen blocks and does not penalize the peer. ### Block validation — keeping gossip honest Block validation in [`block_validity.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/block_validity.rs) is one of the most important pieces of the P2P stack because it determines what the node accepts. The checks run in sequence and the order matters. First, the timestamp must fall within an acceptable window — no more than 5 seconds in the future or 60 seconds in the past. This rejects stale blocks and prevents replay attacks (where an attacker re-broadcasts old, legitimate messages to confuse the network). Second, the block hash is recomputed from the payload and compared against the hash in the envelope. A mismatch indicates tampering. Third, version-specific payload constraints are enforced. V3 (Ecotone) and later payloads must include a non-empty parent beacon block root and zero blob gas usage. V4 (Isthmus) payloads must include a withdrawals root. This step catches blocks that are structurally invalid for their version. Fourth, the handler consults its seen-hashes tracking. It maintains a `BTreeMap` keyed by block height with a 1,000-entry cache. If more than 5 different blocks already exist for a given height (a sixth unique block is accepted but a seventh is rejected), the new block is rejected. If this exact block hash has been seen before, it is ignored without penalty. Multiple valid blocks at the same height can occur with a single sequencer when it produces a replacement block — for example, after a reorg (chain reorganization) triggered from L1. Fifth, and most important for rollup security, the signature is verified. The sequencer signs each block with its private key, and every node knows the expected signer's address. The expected signer is read first, then the signature is recovered from the payload hash via ECDSA recovery (a property of elliptic curve signatures that lets you compute the signer's public key from just the signature and the signed message). If the recovered address does not match the expected signer, the block is rejected: ```rust let msg = envelope.payload_hash.signature_message(self.rollup_config.l2_chain_id.id()); let block_signer = *self.signer_recv.borrow(); let Ok(msg_signer) = envelope.signature.recover_address_from_prehash(&msg) else { return Err(BlockInvalidError::Signature); }; if msg_signer != block_signer { return Err(BlockInvalidError::Signer { expected: block_signer, received: msg_signer }); } ``` Only after the signature passes does the handler insert the block hash into the seen-hashes map, marking it as processed. This prevents spam without rejecting legitimate competing blocks. ### Connection gating — controlling who connects The [`ConnectionGater`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/gater.rs) is a rate-limiting layer that controls peer connections. It tracks dial attempts per peer address and enforces a configurable dial period (default: 1 hour). By default, redialing is disabled entirely — a peer can only be dialed once per period. The CLI overrides this to allow up to 500 redials per period via `--p2p.redial`. The gater also supports explicitly blocking peers by ID, IP address, or subnet, and protecting specific peers from disconnection regardless of score. Without connection gating, a misbehaving or misconfigured node could repeatedly attempt to connect, wasting resources. The gater bounds connection attempts and lets known-bad actors be blocked at the connection level rather than just at the gossip level. ### The libp2p Behaviour — combining protocols The [`Behaviour`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/behaviour.rs) struct is a libp2p `NetworkBehaviour` that combines several sub-protocols into a single swarm (libp2p's term for the combination of transport, protocol behaviors, and connection management — essentially the "networking engine"): ```rust #[derive(NetworkBehaviour)] pub struct Behaviour { pub ping: libp2p::ping::Behaviour, pub gossipsub: libp2p::gossipsub::Behaviour, pub identify: libp2p::identify::Behaviour, pub sync_req_resp: libp2p_stream::Behaviour, } ``` `ping` sends periodic keepalive pings and measures round-trip times. `gossipsub` handles block gossip. `identify` exchanges capability information when peers first connect (Base advertises its agent version as `"base"`). `sync_req_resp` supports a legacy request-response protocol called `payload_by_number` that is part of the OP Stack spec. It is being deprecated and the Base implementation responds "not found" to all requests, but it is still present so op-nodes do not penalize Base nodes for missing it. The `GossipDriver` ([`gossip/src/driver.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/driver.rs)) wraps the swarm and provides higher-level operations. Its `start()` method binds the swarm to a TCP address (default `0.0.0.0:9222`), waits for the `NewListenAddr` event confirming the listener is up, and returns. Its `publish()` method takes an execution payload envelope (the signed wrapper around a block's contents — transactions, state root, gas used, and so on), selects the appropriate topic based on the block's timestamp and active hardfork, encodes it with version-appropriate serialization, and publishes it to gossipsub. Its `dial()` method takes an ENR from discovery, validates the chain ID, extracts the TCP multiaddr (a self-describing network address format used by libp2p, e.g. `/ip4/192.168.1.1/tcp/9222`), checks the connection gate, and initiates the connection. ### Putting it together — the network actor The [`NetworkActor`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/actor.rs) in the service crate ties everything together. It follows the actor pattern, a concurrency design where each component runs as an independent task that communicates with others exclusively through message channels, avoiding shared mutable state. The actor is the top-level component the consensus node's main loop interacts with. It is generic over a [`GossipTransport`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/transport.rs) trait, which lets the real networking stack be swapped out for an in-process test transport: ```rust #[async_trait] pub trait GossipTransport: Send + 'static { type Error: std::fmt::Debug + Send + 'static; async fn publish(&mut self, payload: BaseExecutionPayloadEnvelope) -> Result<(), Self::Error>; async fn next_unsafe_block(&mut self) -> Option; fn set_block_signer(&mut self, address: Address); fn handle_p2p_rpc(&mut self, request: P2pRpcRequest); } ``` The production implementation, [`NetworkHandler`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/handler.rs), composes the `GossipDriver` and `Discv5Handler`. It runs a `tokio::select!` loop that simultaneously handles several things: receiving ENRs from discovery and dialing them as new gossip peers, receiving blocks from gossip and forwarding them to the consensus engine, publishing blocks produced locally if the node is the sequencer, inspecting peer scores every 15 seconds and banning low-scoring peers (disconnecting them from gossip and banning their addresses in discovery), and handling administrative RPC requests. The [`NetworkDriver`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/driver.rs) handles the startup sequence. It starts the gossip swarm first, gets back the actual listen address, optionally updates the local ENR with that address (so other nodes discover the correct port), and then starts discovery. Ordering matters because the ENR must contain the real TCP port that gossip is listening on. The `NetworkActor` communicates with the rest of the consensus node through `mpsc` channels bundled in a [`NetworkInboundData`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/actor.rs) struct: ```rust pub struct NetworkInboundData { pub signer: mpsc::Sender
, pub p2p_rpc: mpsc::Sender, pub admin_rpc: mpsc::Sender, pub gossip_payload_tx: mpsc::Sender, } ``` Other actors in the node (such as the sequencer or the admin RPC server) push data to the network actor through these senders. The `signer` channel updates the expected unsafe block signer address. The `gossip_payload_tx` channel lets the sequencer publish newly produced blocks. This message-passing architecture isolates all networking concerns in one actor without shared mutable state. ### CL startup flow from the command line When you launch the Base consensus binary, P2P configuration comes from CLI flags defined in [`base-client-cli`](https://github.com/base/base/tree/main/crates/client/cli). Key flags include `--p2p.listen.tcp` (default 9222) and `--p2p.listen.udp` (default 9223) for local bind addresses, `--p2p.advertise.ip` for NAT (Network Address Translation) scenarios where the node sits behind a router and its public IP differs from its local IP, `--p2p.priv.path` for the node's secp256k1 private key, and the mesh parameters such as `--p2p.gossip.mesh.d` for the target mesh size. The startup flow in the CLI's `exec()` function loads the rollup configuration, parses the P2P arguments into a `NetworkConfig`, constructs a `NetworkBuilder` with both the gossip and discovery builders, and passes it to the `RollupNodeBuilder` which starts the `NetworkActor`. From that point on, the node is live on the consensus P2P network. ## The execution layer P2P stack The execution layer P2P stack is built on Reth, a high-performance Ethereum execution client written in Rust. The Base-specific customizations live under [`crates/execution/`](https://github.com/base/base/tree/main/crates/execution), and the node definition is in [`crates/execution/node/`](https://github.com/base/base/tree/main/crates/execution/node). For an architectural overview of how this fits the rest of the system, see the [architecture overview](/architecture/overview/). ### How Reth handles networking Reth implements the standard Ethereum execution layer networking stack. At the transport level it uses DevP2P with RLPx, a cryptographic transport where peers handshake to establish an encrypted, authenticated session. The mechanics resemble HTTPS: both nodes exchange temporary keys and derive a shared secret, after which all communication is encrypted. (For the curious, the handshake uses ECIES — Elliptic Curve Integrated Encryption Scheme — with ephemeral key shares and Diffie-Hellman key agreement. The session is encrypted with AES-256 and authenticated with keccak256-based MACs. Understanding these details is not necessary to work with the codebase.) Once the encrypted channel is up, the two nodes exchange "Hello" messages negotiating which sub-protocols they both support. On top of this transport, Reth speaks the `eth/68` wire protocol (version 68 of the Ethereum sub-protocol for exchanging chain data between execution clients). It handles block headers, block bodies, receipts, and transaction announcements. For transaction gossip specifically, eth/68 uses a two-phase announcement system: when a node receives a new transaction, it sends the full transaction to a small random fraction of its peers and sends lightweight hash announcements (with type and size metadata) to all other peers, who can then request the full transaction if they do not already have it. Reth also supports the `snap/1` protocol for snapshot-based state synchronization, letting new nodes download state much faster than replaying chain history. For peer discovery, Reth supports both discv4 (the older UDP-based Kademlia protocol) and discv5 (the newer protocol also used by the consensus layer). Nodes can additionally be configured with static boot nodes and DNS-based discovery. ### The BaseNetworkBuilder The [`BaseNetworkBuilder`](https://github.com/base/base/blob/main/crates/execution/node/src/node.rs) configures Reth's network for Base. It exposes two flags: ```rust pub struct BaseNetworkBuilder { pub disable_txpool_gossip: bool, pub disable_discovery_v4: bool, } ``` The `disable_txpool_gossip` flag is particularly important for rollup nodes. When a node is configured with a sequencer endpoint (so it should forward transactions to the sequencer rather than including them itself), transaction pool gossip is disabled. This stops the node from broadcasting pending transactions to the rest of the network, because in a rollup the sequencer is the only entity that orders transactions. The `network_config` method assembles Reth's `NetworkConfig` by applying the discovery settings. The code below builds the configuration step by step: it sets the RLPx socket address, conditionally disables discv4, enables discv5 with boot nodes, and finally sets the transaction gossip flag: ```rust let network_builder = ctx .network_config_builder()? .apply(|mut builder| { let rlpx_socket = (args.addr, args.port).into(); if disable_discovery_v4 || args.discovery.disable_discovery { builder = builder.disable_discv4_discovery(); } if !args.discovery.disable_discovery { builder = builder.discovery_v5( args.discovery.discovery_v5_builder( rlpx_socket, ctx.config() .network .resolved_bootnodes() .or_else(|| ctx.chain_spec().bootnodes()) .unwrap_or_default(), ), ); } builder }); let mut network_config = ctx.build_network_config(network_builder); network_config.tx_gossip_disabled = disable_txpool_gossip; ``` Discv4 is disabled by default for Base (`--rollup.discovery.v4` defaults to false) while discv5 is enabled. Boot nodes resolve from CLI arguments first and fall back to the chain specification. Once the config is built, `build_network` creates a `NetworkManager`, starts it, and logs the local enode record (the DevP2P equivalent of an ENR — a URL-formatted node identifier such as `enode://@:`). ### Transaction pool and gossip The Base transaction pool lives in [`crates/execution/txpool/`](https://github.com/base/base/tree/main/crates/execution/txpool). It extends Reth's standard transaction pool with rollup-specific validation and ordering. The [`OpTransactionValidator`](https://github.com/base/base/blob/main/crates/execution/txpool/src/validator.rs) wraps Reth's `EthTransactionValidator` and adds L1 data gas fee checks. Every transaction on Base pays both an L2 execution gas cost and an L1 data fee (the cost of posting transaction data to Ethereum L1). The validator confirms the sender's balance covers both. It also rejects EIP-4844 blob transactions (a special transaction type used on L1 to carry large data blobs for rollups, which are not meaningful on the L2 itself). The ordering strategy is configurable via `--rollup.txpool-ordering` and defined in [`ordering.rs`](https://github.com/base/base/blob/main/crates/execution/txpool/src/ordering.rs): ```rust pub enum BaseOrdering { CoinbaseTip(CoinbaseTipOrdering), Timestamp(TimestampOrdering), } ``` `CoinbaseTip` is the standard Ethereum priority-fee ordering — higher fees first. `Timestamp` is a rollup-specific FIFO ordering that prioritizes by arrival time regardless of fee, which can produce fairer sequencing. ### Transaction forwarding For non-sequencer nodes, transactions accepted into the mempool need to be forwarded to the sequencer for inclusion. This is handled by the consumer/forwarder pipeline in the txpool crate. The [`SpawnedConsumer`](https://github.com/base/base/blob/main/crates/execution/txpool/src/consumer/mod.rs) polls the transaction pool for new pending transactions and broadcasts them through a `tokio::broadcast` channel. The [`SpawnedForwarder`](https://github.com/base/base/blob/main/crates/execution/txpool/src/forwarder/mod.rs) subscribes to that channel and forwards each transaction via a custom JSON-RPC method (`base_insertValidatedTransactions`) to configured builder endpoints. One forwarder task is spawned per builder URL, so multiple downstream builders can receive transactions simultaneously. The pipeline runs as background tasks on the node's task executor. ### EL P2P configuration flags The execution layer P2P is configured through Reth's standard network flags plus Base-specific rollup flags defined in [`args.rs`](https://github.com/base/base/blob/main/crates/execution/node/src/args.rs). Key flags: `--rollup.sequencer` sets the sequencer endpoint for transaction forwarding. `--rollup.disable-tx-pool-gossip` disables transaction gossip on the DevP2P network (this is a separate flag — setting the sequencer endpoint does not automatically disable gossip, so operators typically set both). `--rollup.discovery.v4` enables the legacy discv4 discovery protocol (disabled by default since Base uses discv5). `--rollup.txpool-ordering` selects between `coinbase-tip` and `timestamp` ordering strategies. Standard Reth network flags still apply: `--network.addr` and `--network.port` control the RLPx bind address (default port 30303), `--network.discovery.disable-discovery` turns off all peer discovery, and `--network.discovery.bootnodes` provides custom boot node addresses. ## How the two stacks interact at runtime When a Base node is running, the consensus and execution processes work in tandem but network independently. Block reception flows like this: The sequencer produces a new L2 block and signs it. The signed block is published as a `NetworkPayloadEnvelope` to the CL gossip network on the appropriate versioned topic (for example, `/optimism/8453/3/blocks` for Isthmus). Every consensus node's `BlockHandler` receives the message, validates it (timestamp, hash, signature, deduplication), and if valid marks it `Accept` and passes it to the consensus engine. The engine sends the execution payload to the local execution client via `engine_newPayloadV*`. The execution client validates the block against the EVM, computes the new state root, and reports the result back. Transaction submission flows in the opposite direction. A user submits a transaction to an EL node's RPC endpoint. If transaction pool gossip is enabled, the transaction is broadcast to other EL peers via the DevP2P `eth/68` protocol. If a sequencer endpoint is configured, the transaction forwarder sends it directly to the sequencer via JSON-RPC. The sequencer includes it in the next block, which then propagates through the CL gossip network as described above. Discovery on each layer is independent. The CL uses discv5 on a UDP port (default 9223) to find other CL peers, validating ENRs by chain ID so it only connects to Base nodes. The EL uses discv5 (and optionally discv4) on its own UDP port to find other EL peers. The two discovery networks are entirely separate and serve different purposes. ## Key files **Consensus layer peers and ENR management:** - [`crates/consensus/peers/src/enr.rs`](https://github.com/base/base/blob/main/crates/consensus/peers/src/enr.rs) — BaseEnr encoding and validation - [`crates/consensus/peers/src/store.rs`](https://github.com/base/base/blob/main/crates/consensus/peers/src/store.rs) — BootStore persistence **Consensus layer discovery:** - [`crates/consensus/disc/src/driver.rs`](https://github.com/base/base/blob/main/crates/consensus/disc/src/driver.rs) — Discv5Driver event loop and bootstrap **Consensus layer gossip:** - [`crates/consensus/gossip/src/config.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/config.rs) — Gossipsub constants and configuration - [`crates/consensus/gossip/src/handler.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/handler.rs) — BlockHandler and topic management - [`crates/consensus/gossip/src/block_validity.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/block_validity.rs) — Block validation rules - [`crates/consensus/gossip/src/behaviour.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/behaviour.rs) — libp2p Behaviour composition - [`crates/consensus/gossip/src/gater.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/gater.rs) — Connection rate limiting - [`crates/consensus/gossip/src/driver.rs`](https://github.com/base/base/blob/main/crates/consensus/gossip/src/driver.rs) — GossipDriver swarm management **Consensus layer orchestration:** - [`crates/consensus/service/src/actors/network/actor.rs`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/actor.rs) — NetworkActor definition - [`crates/consensus/service/src/actors/network/handler.rs`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/handler.rs) — Production NetworkHandler transport - [`crates/consensus/service/src/actors/network/driver.rs`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/driver.rs) — Network startup sequence - [`crates/consensus/service/src/actors/network/transport.rs`](https://github.com/base/base/blob/main/crates/consensus/service/src/actors/network/transport.rs) — GossipTransport trait **Execution layer node and networking:** - [`crates/execution/node/src/node.rs`](https://github.com/base/base/blob/main/crates/execution/node/src/node.rs) — BaseNetworkBuilder and network configuration - [`crates/execution/node/src/args.rs`](https://github.com/base/base/blob/main/crates/execution/node/src/args.rs) — Rollup-specific CLI arguments **Execution layer transaction pool:** - [`crates/execution/txpool/src/validator.rs`](https://github.com/base/base/blob/main/crates/execution/txpool/src/validator.rs) — OpTransactionValidator with L1 data gas checks - [`crates/execution/txpool/src/ordering.rs`](https://github.com/base/base/blob/main/crates/execution/txpool/src/ordering.rs) — BaseOrdering (fee-based vs FIFO) - [`crates/execution/txpool/src/consumer/`](https://github.com/base/base/tree/main/crates/execution/txpool/src/consumer) — Transaction pool consumer - [`crates/execution/txpool/src/forwarder/`](https://github.com/base/base/tree/main/crates/execution/txpool/src/forwarder) — Transaction forwarder to sequencer ## Glossary **Attestation** — A validator's vote that a particular block is valid. **Beacon chain** — The chain introduced with Ethereum's proof-of-stake upgrade that coordinates consensus. **Bootnode** — A well-known node whose address is hardcoded into client software, used to bootstrap new nodes into the network. **CL (Consensus Layer)** — The part of an Ethereum node responsible for consensus (deciding which blocks are canonical). **DevP2P** — The execution layer's P2P protocol suite, including RLPx transport and the eth wire protocol. **DHT (Distributed Hash Table)** — A system where many computers collectively maintain a lookup directory without any central coordinator. **Discv4 / Discv5** — Node Discovery Protocol versions 4 and 5. UDP-based protocols for finding peers. **EL (Execution Layer)** — The part of an Ethereum node responsible for executing transactions and maintaining state. **Engine API** — The JSON-RPC interface that the consensus and execution layers use to communicate locally. **ENR (Ethereum Node Record)** — A signed, self-describing identity document that a node uses to advertise itself (IP, ports, public key, chain metadata). **EVM (Ethereum Virtual Machine)** — The runtime environment that executes smart contract bytecode. **Gossipsub** — A publish/subscribe protocol built on libp2p that uses a mesh overlay for efficient message distribution. **GRAFT / PRUNE** — Gossipsub control messages for adding or removing a peer from the mesh. **Hardfork** — A protocol upgrade that changes the rules of the network, activated at a specific timestamp. **IHAVE / IWANT** — Gossipsub control messages for the lazy repair mechanism (advertising and requesting missed messages). **k-bucket** — A fixed-size list of peers at a particular XOR distance in a Kademlia routing table. **L1 (Layer 1)** — The base Ethereum chain. **L2 (Layer 2)** — A chain that runs on top of L1 for scalability (e.g. Base). **libp2p** — A modular networking framework used by the consensus layer, originally developed for IPFS. **Mempool** — The pool of pending transactions waiting to be included in a block. **mpsc** — Multi-producer, single-consumer channel. A thread-safe queue used for async communication in Rust. **Multiaddr** — A self-describing network address format used by libp2p (e.g. `/ip4/192.168.1.1/tcp/9222`). **NAT (Network Address Translation)** — When a node is behind a router and its public IP differs from its local IP. **Reorg** — A chain reorganization where the network switches to a different sequence of blocks. **RLP (Recursive Length Prefix)** — Ethereum's standard binary serialization format. **RLPx** — The execution layer's encrypted TCP transport protocol. **Rollup** — A type of blockchain that executes transactions on its own chain but posts data back to Ethereum for security. **Sequencer** — The single designated node that orders and produces L2 blocks. **Snappy** — A fast compression algorithm used for gossip message compression. **State root** — A cryptographic fingerprint of the entire blockchain state after executing a block's transactions. **Swarm** — libp2p's term for the combination of transport, protocol behaviors, and connection management. **XOR distance** — The distance metric used in Kademlia, computed by XOR-ing two node IDs. Has nothing to do with geographic distance. ---