Skip to content

Commit a901300

Browse files
authored
Merge pull request #149 from OffchainLabs/add-force-inclusion
Add force inclusion example
2 parents bb88573 + b34def1 commit a901300

6 files changed

Lines changed: 832 additions & 5 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Using public testnet RPCs can be slow because many tutorials wait for transactio
7070
- 🌉 [Bridging a custom token through the generic-custom gateway](./packages/custom-token-bridging/)
7171
- 🌉 [Bridging a custom token through a custom gateway](./packages/custom-gateway-bridging/)
7272
- ✈️ [Send a signed transaction from the parent chain](./packages/delayedInbox-l2msg/)
73+
- 🛡️ [Force inclusion end-to-end test](./packages/force-inclusion/)
7374
- 🎁 [Redeem pending retryable ticket](./packages/redeem-pending-retryable/)
7475
- 🧮 [Gas estimation](./packages/gas-estimation/)
7576
- 🌀 [Deposit Ether or Tokens from L1 to L3](./packages/l1-l3-teleport/)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# This is a sample .env file for use in local development.
2+
# Duplicate this file as .env here
3+
4+
# Private key of the deployer (must have ETH on the parent chain)
5+
DEPLOYER_PRIVATE_KEY="0x your key here"
6+
7+
# The parent chain's RPC
8+
# (default: Arbitrum Sepolia)
9+
PARENT_CHAIN_RPC="https://sepolia-rollup.arbitrum.io/rpc"
10+
11+
# (Optional) Parent chain ID
12+
# Defaults to Arbitrum Sepolia (421614) if not set
13+
# PARENT_CHAIN_ID=421614
14+
15+
# (Optional) Batch poster and validator keys
16+
# Auto-generated if not set (only needed for --with-node)
17+
# BATCH_POSTER_PRIVATE_KEY="0x..."
18+
# VALIDATOR_PRIVATE_KEY="0x..."

packages/force-inclusion/README.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Tutorial: Force Inclusion End-to-End Test
2+
3+
`force-inclusion` demonstrates Arbitrum's **censorship resistance** mechanism end-to-end. It deploys a fresh Orbit rollup with a short force inclusion delay (90 seconds), deposits ETH via the delayed inbox, waits for the delay window to pass, and then force includes the deposit — all without a running sequencer.
4+
5+
## What is force inclusion?
6+
7+
Arbitrum's [Sequencer](https://docs.arbitrum.io/how-arbitrum-works/sequencer) normally orders transactions. But what if the sequencer goes offline or starts censoring? Arbitrum guarantees that any message sent to the **delayed inbox** on the parent chain can be **force included** into the chain's inbox after a time delay, bypassing the sequencer entirely.
8+
9+
This tutorial runs the full cycle in a single command:
10+
11+
1. **Deploy** a new Orbit rollup with `maxTimeVariation.delaySeconds = 90` (instead of the default 24 hours)
12+
2. **Deposit** ETH via `Inbox.depositEth()` on the parent chain (goes into the delayed inbox)
13+
3. **Force include** the deposit by calling `SequencerInbox.forceInclusion()` after the delay window passes
14+
4. _(Optional)_ **Start a fullnode** (no sequencer) to verify the deposit appears on the child chain
15+
16+
## Prerequisites
17+
18+
- Node.js 18+
19+
- A deployer account with ETH on the parent chain (Arbitrum Sepolia or a custom parent chain)
20+
- Docker (only needed for the `--with-node` option)
21+
22+
## Set environment variables
23+
24+
Copy the sample env file and fill in your values:
25+
26+
```bash
27+
cp .env-sample .env
28+
```
29+
30+
Required variables:
31+
32+
| Variable | Description |
33+
| ---------------------- | --------------------------------------------------------------- |
34+
| `DEPLOYER_PRIVATE_KEY` | Private key of the deployer (must have ETH on the parent chain) |
35+
| `PARENT_CHAIN_RPC` | RPC URL of the parent chain |
36+
37+
Optional variables:
38+
39+
| Variable | Description |
40+
| -------------------------- | ----------------------------------------------------- |
41+
| `PARENT_CHAIN_ID` | Parent chain ID (defaults to Arbitrum Sepolia 421614) |
42+
| `BATCH_POSTER_PRIVATE_KEY` | Batch poster key (auto-generated if not set) |
43+
| `VALIDATOR_PRIVATE_KEY` | Validator key (auto-generated if not set) |
44+
45+
## Run
46+
47+
Run steps 1–3 (deploy, deposit, force include):
48+
49+
```bash
50+
yarn test
51+
```
52+
53+
Run all 4 steps including fullnode verification (requires Docker):
54+
55+
```bash
56+
yarn test:withNode
57+
```
58+
59+
## How it works
60+
61+
### Rollup deployment
62+
63+
The script uses `@arbitrum/chain-sdk` (Orbit SDK) to deploy a new rollup. The key configuration is `sequencerInboxMaxTimeVariation`, which controls how long a delayed message must wait before it can be force included:
64+
65+
```js
66+
sequencerInboxMaxTimeVariation: {
67+
delayBlocks: 6n,
68+
futureBlocks: 12n,
69+
delaySeconds: 90n,
70+
futureSeconds: 3600n,
71+
}
72+
```
73+
74+
### Delayed inbox deposit
75+
76+
ETH is deposited using `@arbitrum/sdk`'s `EthBridger.deposit()`. Under the hood, this calls `Inbox.depositEth()` on the parent chain, which routes through `bridge.enqueueDelayedMessage()`. Without a running sequencer, this message stays in the delayed inbox.
77+
78+
### Force inclusion
79+
80+
After the delay window passes (90 seconds + 6 blocks), `InboxTools.forceInclude()` calls `SequencerInbox.forceInclusion()` on the parent chain. This emits the same `SequencerBatchDelivered` event as a normal sequencer batch, making the deposit part of the canonical chain.
81+
82+
### Fullnode verification (--with-node)
83+
84+
When `--with-node` is passed, the script starts a Nitro fullnode via Docker with the sequencer disabled (`node.sequencer = false`, `execution.forwarding-target = "null"`). The fullnode reads from the parent chain and processes the force-included batch, allowing you to verify that the deposited ETH appears on the child chain.
85+
86+
## Related tutorials
87+
88+
- [Send a signed transaction from the parent chain](../delayedInbox-l2msg/) — demonstrates sending transactions via the delayed inbox with a running sequencer
89+
90+
<p align="left">
91+
<img width="350" height="150" src= "../../assets/logo.svg" />
92+
</p>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "force-inclusion",
3+
"version": "1.0.0",
4+
"description": "End-to-end force inclusion test: deploy a rollup with a short delay, deposit ETH via delayed inbox, and force include — all without a sequencer.",
5+
"scripts": {
6+
"test": "node scripts/force-inclusion-test.js",
7+
"test:withNode": "node scripts/force-inclusion-test.js --with-node"
8+
},
9+
"author": "Offchain Labs, Inc.",
10+
"license": "Apache-2.0",
11+
"dependencies": {
12+
"@arbitrum/sdk": "^4.0.5",
13+
"@arbitrum/chain-sdk": "^0.25.0",
14+
"viem": "^1.20.0"
15+
}
16+
}

0 commit comments

Comments
 (0)