Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions packages/synapse-core/src/sp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,48 @@ export async function deletePiece(options: deletePiece.OptionsType): Promise<del
return response.result
}

export namespace deletePieces {
export type OptionsType = {
endpoint: string
dataSetId: bigint
pieceIds: bigint[]
extraData: Hex
}
export type ReturnType = {
txHash: Hex
}
export type ErrorType = DeletePieceError | TimeoutError | NetworkError | AbortError
}

/**
* Delete multiple pieces from a data set on the PDP API.
*
* POST /pdp/data-sets/{dataSetId}/pieces/removals
*
* @param options - {@link deletePieces.OptionsType}
* @returns Hash of the delete operation {@link deletePieces.ReturnType}
* @throws Errors {@link deletePieces.ErrorType}
*/
export async function deletePieces(options: deletePieces.OptionsType): Promise<deletePieces.ReturnType> {
const { endpoint, dataSetId, pieceIds, extraData } = options
const response = await request.json.post<deletePieces.ReturnType>(
new URL(`pdp/data-sets/${dataSetId}/pieces/removals`, endpoint),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think curio has this endpoint yet. If you are working on that too, please link your PR. It should target the pdpv0 branch.

{
body: { pieceIds: pieceIds.map((id) => id.toString()), extraData },
timeout: TIMEOUT,
}
)

if (response.error) {
if (HttpError.is(response.error)) {
throw new DeletePieceError(await response.error.response.text())
}
throw response.error
}

return response.result
}

/**
* Ping the PDP API.
*
Expand Down
34 changes: 34 additions & 0 deletions packages/synapse-core/src/warm-storage/pieces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,40 @@ export async function waitForDeletePieceStatus(
return receipt
}

export type DeletePiecesOptions = {
pieceIds: bigint[]
dataSetId: bigint
clientDataSetId: bigint
endpoint: string
}

/**
* Delete multiple pieces from a data set
*
* Call the Service Provider API to delete the pieces.
*
* @param client - The client to use to delete the pieces.
* @param options - The options for the delete pieces.
* @param options.dataSetId - The ID of the data set.
* @param options.clientDataSetId - The ID of the client data set.
* @param options.pieceIds - The IDs of the pieces.
* @param options.endpoint - The endpoint of the PDP API.
* @returns The transaction hashes of the delete operations.
*/
export async function deletePieces(client: Client<Transport, Chain, Account>, options: DeletePiecesOptions) {
const extraData = await signSchedulePieceRemovals(client, {
clientDataSetId: options.clientDataSetId,
pieceIds: options.pieceIds,
})

return PDP.deletePieces({
endpoint: options.endpoint,
dataSetId: options.dataSetId,
pieceIds: options.pieceIds,
extraData,
})
}

export type GetPiecesOptions = {
dataSet: DataSet
address: Address
Expand Down
35 changes: 35 additions & 0 deletions packages/synapse-core/test/sp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,41 @@ InvalidSignature(address expected, address actual)
})
})

describe('deletePieces', () => {
it('should handle successful batch delete', async () => {
const mockTxHash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
const mockResponse = {
txHash: mockTxHash,
}

server.use(
http.post('http://pdp.local/pdp/data-sets/1/pieces/removals', async ({ request }) => {
const body = (await request.json()) as { pieceIds: string[]; extraData: string }
assert.hasAllKeys(body, ['pieceIds', 'extraData'])
assert.deepStrictEqual(body.pieceIds, ['2', '3'])
assert.isDefined(body.extraData)
return HttpResponse.json(mockResponse, {
status: 200,
})
})
)

const extraData = await TypedData.signSchedulePieceRemovals(client, {
clientDataSetId: 0n,
pieceIds: [2n, 3n],
})

const result = await SP.deletePieces({
endpoint: 'http://pdp.local',
dataSetId: 1n,
pieceIds: [2n, 3n],
extraData,
})

assert.strictEqual(result.txHash, mockTxHash)
})
})

