Skip to content

Commit deb559e

Browse files
committed
fix: replace SDK activePieceCount with hasActivePieces
Listing paths now report piece presence from leaf count, and getActivePieceCount paginates the cursor API instead of the linear-scan getter.
1 parent b97f1a2 commit deb559e

5 files changed

Lines changed: 72 additions & 22 deletions

File tree

docs/src/content/docs/developer-guides/migration-guide.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,15 @@ if (dataSet?.hasActivePieces) {
121121
}
122122
```
123123

124-
`WarmStorageService.hasActivePieces()` keeps the same public API, but now uses the same leaf-count proxy instead of calculating an exact count.
124+
`WarmStorageService.hasActivePieces()` keeps the same public API, but now uses the same leaf-count proxy instead of calculating an exact count. `EnhancedDataSetInfo` from `getClientDataSetsWithDetails()` / `findDataSets()` also exposes `hasActivePieces` instead of `activePieceCount`.
125125

126-
The standalone `getActivePieceCount()` action remains available, but the underlying contract getter scans the data set's piece-ID range and can fail for large data sets. If you need an exact count, explicitly paginate the active pieces:
126+
The core `getActivePieceCount()` action remains available, but the underlying contract getter scans the data set's piece-ID range and can fail for large data sets. `WarmStorageService.getActivePieceCount()` now paginates `getActivePiecesByCursor` to derive an exact count:
127+
128+
```ts
129+
const activePieceCount = await warmStorageService.getActivePieceCount({ dataSetId })
130+
```
131+
132+
To paginate explicitly in core:
127133

128134
```ts
129135
let activePieceCount = 0n
@@ -135,8 +141,6 @@ for await (const _piece of paginate(({ cursor }) =>
135141
}
136142
```
137143

138-
This field change is limited to the enriched data set types in `@filoz/synapse-core`; the SDK's legacy `EnhancedDataSetInfo.activePieceCount` field is unchanged.
139-
140144
---
141145

142146
## 1.0.0

docs/src/content/docs/developer-guides/storage/storage-operations.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ These APIs are useful when you want to inspect existing data sets, query stored
196196

197197
### Getting All Data Sets
198198

199-
Retrieve all data sets owned by your account to inspect piece counts, CDN status, and metadata:
199+
Retrieve all data sets owned by your account to inspect piece presence, CDN status, and metadata:
200200

201201
```ts twoslash
202202
// @lib: esnext,dom
@@ -210,7 +210,7 @@ for (const ds of dataSets) {
210210
console.log(`Dataset ${ds.pdpVerifierDataSetId}:`, {
211211
live: ds.isLive,
212212
cdn: ds.withCDN,
213-
pieces: ds.activePieceCount,
213+
hasActivePieces: ds.hasActivePieces,
214214
metadata: ds.metadata
215215
});
216216
}

packages/synapse-sdk/src/test/warm-storage-service.test.ts

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { calibration } from '@filoz/synapse-core/chains'
88
import * as Mocks from '@filoz/synapse-core/mocks'
99
import { assert } from 'chai'
1010
import { setup } from 'iso-web/msw'
11-
import { type Address, createWalletClient, http as viemHttp } from 'viem'
11+
import { CID } from 'multiformats/cid'
12+
import { type Address, bytesToHex, createWalletClient, http as viemHttp } from 'viem'
1213
import { privateKeyToAccount } from 'viem/accounts'
1314
import { WarmStorageService } from '../warm-storage/index.ts'
1415

@@ -83,6 +84,51 @@ describe('WarmStorageService', () => {
8384
})
8485
})
8586

