Skip to content

Commit 0104881

Browse files
committed
fix: add correct path to runParkingBinary and use the public gateway to getDataSet
1 parent 239e0e7 commit 0104881

3 files changed

Lines changed: 105 additions & 69 deletions

File tree

scripts/backup-helper/README.md

Lines changed: 59 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,73 @@ This tool turns the inventory into:
88

99
The input DB is treated as strictly read-only, and all derived state lives in `tracking.db` under the output directory, so `rm -rf <dir>` is always a safe reset.
1010

11-
## Subcommands
11+
## Commands
1212

13-
```sh
14-
node scripts/backup-helper/index.mjs create --db <space-inventory.db> --dir <output-dir>
15-
node scripts/backup-helper/index.mjs download --dir <output-dir> [--port N] [--concurrency N]
16-
node scripts/backup-helper/index.mjs prepare --dir <output-dir> [--concurrency N]
17-
node scripts/backup-helper/index.mjs commit --dir <output-dir> --target <curio-piece-dir> --service-url https://... --provider-address 0x... --session-key 0x... --customer-wallet 0x... [--network mainnet|calibration] [--concurrency N] [--retry]
18-
```
13+
* **`create`** — Reads the input DB, deduplicates shards by `shard_cid` across all spaces, and generates:
14+
15+
* `<dir>/tracking.db`
16+
* `<dir>/manifest.aria2`
17+
18+
Safe to re-run. Produces identical output for unchanged input and never overwrites an existing `piece_cid`.
19+
20+
* **`download`** — Starts a local aria2 RPC worker and downloads shards from `tracking.db` into:
21+
22+
```
23+
<dir>/shards/<shardCID>.car
24+
```
25+
26+
Resumable via `tracking.db`, `aria2.session`, and `.aria2` control files. If `--port` is not provided, a free localhost port is selected automatically.
1927

20-
- `create` — read the input DB, deduplicate by `shard_cid` across every space,
21-
populate `<dir>/tracking.db`, and stream `<dir>/manifest.aria2`. Idempotent
22-
on re-run: produces byte-identical output for unchanged input and never
23-
clobbers a previously-computed `piece_cid` in tracking.db.
24-
- `download` — starts a local aria2 RPC worker directly from the command,
25-
then schedules shards from `tracking.db`.
26-
Writes each CAR to `<dir>/shards/<shardCID>.car`. Resumable via shard status
27-
in `tracking.db`, plus aria2's session and per-file `.aria2` control files.
28-
`--port N` is optional; if omitted, `download` picks a free localhost port
29-
for that run automatically. The `manifest.aria2` and `aria2.session` files are
30-
just generated artifacts that can be useful for debugging if needed.
31-
- `prepare` — process completed local shard CARs from `tracking.db`, compute
32-
pieceCID v2 when `piece_cid IS NULL`, and rename each prepared CAR from
33-
`<shardCID>.car` to `<pieceCID>.car`. Failures land in `tracking.db`'s
34-
`failures` table under `stage='prepare'`; rows are deleted on a later
35-
successful attempt.
36-
- `commit` — uses `tracking.db` plus Synapse to park prepared pieces and commit
37-
them on-chain. The parking flow shells out to
38-
`curio toolbox import-pieces --source <dir> --target <target> --batch-size N`
39-
and consumes its JSON `{ count, pieces }` output until `count = 0`. Commit
40-
state is persisted on `root_shards` plus a single `migration_metadata` row in
41-
`tracking.db`.
28+
* **`prepare`** — Processes downloaded CARs, computes missing Piece CID v2 values, and renames files from:
29+
30+
```
31+
<shardCID>.car → <pieceCID>.car
32+
```
33+
34+
Failures are recorded in `tracking.db` (`stage='prepare'`) and cleared automatically after a successful retry.
35+
36+
* **`commit`** — Parks prepared pieces in Curio and performs on-chain commits concurrently using synapse-core. Piece parking is done through:
37+
38+
```bash
39+
curio toolbox import-pieces \
40+
--source <dir> \
41+
--target <target> \
42+
--batch-size N
43+
```
44+
45+
The command continuously imports pieces into Curio while concurrently submitting eligible commits on-chain. Progress is persisted in `tracking.db` (`root_shards` and `migration_metadata`), allowing the operation to be safely resumed after interruptions.
4246

4347
## End-to-end workflow
4448