describe('findPiece', () => {
const mockPieceCidStr = 'bafkzcibcd4bdomn3tgwgrh3g532zopskstnbrd2n3sxfqbze7rxt7vqn7veigmy'

Expand Down
1 change: 1 addition & 0 deletions packages/synapse-react/src/warm-storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './use-create-data-set.ts'
export * from './use-data-sets.ts'
export * from './use-delete-piece.ts'
export * from './use-delete-pieces.ts'
export * from './use-providers.ts'
export * from './use-service-price.ts'
export * from './use-upload.ts'
65 changes: 65 additions & 0 deletions packages/synapse-react/src/warm-storage/use-delete-pieces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { getChain } from '@filoz/synapse-core/chains'
import type { SessionKey } from '@filoz/synapse-core/session-key'
import { type DataSet, deletePieces, waitForDeletePieceStatus } from '@filoz/synapse-core/warm-storage'
import { type MutateOptions, useMutation, useQueryClient } from '@tanstack/react-query'
import type { TransactionReceipt } from 'viem'
import { useAccount, useChainId, useConfig } from 'wagmi'
import { getConnectorClient } from 'wagmi/actions'

export interface UseDeletePiecesProps {
/**
* The callback to call when the hash is available.
*/
onHash?: (hash: string) => void
sessionKey?: SessionKey
mutation?: Omit<MutateOptions<TransactionReceipt, Error, UseDeletePiecesVariables>, 'mutationFn'>
}

export interface UseDeletePiecesVariables {
dataSet: DataSet
pieceIds: bigint[]
}

/**
* Hook to delete multiple pieces from a data set.
*
* @param props - {@link UseDeletePiecesProps}
* @returns
*/
export function useDeletePieces(props: UseDeletePiecesProps) {
const config = useConfig()
const chainId = useChainId({ config })
const chain = getChain(chainId)
const account = useAccount({ config })
const queryClient = useQueryClient()
const client = config.getClient()

return useMutation({
...props?.mutation,
mutationFn: async ({ dataSet, pieceIds }: UseDeletePiecesVariables) => {
let connectorClient = await getConnectorClient(config, {
account: account.address,
chainId,
})

if (props?.sessionKey && (await props?.sessionKey.isValid(connectorClient, 'SchedulePieceRemovals'))) {
connectorClient = props?.sessionKey.client(chain, client.transport)
}

const deletePiecesRsp = await deletePieces(connectorClient, {
endpoint: dataSet.pdp.serviceURL,
dataSetId: dataSet.dataSetId,
clientDataSetId: dataSet.clientDataSetId,
pieceIds,
})

props?.onHash?.(deletePiecesRsp.txHash)
const rsp = await waitForDeletePieceStatus(client, deletePiecesRsp)

queryClient.invalidateQueries({
queryKey: ['synapse-warm-storage-data-sets', account.address],
})
return rsp
},
})
}
1 change: 1 addition & 0 deletions packages/synapse-sdk/src/pdp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
export type {
AddPiecesResponse,
CreateDataSetResponse,
DeletePiecesResponse,
UploadPieceOptions,
} from './server.ts'
export { PDPServer } from './server.ts'
Expand Down
31 changes: 31 additions & 0 deletions packages/synapse-sdk/src/pdp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
addPieces,
createDataSet,
createDataSetAndAddPieces,
deletePieces,
type PieceInputWithMetadata,
} from '@filoz/synapse-core/warm-storage'
import type { Account, Address, Chain, Client, Transport } from 'viem'
Expand Down Expand Up @@ -60,6 +61,16 @@ export interface AddPiecesResponse {
statusUrl: string
}

/**
* Response from deleting pieces from a data set
*/
export interface DeletePiecesResponse {
/** Success message from the server */
message: string
/** Transaction hash for the piece removal */
txHash: string
}

/**
* Options for uploading a piece
*/
Expand Down Expand Up @@ -251,4 +262,24 @@ export class PDPServer {
nextChallengeEpoch: data.nextChallengeEpoch,
}
}

/**
* Delete multiple pieces from a data set
* @param dataSetId - The ID of the data set
* @param clientDataSetId - The client's dataset ID used when creating the data set
* @param pieceIds - Array of piece IDs to delete
* @returns Promise that resolves with transaction hash
*/
async deletePieces(dataSetId: bigint, clientDataSetId: bigint, pieceIds: bigint[]): Promise<DeletePiecesResponse> {
const { txHash } = await deletePieces(this._client, {
pieceIds,
dataSetId,
clientDataSetId,
endpoint: this._endpoint,
})
return {
message: `${pieceIds.length} pieces removed from data set ID ${dataSetId} successfully`,
txHash,
}
}
}
Loading