87+
describe('getActivePieceCount', () => {
88+
it('should count active pieces by paginating the cursor', async () => {
89+
server.use(Mocks.JSONRPC(Mocks.presets.basic))
90+
const warmStorageService = await createWarmStorageService()
91+
assert.equal(await warmStorageService.getActivePieceCount({ dataSetId: 1n }), 2n)
92+
})
93+
94+
it('should return zero when the data set has no active pieces', async () => {
95+
server.use(
96+
Mocks.JSONRPC({
97+
...Mocks.presets.basic,
98+
pdpVerifier: {
99+
...Mocks.presets.basic.pdpVerifier,
100+
getActivePiecesByCursor: () => [[], [], false],
101+
},
102+
})
103+
)
104+
const warmStorageService = await createWarmStorageService()
105+
assert.equal(await warmStorageService.getActivePieceCount({ dataSetId: 1n }), 0n)
106+
})
107+
108+
it('should sum pieces across cursor pages', async () => {
109+
const first = CID.parse('bafkzcibcd4bdomn3tgwgrh3g532zopskstnbrd2n3sxfqbze7rxt7vqn7veigmy')
110+
const second = CID.parse('bafkzcibeqcad6efnpwn62p5vvs5x3nh3j7xkzfgb3xtitcdm2hulmty3xx4tl3wace')
111+
server.use(
112+
Mocks.JSONRPC({
113+
...Mocks.presets.basic,
114+
pdpVerifier: {
115+
...Mocks.presets.basic.pdpVerifier,
116+
getActivePiecesByCursor: (args) => {
117+
const startPieceId = args[1]
118+
if (startPieceId === 0n) {
119+
return [[{ data: bytesToHex(first.bytes) }], [1n], true]
120+
}
121+
assert.equal(startPieceId, 2n)
122+
return [[{ data: bytesToHex(second.bytes) }], [2n], false]
123+
},
124+
},
125+
})
126+
)
127+
const warmStorageService = await createWarmStorageService()
128+
assert.equal(await warmStorageService.getActivePieceCount({ dataSetId: 1n }), 2n)
129+
})
130+
})
131+
86132
describe('getDataSet', () => {
87133
it('should return a single data set by ID', async () => {
88134
server.use(Mocks.JSONRPC(Mocks.presets.basic))
@@ -485,7 +531,7 @@ describe('WarmStorageService', () => {
485531
assert.lengthOf(detailedDataSets, 1)
486532
assert.equal(detailedDataSets[0].pdpRailId, 48n)
487533
assert.equal(detailedDataSets[0].pdpVerifierDataSetId, 242n)
488-
assert.equal(detailedDataSets[0].activePieceCount, 2n)
534+
assert.isTrue(detailedDataSets[0].hasActivePieces)
489535
assert.isTrue(detailedDataSets[0].isLive)
490536
assert.isTrue(detailedDataSets[0].isManaged)
491537
})

packages/synapse-sdk/src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,8 @@ export interface DataSetInfo {
256256
export interface EnhancedDataSetInfo extends DataSetInfo {
257257
/** PDPVerifier global data set ID */
258258
pdpVerifierDataSetId: bigint
259-
/** Number of active pieces in the data set (excludes removed pieces) */
260-
activePieceCount: bigint
259+
/** Whether the data set contains at least one active piece (non-zero leaf count). */
260+
hasActivePieces: boolean
261261
/** Whether the data set is live on-chain */
262262
isLive: boolean
263263
/** Whether this data set is managed by the current Warm Storage contract */

packages/synapse-sdk/src/warm-storage/service.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,8 @@ export class WarmStorageService {
148148
* Get all data sets for a client with enhanced details
149149
* This includes live status and management information.
150150
*
151-
* `activePieceCount` still uses the contract's linear-scan getter and can run
152-
* out of gas for large data sets. Prefer {@link hasActivePieces} when only
153-
* presence is needed.
151+
* Piece presence uses a non-zero PDP leaf count rather than an exact active
152+
* piece count. Prefer {@link getActivePieceCount} when an exact count is needed.
154153
* @param options - Options for the client data sets
155154
* @param options.address - The client address. Defaults to the client account address.
156155
* @param options.onlyManaged - If true, only return data sets managed by this Warm Storage contract. Defaults to false.
@@ -195,15 +194,13 @@ export class WarmStorageService {
195194
return null // Will be filtered out
196195
}
197196

198-
// Get active piece count only if the data set is live
199-
const activePieceCount = isLive
200-
? await PDPVerifier.getActivePieceCount(this._client, { dataSetId: dataSet.dataSetId })
201-
: 0n
197+
// Get piece presence only if the data set is live
198+
const hasActivePieces = isLive ? await this.hasActivePieces({ dataSetId: dataSet.dataSetId }) : false
202199

203200
return {
204201
...dataSet,
205202
pdpVerifierDataSetId: dataSet.dataSetId,
206-
activePieceCount,
203+
hasActivePieces,
207204
isLive,
208205
isManaged,
209206
withCDN: dataSet.cdnRailId > 0 && metadata[0].includes(METADATA_KEYS.WITH_CDN),
@@ -284,15 +281,18 @@ export class WarmStorageService {
284281
/**
285282
* Get the count of active pieces in a dataset (excludes removed pieces)
286283
*
287-
* The contract getter scans the data set's piece-ID range and can run out of
288-
* gas for large data sets. Prefer {@link hasActivePieces} when only presence
289-
* is needed, or paginate `getActivePiecesByCursor` to derive an exact count.
284+
* Paginates `getActivePiecesByCursor` rather than calling the contract's
285+
* linear-scan getter, which can run out of gas for large data sets.
286+
* Prefer {@link hasActivePieces} when only presence is needed.
290287
* @param options - Options for the data set
291288
* @param options.dataSetId - The PDPVerifier data set ID
292289
* @returns The number of active pieces
293290
*/
294291
async getActivePieceCount(options: { dataSetId: bigint }): Promise<bigint> {
295-
return PDPVerifier.getActivePieceCount(this._client, { dataSetId: options.dataSetId })
292+
const pieces = await Array.fromAsync(
293+
paginate(({ cursor }) => PDPVerifier.getActivePiecesByCursor(this._client, { ...options, cursor }))
294+
)
295+
return BigInt(pieces.length)
296296
}
297297

298298
/**

0 commit comments

Comments
 (0)