4549
```sh
4650
# 1. Inventory + manifest (fast: minutes for 2M-row input DBs).
4751
node scripts/backup-helper/index.mjs create \
48-
--db /path/to/space-inventory.db \
49-
--dir /path/to/backup-dir
52+
--db <space-inventory.db> \
53+
--dir <output-dir>
5054

5155
# 2. Download CARs (long: hours for terabyte-scale inventories; resumable).
56+
# Optional: pin aria2 RPC to a specific localhost port
5257
node scripts/backup-helper/index.mjs download \
53-
--dir /path/to/backup-dir
54-
55-
# Optional: pin aria2 RPC to a specific localhost port for debugging.
56-
node scripts/backup-helper/index.mjs download \
57-
--dir /path/to/backup-dir \
58-
--port 6801
58+
--dir <output-dir> \
59+
[--port N] \
60+
[--concurrency N]
5961

6062
# 3. Compute pieceCIDs + rename CARs to pieceCID filenames.
6163
node scripts/backup-helper/index.mjs prepare \
62-
--dir /path/to/backup-dir
64+
--dir <output-dir> \
65+
[--concurrency N]
6366

6467
# 4. Park prepared pieces and commit them on-chain.
6568
node scripts/backup-helper/index.mjs commit \
66-
--dir /path/to/backup-dir \
67-
--target /path/to/curio-storage/piece \
68-
--service-url https://pdp.example.com/ \
69+
--dir <output-dir> \
70+
--target <curio-piece-dir> \
71+
--service-url https://... \
6972
--provider-address 0x... \
7073
--session-key 0x... \
71-
--customer-wallet 0x...
74+
--customer-wallet 0x... \
75+
[--network mainnet|calibration] \
76+
[--concurrency N] \
77+
[--retry]
7278
```
7379

7480
## Final Output layout
@@ -84,27 +90,27 @@ node scripts/backup-helper/index.mjs commit \
8490

8591
## Requirements
8692

