Skip to content

Commit

Permalink
fix!: update aggregate spec in client and api (#824)
Browse files Browse the repository at this point in the history
Updates client and api based on
storacha/specs@63846e5

It also starts relying on the
https://github.com/web3-storage/data-segment/ lib for the tests by
generating commP of randomly generated CARs. In next iteration, tests
should also include commP of commPs builder (needs
storacha/data-segment#8)

Client API for submitting offer was changed to receive piece instead of
computing it. Main reason for this is that there is a need to build it
outside while keeping track of sizes. It could also happen here and
explode if not, even though this is an aggregate offer call and not
really the builder. So I would love feedback on API surface preferences.
This will not be used by end users as will be abstracted within our
services. The API will still need to validate if given commP of commPs
is good for the given offer.

BREAKING CHANGE: aggregate capabilities now have different nb properties
and aggregate client api was simplified
  • Loading branch information
vasco-santos authored Jul 6, 2023
1 parent 59dc765 commit ebefd88
Show file tree
Hide file tree
Showing 20 changed files with 1,092 additions and 1,070 deletions.
3 changes: 2 additions & 1 deletion packages/aggregate-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
"@ucanto/interface": "^8.0.0",
"@ucanto/server": "^8.0.0",
"@ucanto/transport": "^8.0.0",
"@web3-storage/capabilities": "workspace:^"
"@web3-storage/capabilities": "workspace:^",
"@web3-storage/data-segment": "^1.0.1"
},
"devDependencies": {
"@ipld/car": "^5.1.1",
Expand Down
6 changes: 3 additions & 3 deletions packages/aggregate-api/src/aggregate/get.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ export const provide = (context) =>
* @returns {Promise<API.UcantoInterface.Result<API.AggregateGetSuccess, API.AggregateGetFailure>>}
*/
export const claim = async ({ capability }, { aggregateStore }) => {
const commitmentProof = capability.nb.commitmentProof
const subject = capability.nb.subject

const aggregateArrangedResult = await aggregateStore.get(commitmentProof)
const aggregateArrangedResult = await aggregateStore.get(subject)
if (!aggregateArrangedResult) {
return {
error: new AggregateNotFound(
`aggregate not found for commitment proof: ${commitmentProof}`
`aggregate not found for subject: ${subject}`
),
}
}
Expand Down
43 changes: 11 additions & 32 deletions packages/aggregate-api/src/aggregate/offer.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export const claim = async (
) => {
// Get offer block
const offerCid = capability.nb.offer
const commitmentProof = capability.nb.commitmentProof
const offers = getOfferBlock(offerCid, invocation)
const piece = capability.nb.piece
const offers = getOfferBlock(offerCid, invocation.iterateIPLDBlocks())

if (!offers) {
return {
Expand All @@ -52,30 +52,15 @@ export const claim = async (
`offer over size, offered: ${size}, maximum: ${MAX_SIZE}`
),
}
} else if (size !== capability.nb.size) {
} else if (size !== piece.size) {
return {
error: new AggregateOfferInvalidSizeError(
`offer size mismatch, specified: ${capability.nb.size}, actual: ${size}`
`offer size mismatch, specified: ${piece.size}, actual: ${size}`
),
}
}

// Validate URLs in offers src
for (const offer of offers.values()) {
for (const u of offer.src) {
try {
new URL(u)
} catch {
return {
error: new AggregateOfferInvalidUrlError(
`offer has invalid URL: ${u}`
),
}
}
}
}

// TODO: Validate commP
// TODO: Validate commP of commPs

// Create effect for receipt
const fx = await Offer.arrange
Expand All @@ -84,13 +69,13 @@ export const claim = async (
audience: context.id,
with: context.id.did(),
nb: {
commitmentProof,
pieceLink: piece.link,
},
})
.delegate()

// Write offer to store
await offerStore.queue({ commitmentProof, offers })
await offerStore.queue({ piece, offers })

return Server.ok({
status: 'queued',
Expand All @@ -99,13 +84,13 @@ export const claim = async (

/**
* @param {Server.API.Link<unknown, number, number, 0 | 1>} offerCid
* @param {Server.API.Invocation<Server.API.Capability<"aggregate/offer", `did:${string}:${string}` & `did:${string}` & Server.API.Phantom<{ protocol: "did:"; }> & `${string}:${string}` & Server.API.Phantom<{ protocol: `${string}:`; }>, Pick<{ offer: Server.API.Link<unknown, number, number, 0 | 1>; commitmentProof: Server.API.Link<unknown, number, number, 0 | 1>; size: number & Server.API.Phantom<{ typeof: "integer"; }>; }, "offer" | "commitmentProof" | "size"> & Partial<Pick<{ offer: Server.API.Link<unknown, number, number, 0 | 1>; commitmentProof: Server.API.Link<unknown, number, number, 0 | 1>; size: number & Server.API.Phantom<{ typeof: "integer"; }>; }, never>>>>} invocation
* @param {IterableIterator<Server.API.Transport.Block<unknown, number, number, 1>>} blockIterator
*/
function getOfferBlock(offerCid, invocation) {
for (const block of invocation.iterateIPLDBlocks()) {
function getOfferBlock(offerCid, blockIterator) {
for (const block of blockIterator) {
if (block.cid.equals(offerCid)) {
const decoded =
/** @type {import('@web3-storage/aggregate-client/types').Offer[]} */ (
/** @type {import('@web3-storage/aggregate-client/types').Piece[]} */ (
CBOR.decode(block.bytes)
)
return decoded
Expand All @@ -114,12 +99,6 @@ function getOfferBlock(offerCid, invocation) {
}
}

class AggregateOfferInvalidUrlError extends Server.Failure {
get name() {
return /** @type {const} */ ('AggregateOfferInvalidUrl')
}
}

class AggregateOfferInvalidSizeError extends Server.Failure {
get name() {
return /** @type {const} */ ('AggregateOfferInvalidSize')
Expand Down
6 changes: 3 additions & 3 deletions packages/aggregate-api/src/offer/arrange.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export const provide = (context) =>
* @returns {Promise<API.UcantoInterface.Result<API.OfferArrangeSuccess, API.OfferArrangeFailure>>}
*/
export const claim = async ({ capability }, { arrangedOfferStore }) => {
const commitmentProof = capability.nb.commitmentProof
const pieceLink = capability.nb.pieceLink

const status = await arrangedOfferStore.get(commitmentProof)
const status = await arrangedOfferStore.get(pieceLink)

if (!status) {
return {
error: new OfferArrangeNotFound(
`arranged offer not found for commitment proof: ${commitmentProof}`
`arranged offer not found for piece: ${pieceLink}`
),
}
}
Expand Down
12 changes: 6 additions & 6 deletions packages/aggregate-api/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
} from '@ucanto/interface'
import type { ProviderInput } from '@ucanto/server'

import type { Offer } from '@web3-storage/aggregate-client/types'
import type { Piece } from '@web3-storage/aggregate-client/types'
export * from '@web3-storage/aggregate-client/types'

export * from '@web3-storage/capabilities/types'
Expand All @@ -31,7 +31,7 @@ export interface ServiceContext

export interface ArrangedOfferStore {
get: (
commitmentProof: Link<unknown, number, number, 0 | 1>
pieceLink: Link<unknown, number, number, 0 | 1>
) => Promise<string | undefined>
}

Expand All @@ -40,13 +40,13 @@ export interface OfferStore {
}

export interface OfferToQueue {
commitmentProof: Link<unknown, number, number, 0 | 1>
offers: Offer[]
piece: Piece
offers: Piece[]
}

export interface AggregateStore {
get: (
commitmentProof: Link<unknown, number, number, 0 | 1>
pieceLink: Link<unknown, number, number, 0 | 1>
) => Promise<unknown[] | undefined>
}

Expand Down Expand Up @@ -76,7 +76,7 @@ export interface Assert {

export interface AggregateStoreBackend {
put: (
commitmentProof: Link<unknown, number, number, 0 | 1>,
pieceLink: Link<unknown, number, number, 0 | 1>,
aggregateInfo: unknown
) => Promise<void>
}
Expand Down
Loading

0 comments on commit ebefd88

Please sign in to comment.