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