@@ -62,16 +62,144 @@ Badger backups end-to-end:
6262 ``` bash
6363 ./scripts/reth-backup/backup.sh backups/full-run/reth
6464 ```
65- 5 . Stream a Badger backup from the ev-node into the container filesystem and
66- copy it to the host.
65+ The script prints the generated tag (for example ` 20251013-104816 ` ) and the
66+ captured height (stored under
67+ ` backups/full-run/reth/<TAG>/height.txt ` ).
68+ 5 . Align the ev-node datastore to that height and take the Badger backup:
6769 ``` bash
68- docker compose exec ev-node-evm-single \
69- evm-single backup --output /tmp/evnode-backup.badger --force
70- docker cp ev-node-evm-single:/tmp/evnode-backup.badger backups/full-run/ev-node/
70+ HEIGHT=$( cat backups/full-run/reth/< TAG> /height.txt)
71+ BACKUP_ROOT=" $( pwd) /backups/full-run"
72+
73+ # Stop the managed container so it cannot advance.
74+ (cd apps/evm/single && docker compose stop ev-node-evm-single)
75+
76+ # Roll the datastore back to the captured height. The --sync-node and
77+ # --skip-p2p-stores flags avoid DA-finality and header-store checks.
78+ (cd apps/evm/single && docker compose run --rm \
79+ ev-node-evm-single rollback \
80+ --height " ${HEIGHT} " \
81+ --home /root/.evm-single \
82+ --sync-node \
83+ --skip-p2p-stores)
84+
85+ # Stream the Badger backup without producing new blocks.
86+ cat << 'EOF ' > /tmp/evnode_backup.sh
87+ set -euo pipefail
88+ OUT="$1"
89+ TARGET="$2"
90+ START_CMD="evm-single start \
91+ --home=/root/.evm-single \
92+ --evm.jwt-secret $EVM_JWT_SECRET \
93+ --evm.genesis-hash $EVM_GENESIS_HASH \
94+ --evm.engine-url $EVM_ENGINE_URL \
95+ --evm.eth-url $EVM_ETH_URL \
96+ --rollkit.node.block_time 1h \
97+ --rollkit.node.aggregator=true \
98+ --rollkit.signer.passphrase $EVM_SIGNER_PASSPHRASE \
99+ --rollkit.da.address $DA_ADDRESS \
100+ --evnode.clear_cache"
101+ rm -f "$OUT"
102+ sh -c "$START_CMD" &
103+ PID=$!
104+ trap "kill $PID 2>/dev/null || true; wait $PID 2>/dev/null || true" EXIT
105+ for i in $(seq 1 30); do
106+ sleep 2
107+ if evm-single backup --output "$OUT" --force --target-height "$TARGET" >/tmp/backup.log 2>&1; then
108+ cat /tmp/backup.log
109+ exit 0
110+ fi
111+ cat /tmp/backup.log
112+ done
113+ echo "backup did not succeed within timeout" >&2
114+ exit 1
115+ EOF
116+ chmod +x /tmp/evnode_backup.sh
117+
118+ (cd apps/evm/single && docker compose run --rm \
119+ --entrypoint sh \
120+ -v /tmp/evnode_backup.sh:/tmp/evnode_backup.sh \
121+ -v " ${BACKUP_ROOT} /ev-node:/host-backup" \
122+ ev-node-evm-single \
123+ -c " /tmp/evnode_backup.sh /host-backup/evnode-backup-aligned.badger ${HEIGHT} " )
124+
125+ rm /tmp/evnode_backup.sh
126+ # Bring the managed container back with its usual supervisor.
127+ (cd apps/evm/single && docker compose start ev-node-evm-single)
71128 ```
129+ The CLI will report the streamed metadata, and the backup lands at
130+ ` backups/full-run/ev-node/evnode-backup-aligned.badger ` .
721316 . When finished, tear the stack down.
73132 ``` bash
74133 (cd apps/evm/single && docker compose down)
75134 ```
76135
77136Both backups can then be found under ` backups/full-run/ ` .
137+
138+ ## Restoring and validating the backups
139+
140+ To verify that both snapshots can be replayed, you can shut everything down, mutate the live data, and then restore from the artifacts collected above.
141+
142+ 1 . ** Let the stack advance after the backup (optional but recommended).** Keep ` docker compose ` running for a few more blocks or submit a dev transaction so the live height diverges from the one recorded in ` backups/full-run/reth/height.txt ` .
143+ 2 . ** Stop the services.**
144+ ``` bash
145+ (cd apps/evm/single && docker compose down)
146+ ```
147+ 3 . ** Recreate the containers without starting them.** This gives you stopped containers that already own the right named volumes.
148+ ``` bash
149+ (cd apps/evm/single && docker compose up --no-start)
150+ ```
151+ 4 . ** Restore the ` ev-reth ` MDBX volume from the snapshot.** Run the following from the repository root (adjust ` BACKUP_ROOT ` if you saved the files elsewhere):
152+ ``` bash
153+ BACKUP_ROOT=" $( pwd) /backups/full-run"
154+ docker run --rm \
155+ --volumes-from ev-reth \
156+ -v " ${BACKUP_ROOT} /reth:/backup:ro" \
157+ alpine:3.18 \
158+ sh -ec ' rm -rf /home/reth/eth-home/db /home/reth/eth-home/static_files && \
159+ mkdir -p /home/reth/eth-home/db /home/reth/eth-home/static_files && \
160+ cp /backup/db/mdbx.dat /home/reth/eth-home/db/mdbx.dat && \
161+ cp /backup/db/mdbx.lck /home/reth/eth-home/db/mdbx.lck && \
162+ cp -a /backup/static_files/. /home/reth/eth-home/static_files/ || true'
163+ ```
164+ > ` docker run --volumes-from ev-reth ` reuses the stopped container's volumes; adjust ` alpine:3.18 ` if you prefer another image that provides ` cp ` .
165+ 5 . ** Restore the ` ev-node ` Badger datastore.**
166+ ``` bash
167+ TEMP_RESTORE=" $( mktemp -d backups/full-run/ev-node/restore-XXXXXX) "
168+ badger restore --dir " ${TEMP_RESTORE} " --files " ${BACKUP_ROOT} /ev-node/evnode-backup-aligned.badger"
169+ docker run --rm \
170+ --volumes-from ev-node-evm-single \
171+ -v " ${TEMP_RESTORE} :/restore:ro" \
172+ alpine:3.18 \
173+ sh -ec ' rm -rf /root/.evm-single/data && mkdir -p /root/.evm-single/data/evm-single && \
174+ cp -a /restore/. /root/.evm-single/data/evm-single/'
175+ rm -rf " ${TEMP_RESTORE} "
176+ ```
177+ > Install the Badger CLI once via ` go install github.com/dgraph-io/badger/v4/cmd/badger@latest ` if it is not already on your ` $PATH ` .
178+ 6 . ** Start the services back up.**
179+ ``` bash
180+ (cd apps/evm/single && docker compose up -d ev-reth local-da)
181+ (cd apps/evm/single && docker compose up -d ev-node-evm-single)
182+ ```
183+ If you prefer to launch the sequencer manually first, you can run:
184+ ``` bash
185+ (cd apps/evm/single && docker compose run --rm \
186+ ev-node-evm-single start \
187+ --home /root/.evm-single \
188+ --evm.jwt-secret " $EVM_JWT_SECRET " \
189+ --evm.genesis-hash " $EVM_GENESIS_HASH " \
190+ --evm.engine-url " $EVM_ENGINE_URL " \
191+ --evm.eth-url " $EVM_ETH_URL " \
192+ --rollkit.node.block_time 1s \
193+ --rollkit.node.aggregator=true \
194+ --rollkit.signer.passphrase " $EVM_SIGNER_PASSPHRASE " \
195+ --rollkit.da.address " $DA_ADDRESS " \
196+ --evnode.clear_cache)
197+ ```
198+ and once it exits cleanly, start the managed container with ` docker compose up -d ev-node-evm-single ` .
199+ 7 . ** Confirm the node resumes from the backed-up height.** Compare the logged chain height with ` backups/full-run/reth/height.txt ` and run:
200+ ``` bash
201+ (cd apps/evm/single && docker compose exec ev-node-evm-single evm-single net-info --home /root/.evm-single)
202+ ```
203+ The reported height should match the snapshot before new blocks are produced.
204+
205+ With this round-trip check you can be confident that the snapshot pair (MDBX + Badger) fully recreates the state captured during the backup.
0 commit comments