Skip to content

Commit 6435cc2

Browse files
feat(synapse-core): support paginated client dataset reads from FWSS (#698)
1 parent 8b85290 commit 6435cc2

11 files changed

Lines changed: 600 additions & 7 deletions

packages/synapse-core/src/abis/generated.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3239,6 +3239,19 @@ export const filecoinWarmStorageServiceStateViewAbi = [
32393239
],
32403240
stateMutability: 'nonpayable',
32413241
},
3242+
{
3243+
type: 'function',
3244+
inputs: [
3245+
{ name: 'payer', internalType: 'address', type: 'address' },
3246+
{ name: 'offset', internalType: 'uint256', type: 'uint256' },
3247+
{ name: 'limit', internalType: 'uint256', type: 'uint256' },
3248+
],
3249+
name: 'clientDataSets',
3250+
outputs: [
3251+
{ name: 'dataSetIds', internalType: 'uint256[]', type: 'uint256[]' },
3252+
],
3253+
stateMutability: 'view',
3254+
},
32423255
{
32433256
type: 'function',
32443257
inputs: [{ name: 'payer', internalType: 'address', type: 'address' }],
@@ -3307,6 +3320,36 @@ export const filecoinWarmStorageServiceStateViewAbi = [
33073320
outputs: [{ name: 'count', internalType: 'uint256', type: 'uint256' }],
33083321
stateMutability: 'view',
33093322
},
3323+
{
3324+
type: 'function',
3325+
inputs: [
3326+
{ name: 'client', internalType: 'address', type: 'address' },
3327+
{ name: 'offset', internalType: 'uint256', type: 'uint256' },
3328+
{ name: 'limit', internalType: 'uint256', type: 'uint256' },
3329+
],
3330+
name: 'getClientDataSets',
3331+
outputs: [
3332+
{
3333+
name: 'infos',
3334+
internalType: 'struct FilecoinWarmStorageService.DataSetInfoView[]',
3335+
type: 'tuple[]',
3336+
components: [
3337+
{ name: 'pdpRailId', internalType: 'uint256', type: 'uint256' },
3338+
{ name: 'cacheMissRailId', internalType: 'uint256', type: 'uint256' },
3339+
{ name: 'cdnRailId', internalType: 'uint256', type: 'uint256' },
3340+
{ name: 'payer', internalType: 'address', type: 'address' },
3341+
{ name: 'payee', internalType: 'address', type: 'address' },
3342+
{ name: 'serviceProvider', internalType: 'address', type: 'address' },
3343+
{ name: 'commissionBps', internalType: 'uint256', type: 'uint256' },
3344+
{ name: 'clientDataSetId', internalType: 'uint256', type: 'uint256' },
3345+
{ name: 'pdpEndEpoch', internalType: 'uint256', type: 'uint256' },
3346+
{ name: 'providerId', internalType: 'uint256', type: 'uint256' },
3347+
{ name: 'dataSetId', internalType: 'uint256', type: 'uint256' },
3348+
],
3349+
},
3350+
],
3351+
stateMutability: 'view',
3352+
},
33103353
{
33113354
type: 'function',
33123355
inputs: [{ name: 'client', internalType: 'address', type: 'address' }],
@@ -3333,6 +3376,13 @@ export const filecoinWarmStorageServiceStateViewAbi = [
33333376
],
33343377
stateMutability: 'view',
33353378
},
3379+
{
3380+
type: 'function',
3381+
inputs: [{ name: 'payer', internalType: 'address', type: 'address' }],
3382+
name: 'getClientDataSetsLength',
3383+
outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }],
3384+
stateMutability: 'view',
3385+
},
33363386
{
33373387
type: 'function',
33383388
inputs: [],
@@ -3562,6 +3612,13 @@ export const pdpVerifierAbi = [
35623612
],
35633613
stateMutability: 'nonpayable',
35643614
},
3615+
{
3616+
type: 'function',
3617+
inputs: [],
3618+
name: 'FIL_SYBIL_FEE',
3619+
outputs: [{ name: '', internalType: 'uint256', type: 'uint256' }],
3620+
stateMutability: 'pure',
3621+
},
35653622
{
35663623
type: 'function',
35673624
inputs: [],
@@ -3748,6 +3805,25 @@ export const pdpVerifierAbi = [
37483805
],
37493806
stateMutability: 'view',
37503807
},
3808+
{
3809+
type: 'function',
3810+
inputs: [
3811+
{ name: 'setId', internalType: 'uint256', type: 'uint256' },
3812+
{
3813+
name: 'pieceCid',
3814+
internalType: 'struct Cids.Cid',
3815+
type: 'tuple',
3816+
components: [{ name: 'data', internalType: 'bytes', type: 'bytes' }],
3817+
},
3818+
{ name: 'startPieceId', internalType: 'uint256', type: 'uint256' },
3819+
{ name: 'limit', internalType: 'uint256', type: 'uint256' },
3820+
],
3821+
name: 'findPieceIdsByCid',
3822+
outputs: [
3823+
{ name: 'pieceIds', internalType: 'uint256[]', type: 'uint256[]' },
3824+
],
3825+
stateMutability: 'view',
3826+
},
37513827
{
37523828
type: 'function',
37533829
inputs: [{ name: 'setId', internalType: 'uint256', type: 'uint256' }],

packages/synapse-core/src/mocks/jsonrpc/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ export const presets = {
505505
getPDPConfig: () => {
506506
return [BigInt(2880), BigInt(60), BigInt(1), BigInt(0)]
507507
},
508+
getClientDataSetsLength: () => {
509+
return [1n]
510+
},
508511
},
509512
pdpVerifier: {
510513
dataSetLive: () => [true],

packages/synapse-core/src/mocks/jsonrpc/warm-storage.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type getAllPieceMetadata = ExtractAbiFunction<typeof Abis.fwssView, 'getA
2020
export type getPieceMetadata = ExtractAbiFunction<typeof Abis.fwssView, 'getPieceMetadata'>
2121
export type clientNonces = ExtractAbiFunction<typeof Abis.fwssView, 'clientNonces'>
2222
export type getPDPConfig = ExtractAbiFunction<typeof Abis.fwssView, 'getPDPConfig'>
23+
export type getClientDataSetsLength = ExtractAbiFunction<typeof Abis.fwssView, 'getClientDataSetsLength'>
2324

2425
export interface WarmStorageViewOptions {
2526
isProviderApproved?: (args: AbiToType<isProviderApproved['inputs']>) => AbiToType<isProviderApproved['outputs']>
@@ -36,6 +37,9 @@ export interface WarmStorageViewOptions {
3637
getPieceMetadata?: (args: AbiToType<getPieceMetadata['inputs']>) => AbiToType<getPieceMetadata['outputs']>
3738
clientNonces?: (args: AbiToType<clientNonces['inputs']>) => AbiToType<clientNonces['outputs']>
3839
getPDPConfig?: (args: AbiToType<getPDPConfig['inputs']>) => AbiToType<getPDPConfig['outputs']>
40+
getClientDataSetsLength?: (
41+
args: AbiToType<getClientDataSetsLength['inputs']>
42+
) => AbiToType<getClientDataSetsLength['outputs']>
3943
}
4044

4145
/**
@@ -346,6 +350,15 @@ export function warmStorageViewCallHandler(data: Hex, options: JSONRPCOptions):
346350
options.warmStorageView.getPDPConfig(args)
347351
)
348352
}
353+
case 'getClientDataSetsLength': {
354+
if (!options.warmStorageView?.getClientDataSetsLength) {
355+
throw new Error('Warm Storage View: getClientDataSetsLength is not defined')
356+
}
357+
return encodeAbiParameters(
358+
Abis.fwssView.find((abi) => abi.type === 'function' && abi.name === 'getClientDataSetsLength')!.outputs,
359+
options.warmStorageView.getClientDataSetsLength(args)
360+
)
361+
}
349362

350363
default: {
351364
throw new Error(`Warm Storage View: unknown function: ${functionName} with args: ${args}`)
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import type { Simplify } from 'type-fest'
2+
import type {
3+
Address,
4+
Chain,
5+
Client,
6+
ContractFunctionParameters,
7+
ContractFunctionReturnType,
8+
ReadContractErrorType,
9+
Transport,
10+
} from 'viem'
11+
import { readContract } from 'viem/actions'
12+
import type { fwssView as storageViewAbi } from '../abis/index.ts'
13+
import { asChain } from '../chains.ts'
14+
import type { ActionCallChain } from '../types.ts'
15+
16+
export namespace getClientDataSetIds {
17+
export type OptionsType = {
18+
/** Client address to fetch data set IDs for. */
19+
address: Address
20+
/** Starting index (0-based). Use 0 to start from beginning. Defaults to 0. */
21+
offset?: bigint
22+
/** Maximum number of dataset IDs to return. Use 0 to get all remaining IDs. Defaults to 0. */
23+
limit?: bigint
24+
/** Warm storage contract address. If not provided, the default is the storage view contract address for the chain. */
25+
contractAddress?: Address
26+
}
27+
28+
export type ContractOutputType = ContractFunctionReturnType<
29+
typeof storageViewAbi,
30+
'pure' | 'view',
31+
'clientDataSets',
32+
[Address, bigint, bigint]
33+
>
34+
35+
/** Array of client data set IDs */
36+
export type OutputType = bigint[]
37+
38+
export type ErrorType = asChain.ErrorType | ReadContractErrorType
39+
}
40+
41+
/**
42+
* Get client data set IDs with optional pagination
43+
*
44+
* For large lists, use pagination to avoid gas limit issues. If limit=0,
45+
* returns all remaining IDs starting from offset.
46+
*
47+
* @param client - The client to use to get data set IDs.
48+
* @param options - {@link getClientDataSetIds.OptionsType}
49+
* @returns Array of data set IDs {@link getClientDataSetIds.OutputType}
50+
* @throws Errors {@link getClientDataSetIds.ErrorType}
51+
*
52+
* @example
53+
* ```ts
54+
* import { getClientDataSetIds } from '@filoz/synapse-core/warm-storage'
55+
* import { createPublicClient, http } from 'viem'
56+
* import { calibration } from '@filoz/synapse-core/chains'
57+
*
58+
* const client = createPublicClient({
59+
* chain: calibration,
60+
* transport: http(),
61+
* })
62+
*
63+
* // Get first 100 dataset IDs
64+
* const ids = await getClientDataSetIds(client, {
65+
* address: '0x0000000000000000000000000000000000000000',
66+
* offset: 0n,
67+
* limit: 100n,
68+
* })
69+
*
70+
* console.log(ids)
71+
* ```
72+
*/
73+
export async function getClientDataSetIds(
74+
client: Client<Transport, Chain>,
75+
options: getClientDataSetIds.OptionsType
76+
): Promise<getClientDataSetIds.OutputType> {
77+
const data = await readContract(
78+
client,
79+
getClientDataSetIdsCall({
80+
chain: client.chain,
81+
address: options.address,
82+
offset: options.offset,
83+
limit: options.limit,
84+
contractAddress: options.contractAddress,
85+
})
86+
)
87+
return data as getClientDataSetIds.OutputType
88+
}
89+
90+
export namespace getClientDataSetIdsCall {
91+
export type OptionsType = Simplify<getClientDataSetIds.OptionsType & ActionCallChain>
92+
export type ErrorType = asChain.ErrorType
93+
export type OutputType = ContractFunctionParameters<
94+
typeof storageViewAbi,
95+
'pure' | 'view',
96+
'clientDataSets',
97+
[Address, bigint, bigint]
98+
>
99+
}
100+
101+
/**
102+
* Create a call to the {@link getClientDataSetIds} function for use with the Viem multicall, readContract, or simulateContract functions.
103+
*
104+
* @param options - {@link getClientDataSetIdsCall.OptionsType}
105+
* @returns The call to the clientDataSets function {@link getClientDataSetIdsCall.OutputType}
106+
* @throws Errors {@link getClientDataSetIdsCall.ErrorType}
107+
*
108+
* @example
109+
* ```ts
110+
* import { getClientDataSetIdsCall } from '@filoz/synapse-core/warm-storage'
111+
* import { createPublicClient, http } from 'viem'
112+
* import { multicall } from 'viem/actions'
113+
* import { calibration } from '@filoz/synapse-core/chains'
114+
*
115+
* const client = createPublicClient({
116+
* chain: calibration,
117+
* transport: http(),
118+
* })
119+
*
120+
* // Paginate through IDs in batches of 50
121+
* const results = await multicall(client, {
122+
* contracts: [
123+
* getClientDataSetIdsCall({ chain: calibration, address: '0x...', offset: 0n, limit: 50n }),
124+
* getClientDataSetIdsCall({ chain: calibration, address: '0x...', offset: 50n, limit: 50n }),
125+
* ],
126+
* })
127+
*
128+
* console.log(results)
129+
* ```
130+
*/
131+
export function getClientDataSetIdsCall(options: getClientDataSetIdsCall.OptionsType) {
132+
const chain = asChain(options.chain)
133+
return {
134+
abi: chain.contracts.fwssView.abi,
135+
address: options.contractAddress ?? chain.contracts.fwssView.address,
136+
functionName: 'clientDataSets',
137+
args: [options.address, options.offset ?? 0n, options.limit ?? 0n],
138+
} satisfies getClientDataSetIdsCall.OutputType
139+
}

0 commit comments

Comments
 (0)