87-
- Node.js **24** (uses the built-in `node:sqlite`; no native `better-sqlite3`
93+
* Node.js **24** (uses the built-in `node:sqlite`; no native `better-sqlite3`
8894
install required).
89-
- `aria2c` on PATH for the `download` subcommand.
90-
- macOS: `brew install aria2`
91-
- Debian/Ubuntu: `sudo apt install aria2`
92-
- Windows: download from <https://aria2.github.io/> and add `aria2c.exe` to PATH.
93-
- `@filoz/synapse-core` for pieceCID v2 streaming hash
95+
* `aria2c` on PATH for the `download` subcommand.
96+
* macOS: `brew install aria2`
97+
* Debian/Ubuntu: `sudo apt install aria2`
98+
* Windows: download from <https://aria2.github.io/> and add `aria2c.exe` to PATH.
99+
* `@filoz/synapse-core` for pieceCID v2 streaming hash
94100

95101
## Caveats
96102

97-
- **The input `space-inventory.db` is read-only.** The tool opens it with the
103+
* **The input `space-inventory.db` is read-only.** The tool opens it with the
98104
`{ readOnly: true }` option and never writes. All derived state lives in
99105
`<dir>/tracking.db`, separate from the client's deliverable.
100-
- **One `<dir>` per client.** The output directory is the unit of "a client's
106+
* **One `<dir>` per client.** The output directory is the unit of "a client's
101107
backup". Different clients should run in different directories.
102-
- **Don't run two backup-helper commands against the same `<dir>` at the same
108+
* **Don't run two backup-helper commands against the same `<dir>` at the same
103109
time.** .
104-
- **`download` uses one local aria2 RPC daemon per run.** By default it picks a
110+
* **`download` uses one local aria2 RPC daemon per run.** By default it picks a
105111
free localhost port automatically; you can override it with `--port N` when
106112
you need a predictable port for debugging.
107-
- **`download` performance is tuned for Cloudflare R2-hosted shards.** The
113+
* **`download` performance is tuned for Cloudflare R2-hosted shards.** The
108114
aria2 worker saturates bandwidth horizontally via
109115
`--max-concurrent-downloads` and uses size-based per-file `split` /
110116
`max-connection-per-server` settings. Tune via `--concurrency N`; current

scripts/backup-helper/commands/commit.mjs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import { fromSecp256k1 } from '@filoz/synapse-core/session-key'
1010
import { addPieces, createDataSet, waitForAddPieces, waitForCreateDataSet } from '@filoz/synapse-core/sp'
1111
import { getDataSet } from '@filoz/synapse-core/warm-storage'
1212
import { execa } from 'execa'
13+
import { createPublicClient, http } from 'viem'
1314
import { getAddress } from 'viem/utils'
1415
import { z } from 'zod'
1516

1617
import { renderProgressLine } from '../../utils.js'
18+
import { shardsDir } from '../lib/layout.mjs'
1719
import { openTrackingDb } from '../lib/tracking-db.mjs'
1820

1921
const PARKING_BATCH_SIZE = 50
@@ -28,6 +30,12 @@ const EMPTY_POLL_INTERVAL_MS = 1_000
2830
* @property {string} pieceCid
2931
*/
3032

33+
/**
34+
* @typedef {object} EnsuredDataSet
35+
* @property {number} dataSetId
36+
* @property {bigint} clientDataSetId
37+
*/
38+
3139
/** @typedef {ReturnType<typeof openTrackingDb>} TrackingDb */
3240

3341
function sleep(ms) {
@@ -58,25 +66,28 @@ async function createSessionKey(sessionKeyStr, customerWallet, chain) {
5866
* @param {ReturnType<typeof fromSecp256k1>} args.sessionKey
5967
* @param {string} args.serviceUrl
6068
* @param {`0x${string}`} args.providerAddress
69+
* @param {import('viem').PublicClient} args.publicClient
70+
* @returns {Promise<EnsuredDataSet>}
6171
*/
62-
async function ensureDataSet({ tracking, sessionKey, serviceUrl, providerAddress }) {
72+
async function ensureDataSet({ tracking, sessionKey, serviceUrl, providerAddress, publicClient }) {
6373
const metadata = tracking.getMigrationMetadata()
6474
if (!metadata) {
6575
throw new Error('commit: migration metadata was not initialized')
6676
}
6777

6878
if (metadata.dataSetId != null) {
79+
console.log(`Dataset ${metadata.dataSetId} already exists, skipping creation...`)
6980
if (metadata.clientDataSetId == null) {
70-
const dataSetInfo = await getDataSet(sessionKey.client, {
81+
const dataSetInfo = await getDataSet(publicClient, {
7182
dataSetId: BigInt(metadata.dataSetId),
7283
})
7384
if (!dataSetInfo) {
7485
throw new Error(`commit: dataset ${metadata.dataSetId} was not found on-chain`)
7586
}
76-
tracking.setMigrationClientDataSetId(Number(dataSetInfo.clientDataSetId))
87+
tracking.setMigrationClientDataSetId(dataSetInfo.clientDataSetId)
7788
return {
7889
dataSetId: metadata.dataSetId,
79-
clientDataSetId: Number(dataSetInfo.clientDataSetId),
90+
clientDataSetId: dataSetInfo.clientDataSetId,
8091
}
8192
}
8293

@@ -90,6 +101,11 @@ async function ensureDataSet({ tracking, sessionKey, serviceUrl, providerAddress
90101
}
91102
}
92103

104+
console.log(`Creating dataset...
105+
payee=${providerAddress}
106+
payer=${metadata.clientWallet}
107+
serviceURL=${serviceUrl}
108+
`)
93109
const createResult = await createDataSet(sessionKey.client, {
94110
cdn: true,
95111
payee: providerAddress,
@@ -100,20 +116,30 @@ async function ensureDataSet({ tracking, sessionKey, serviceUrl, providerAddress
100116
withIPFSIndexing: '',
101117
},
102118
})
119+
120+
console.log(`Waiting for dataset to be created...
121+
txHash=${createResult.txHash}
122+
statusUrl=${createResult.statusUrl}
123+
`)
124+
103125
const { dataSetId } = await waitForCreateDataSet(createResult)
104-
const dataSetInfo = await getDataSet(sessionKey.client, { dataSetId })
126+
console.log(`Dataset created: id=${dataSetId.toString()}`)
127+
128+
const dataSetInfo = await getDataSet(publicClient, { dataSetId })
105129
if (!dataSetInfo) {
106130
throw new Error(`commit: dataset ${dataSetId} was created but could not be fetched`)
107131
}
108132

133+
console.log(`Saving dataset info: dataSetId=${dataSetId.toString()} clientDataSetId=${dataSetInfo.clientDataSetId}`)
134+
109135
tracking.markMigrationDataSetCreated({
110136
dataSetId: Number(dataSetId),
111-
clientDataSetId: Number(dataSetInfo.clientDataSetId),
137+
clientDataSetId: dataSetInfo.clientDataSetId,
112138
})
113139

114140
return {
115141
dataSetId: Number(dataSetId),
116-
clientDataSetId: Number(dataSetInfo.clientDataSetId),
142+
clientDataSetId: dataSetInfo.clientDataSetId,
117143
}
118144
}
119145

@@ -148,7 +174,7 @@ async function runParkingBinary(dir, target) {
148174
'toolbox',
149175
'import-pieces',
150176
'--source',
151-
dir,
177+
shardsDir(dir),
152178
'--target',
153179
target,
154180
'--batch-size',
@@ -180,7 +206,7 @@ function buildCommitPieces(rows) {
180206
* @param {ReturnType<typeof fromSecp256k1>} args.sessionKey
181207
* @param {string} args.serviceUrl
182208
* @param {number} args.dataSetId
183-
* @param {number} args.clientDataSetId
209+
* @param {bigint} args.clientDataSetId
184210
* @param {TrackingDb} args.tracking
185211
* @param {CommitRow[]} args.rows
186212
*/
@@ -189,7 +215,7 @@ async function commitBatch({ sessionKey, serviceUrl, dataSetId, clientDataSetId,
189215
const addResult = await addPieces(sessionKey.client, {
190216
serviceURL: serviceUrl,
191217
dataSetId: BigInt(dataSetId),
192-
clientDataSetId: BigInt(clientDataSetId),
218+
clientDataSetId,
193219
pieces: buildCommitPieces(rows),
194220
})
195221
const addStatus = await waitForAddPieces({ statusUrl: addResult.statusUrl })
@@ -241,12 +267,16 @@ export async function runCommit({
241267
tracking.resetCommitRowsForRetry()
242268
}
243269

270+
console.log(`crate session key...`)
244271
const session = await createSessionKey(/** @type {`0x${string}`} */ (sessionKey), customerWallet, chain)
272+
const publicClient = createPublicClient({ chain, transport: http() })
273+
245274
const ensuredDataSet = await ensureDataSet({
246275
tracking,
247276
sessionKey: session,
248277
serviceUrl,
249278
providerAddress,
279+
publicClient,
250280
})
251281

252282
const parkingLane = (async () => {

scripts/backup-helper/lib/tracking-db.mjs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ const MIGRATION_STATE = {
8686
* @property {string} serviceUrl
8787
* @property {string} providerAddress
8888
* @property {number | null} dataSetId
89-
* @property {number | null} clientDataSetId
89+
* @property {bigint | null} clientDataSetId
9090
* @property {string} state
9191
* @property {number} updatedAt
9292
*/
@@ -723,7 +723,7 @@ export function openTrackingDb(dir) {
723723
serviceUrl: row.service_url.toString(),
724724
providerAddress: row.provider_address.toString(),
725725
dataSetId: row.data_set_id != null ? Number(row.data_set_id) : null,
726-
clientDataSetId: row.client_data_set_id != null ? Number(row.client_data_set_id) : null,
726+
clientDataSetId: row.client_data_set_id != null ? BigInt(row.client_data_set_id.toString()) : null,
727727
state: row.state.toString(),
728728
updatedAt: Number(row.updated_at),
729729
}
@@ -737,19 +737,19 @@ export function openTrackingDb(dir) {
737737
},
738738

739739
/**
740-
* @param {number} clientDataSetId
740+
* @param {bigint} clientDataSetId
741741
*/
742742
setMigrationClientDataSetId(clientDataSetId) {
743-
updateMigrationClientDataSetIdStmt.run(clientDataSetId, now())
743+
updateMigrationClientDataSetIdStmt.run(clientDataSetId.toString(), now())
744744
},
745745

746746
/**
747747
* @param {object} metadata
748748
* @param {number} metadata.dataSetId
749-
* @param {number} metadata.clientDataSetId
749+
* @param {bigint} metadata.clientDataSetId
750750
*/
751751
markMigrationDataSetCreated({ dataSetId, clientDataSetId }) {
752-
updateMigrationMetadataStmt.run(dataSetId, clientDataSetId, MIGRATION_STATE.migrating, now())
752+
updateMigrationMetadataStmt.run(dataSetId, clientDataSetId.toString(), MIGRATION_STATE.migrating, now())
753753
},
754754

755755
resetCommitRowsForRetry() {

0 commit comments

Comments
 (0)