Skip to content

Commit 6897cc5

Browse files
jonastheisomerfirmaknoel2004colinlyguoroynalnaruto
authored
feat(permissionless batches): batch production toolkit and operator recovery (#1555)
Signed-off-by: noelwei <[email protected]> Co-authored-by: Ömer Faruk Irmak <[email protected]> Co-authored-by: noelwei <[email protected]> Co-authored-by: colin <[email protected]> Co-authored-by: Rohit Narurkar <[email protected]> Co-authored-by: colinlyguo <[email protected]> Co-authored-by: Péter Garamvölgyi <[email protected]> Co-authored-by: Morty <[email protected]> Co-authored-by: omerfirmak <[email protected]> Co-authored-by: jonastheis <[email protected]> Co-authored-by: georgehao <[email protected]> Co-authored-by: kunxian xia <[email protected]> Co-authored-by: Velaciela <[email protected]> Co-authored-by: colinlyguo <[email protected]> Co-authored-by: Morty <[email protected]>
1 parent d21fa36 commit 6897cc5

34 files changed

+2115
-47
lines changed

build/dockerfiles/coordinator-api.Dockerfile.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ docs/
44
l2geth/
55
rpc-gateway/
66
*target/*
7+
8+
permissionless-batches/conf/

build/dockerfiles/coordinator-cron.Dockerfile.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ docs/
44
l2geth/
55
rpc-gateway/
66
*target/*
7+
8+
permissionless-batches/conf/

build/dockerfiles/db_cli.Dockerfile.dockerignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ docs/
44
l2geth/
55
rpc-gateway/
66
*target/*
7+
8+
permissionless-batches/conf/
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
assets/
2+
contracts/
23
docs/
34
l2geth/
45
rpc-gateway/
5-
*target/*
6+
*target/*
7+
8+
permissionless-batches/conf/
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Download Go dependencies
2+
FROM scrolltech/go-rust-builder:go-1.21-rust-nightly-2023-12-03 as base
3+
4+
WORKDIR /src
5+
COPY go.work* ./
6+
COPY ./rollup/go.* ./rollup/
7+
COPY ./common/go.* ./common/
8+
COPY ./coordinator/go.* ./coordinator/
9+
COPY ./database/go.* ./database/
10+
COPY ./tests/integration-test/go.* ./tests/integration-test/
11+
COPY ./bridge-history-api/go.* ./bridge-history-api/
12+
RUN go mod download -x
13+
14+
# Build rollup_relayer
15+
FROM base as builder
16+
17+
RUN --mount=target=. \
18+
--mount=type=cache,target=/root/.cache/go-build \
19+
cd /src/rollup/cmd/permissionless_batches/ && CGO_LDFLAGS="-ldl" go build -v -p 4 -o /bin/rollup_relayer
20+
21+
# Pull rollup_relayer into a second stage deploy ubuntu container
22+
FROM ubuntu:20.04
23+
24+
RUN apt update && apt install vim netcat-openbsd net-tools curl ca-certificates -y
25+
26+
ENV CGO_LDFLAGS="-ldl"
27+
28+
COPY --from=builder /bin/rollup_relayer /bin/
29+
WORKDIR /app
30+
ENTRYPOINT ["rollup_relayer"]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
assets/
2+
contracts/
3+
docs/
4+
l2geth/
5+
rpc-gateway/
6+
*target/*
7+
8+
permissionless-batches/conf/
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
assets/
2+
contracts/
23
docs/
34
l2geth/
45
rpc-gateway/
5-
*target/*
6+
*target/*
7+
8+
permissionless-batches/conf/

common/version/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"runtime/debug"
66
)
77

8-
var tag = "v4.5.37"
8+
var tag = "v4.5.38"
99

1010
var commit = func() string {
1111
if info, ok := debug.ReadBuildInfo(); ok {

permissionless-batches/Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.PHONY: batch_production_submission launch_prover psql check_proving_status
2+
3+
export SCROLL_ZKVM_VERSION=0.4.2
4+
PG_URL=postgres://postgres@localhost:5432/scroll
5+
6+
batch_production_submission:
7+
docker compose --profile batch-production-submission up
8+
9+
launch_prover:
10+
docker compose up -d
11+
12+
psql:
13+
psql 'postgres://postgres@localhost:5432/scroll'
14+
15+
check_proving_status:
16+
@echo "Checking proving status..."
17+
@result=$$(psql "${PG_URL}" -t -c "SELECT proving_status = 4 AS is_status_success FROM batch ORDER BY index LIMIT 1;" | tr -d '[:space:]'); \
18+
if [ "$$result" = "t" ]; then \
19+
echo "✅ Prove succeeded! You're ready to submit permissionless batch and proof!"; \
20+
else \
21+
echo "Proof is not ready..."; \
22+
fi

permissionless-batches/README.md

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Permissionless Batches
2+
Permissionless batches aka enforced batches is a feature that provides guarantee to users that they can exit Scroll even if the operator is down or censoring.
3+
It allows anyone to take over and submit a batch (permissionless batch submission) together with a proof after a certain time period has passed without a batch being finalized on L1.
4+
5+
Once permissionless batch mode is activated, the operator can no longer submit batches in a permissioned way. Only the security council can deactivate permissionless batch mode and reinstate the operator as the only batch submitter.
6+
There are two types of situations to consider:
7+
- `Permissionless batch mode is activated:` This means that finalization halted for some time. Now anyone can submit batches utilizing the [batch production toolkit](#batch-production-toolkit).
8+
- `Permissionless batch mode is deactivated:` This means that the security council has decided to reinstate the operator as the only batch submitter. The operator needs to [recover](#operator-recovery) the sequencer and relayer to resume batch submission and the valid L2 chain.
9+
10+
11+
## Batch production toolkit
12+
The batch production toolkit is a set of tools that allow anyone to submit a batch in permissionless mode. It consists of three main components:
13+
1. l2geth state recovery from L1
14+
2. l2geth block production
15+
3. production, proving and submission of batch with `docker-compose.yml`
16+
17+
### Prerequisites
18+
- Unix-like OS, 32GB RAM
19+
- Docker
20+
- [l2geth](https://github.com/scroll-tech/go-ethereum/) or [Docker image](https://hub.docker.com/r/scrolltech/l2geth) of corresponding [version](https://docs.scroll.io/en/technology/overview/scroll-upgrades/).
21+
- access to an Ethereum L1 RPC node (beacon node and execution client)
22+
- ability to run a prover
23+
- L1 account with funds to pay for the batch submission
24+
25+
### 1. l2geth state recovery from L1
26+
Once permissionless mode is activated there's no blocks being produced and propagated on L2. The first step is to recover the latest state of the L2 chain from L1. This is done by running l2geth in recovery mode.
27+
28+
Running l2geth in recovery mode requires following configuration:
29+
- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode
30+
- `--da.blob.beaconnode` - L1 RPC beacon node
31+
- `--l1.endpoint` - L1 RPC execution client
32+
- `--da.sync=true` - enables syncing with L1
33+
- `--da.recovery` - enables recovery mode
34+
- `--da.recovery.initiall1block` - initial L1 block (commit tx of initial batch)
35+
- `--da.recovery.initialbatch` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https://scrollscan.com/batches).
36+
- `--da.recovery.l2endblock` - until which L2 block recovery should run (optional)
37+
38+
```bash
39+
./build/bin/geth --scroll<-sepolia> \
40+
--datadir "tmp/datadir" \
41+
--gcmode archive \
42+
--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \
43+
--da.blob.beaconnode "<L1 RPC beacon node>" \
44+
--l1.endpoint "<L1 RPC execution client>" \
45+
--da.sync=true --da.recovery --da.recovery.initiall1block "<initial L1 block (commit tx of initial batch)>" --da.recovery.initialbatch "<batch where to start recovery from>" --da.recovery.l2endblock "<until which L2 block recovery should run (optional)>" \
46+
--verbosity 3
47+
```
48+
49+
### 2. l2geth block production
50+
After the state is recovered, the next step is to produce blocks on L2. This is done by running l2geth in block production mode.
51+
As a prerequisite, the state recovery must be completed and the latest state of the L2 chain must be available.
52+
53+
You also need to generate a keystore e.g. with [Clef](https://geth.ethereum.org/docs/fundamentals/account-management) to be able to sign blocks.
54+
This key is not used for any funds, but required for block production to work. Once you generated blocks you can safely discard it.
55+
56+
Running l2geth in block production mode requires following configuration:
57+
- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode
58+
- `--da.blob.beaconnode` - L1 RPC beacon node
59+
- `--l1.endpoint` - L1 RPC execution client
60+
- `--da.sync=true` - enables syncing with L1
61+
- `--da.recovery` - enables recovery mode
62+
- `--da.recovery.produceblocks` - enables block production
63+
- `--miner.etherbase '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' --mine` - enables mining. the address is not used, but required for mining to work
64+
- `---miner.gaslimit 1 --miner.gasprice 1 --miner.maxaccountsnum 100 --rpc.gascap 0 --gpo.ignoreprice 1` - gas limits for block production
65+
66+
```bash
67+
./build/bin/geth --scroll<-sepolia> \
68+
--datadir "tmp/datadir" \
69+
--gcmode archive \
70+
--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \
71+
--da.blob.beaconnode "<L1 RPC beacon node>" \
72+
--l1.endpoint "<L1 RPC execution client>" \
73+
--da.sync=true --da.recovery --da.recovery.produceblocks \
74+
--miner.gaslimit 1 --miner.gasprice 1 --miner.maxaccountsnum 100 --rpc.gascap 0 --gpo.ignoreprice 1 \
75+
--miner.etherbase '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' --mine \
76+
--verbosity 3
77+
```
78+
79+
### 3. production, proving and submission of batch with `docker-compose.yml`
80+
After the blocks are produced, the next step is to produce a batch, prove it and submit it to L1. This is done by running the `docker-compose.yml` in the `permissionless-batches` folder.
81+
82+
83+
#### Producing a batch
84+
To produce a batch you need to run the `batch-production-submission` profile in `docker-compose.yml`.
85+
86+
1. Fill `conf/genesis.json` with the latest genesis state from the L2 chain. The genesis for the current fork can be found [here](https://docs.scroll.io/en/technology/overview/scroll-upgrades/).
87+
2. Make sure that `l2geth` with your locally produced blocks is running and reachable from the Docker network (e.g. `http://host.docker.internal:8545`)
88+
3. Fill in required fields in `conf/relayer/config.json`
89+
90+
91+
Run with `make batch_production_submission`.
92+
This will produce chunks, a batch and bundle which will be proven in the next step.
93+
`Success! You're ready to generate proofs!` indicates that everything is working correctly and the batch is ready to be proven.
94+
95+
#### Proving a batch
96+
To prove the chunk, batch and bundle you just generated you need to run the `prover` profile in `docker-compose.yml`.
97+
98+
Local Proving:
99+
100+
1. Hardware spec for local prover: CPU: 36+ core, 128G memory GPU: 24G memory (e.g. Rtx 3090/3090Ti/4090/A10/L4)
101+
2. Make sure `verifier` and `high_version_circuit` in `conf/coordinator/config.json` are correct for the [latest fork](https://docs.scroll.io/en/technology/overview/scroll-upgrades/)
102+
3. Set the `SCROLL_ZKVM_VERSION` environment variable on `Makefile` to the correct [version](https://docs.scroll.io/en/technology/overview/scroll-upgrades/).
103+
4. Fill in the required fields in `conf/proving-service/config.json`
104+
105+
Run with `make launch_prover`.
106+
107+
108+
#### Batch submission
109+
To submit the batch you need to run the `batch-production-submission` profile in `docker-compose.yml`.
110+
111+
1. Fill in required fields in `conf/relayer/config.json` for the sender config.
112+
113+
Run with `make batch_production_submission`.
114+
This will submit the batch to L1 and finalize it. The transaction will be retried in case of failure.
115+
116+
**Troubleshooting**
117+
- in case the submission fails it will print the calldata for the transaction in an error message. You can use this with `cast call --trace --rpc-url "$SCROLL_L1_DEPLOYMENT_RPC" "$L1_SCROLL_CHAIN_PROXY_ADDR" <calldata>` to see what went wrong.
118+
- `0x4df567b9: ErrorNotInEnforcedBatchMode`: permissionless batch mode is not activated, you can't submit a batch
119+
- `0xa5d305cc: ErrorBatchIsEmpty`: no blob was provided. This is usually returned if you do the `cast call`, permissionless mode is activated but you didn't provide a blob in the transaction.
120+
121+
## Operator recovery
122+
Operator recovery needs to be run by the rollup operator to resume normal rollup operation after permissionless batch mode is deactivated. It consists of two main components:
123+
1. l2geth recovery
124+
2. Relayer recovery
125+
126+
These steps are required to resume permissioned batch submission and the valid L2 chain. They will restore the entire history of the batches submitted during permissionless mode.
127+
128+
### Prerequisites
129+
- l2geth with the latest state of the L2 chain (before permissionless mode was activated)
130+
- signer key for the sequencer according to Clique consensus
131+
- relayer and coordinator are set up, running and up-to-date with the latest state of the L2 chain (before permissionless mode was activated)
132+
133+
### l2geth recovery
134+
Running l2geth in recovery mode requires following configuration:
135+
- `--scroll` or `--scroll-sepolia` - enables Scroll Mainnet or Sepolia mode
136+
- `--da.blob.beaconnode` - L1 RPC beacon node
137+
- `--l1.endpoint` - L1 RPC execution client
138+
- `--da.sync=true` - enables syncing with L1
139+
- `--da.recovery` - enables recovery mode
140+
- `--da.recovery.signblocks` - enables signing blocks with the sequencer and configured key
141+
- `--da.recovery.initiall1block` - initial L1 block (commit tx of initial batch)
142+
- `--da.recovery.initialbatch` - batch where to start recovery from. Can be found on [Scrollscan Explorer](https://scrollscan.com/batches).
143+
- `--da.recovery.l2endblock` - until which L2 block recovery should run (optional)
144+
145+
```bash
146+
./build/bin/geth --scroll<-sepolia> \
147+
--datadir "tmp/datadir" \
148+
--gcmode archive \
149+
--http --http.addr "0.0.0.0" --http.port 8545 --http.api "eth,net,web3,debug,scroll" --http.vhosts "*" \
150+
--da.blob.beaconnode "<L1 RPC beacon node>" \
151+
--l1.endpoint "<L1 RPC execution client>" \
152+
--da.sync=true --da.recovery --da.recovery.signblocks --da.recovery.initiall1block "<initial L1 block (commit tx of initial batch)>" --da.recovery.initialbatch "<batch where to start recovery from>" --da.recovery.l2endblock "<until which L2 block recovery should run (optional)>" \
153+
--verbosity 3
154+
```
155+
156+
After the recovery is finished, start the sequencer in normal operation and continue issuing L2 blocks as normal. This will resume the L2 chain, allow the relayer (after running recovery) to create new batches and allow other L2 follower nodes to sync up the valid and signed L2 chain.
157+
158+
### Relayer recovery
159+
Start the relayer with the following additional top-level configuration:
160+
```
161+
"recovery_config": {
162+
"enable": true
163+
}
164+
```
165+
166+
This will make the relayer recover all the chunks, batches and bundles that were submitted during permissionless mode. These batches are marked automatically as proven and finalized.
167+
Once this process is finished, start the relayer normally without the recovery config to resume normal operation.
168+
```
169+
"recovery_config": {
170+
"enable": false
171+
}
172+
```

0 commit comments

Comments
 (0)