Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: w3 aggregation #51

Merged
merged 31 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
60b1a2b
feat: filecoin spec
vasco-santos Mar 1, 2023
898f2eb
fix: new iteration with receipts and aggregate
vasco-santos Mar 27, 2023
1c76c38
chore: apply suggestions from code review
vasco-santos Mar 28, 2023
3e624b7
chore: move bits around per other suggestion
vasco-santos Mar 28, 2023
7248631
chore: apply suggestions from code review for deal out
vasco-santos Mar 28, 2023
8286f15
chore: restructure per feedback
vasco-santos Mar 28, 2023
d5cb712
fix: spell issues
vasco-santos Mar 28, 2023
1de9b86
chore: apply suggestions from code review
vasco-santos Mar 28, 2023
58026c5
chore: address review comments
vasco-santos Mar 28, 2023
dae9ff4
chore: add receipt for aggregate get
vasco-santos Mar 28, 2023
91e9280
chore: rephrrase dequeue
vasco-santos Mar 28, 2023
7695dc0
fix: drop commp of aggregate
vasco-santos Mar 31, 2023
965ceed
fix: use single dag cbor block with info of cars to add to aggregate …
vasco-santos Mar 31, 2023
49daef5
chore: apply suggestions from code review
vasco-santos Apr 11, 2023
208e831
chore: apply suggestions from code review with schema
vasco-santos Apr 11, 2023
0213450
chore: apply suggestions from code review
vasco-santos Apr 11, 2023
c7016e0
chore: address review comments
vasco-santos Apr 11, 2023
d4e8912
chore: appease lint
vasco-santos Apr 11, 2023
904e2d3
chore: rename review to arrange
vasco-santos Apr 11, 2023
7dee532
chore: close code block
Gozala Apr 12, 2023
5a50385
chore: rename some of aggregate mentions to offer for better clarity
vasco-santos Apr 12, 2023
49f5704
chore: add other feedback
vasco-santos Apr 12, 2023
ec12c09
chore: add link to offer arrange from aggregate offer
vasco-santos Apr 12, 2023
4adee82
chore: other renames from car to cbor
vasco-santos Apr 13, 2023
9b80833
fix: add cbor block in invocation CAR file to avoid io to execute cap…
vasco-santos Apr 14, 2023
0d2f464
fix: spell issues
vasco-santos Apr 14, 2023
babefc0
chore: new iteration based on thing discussions
vasco-santos Apr 21, 2023
555d647
fix: spell issues
vasco-santos Apr 21, 2023
c2169a4
chore: apply suggestions from code review
vasco-santos May 4, 2023
055603e
chore: make src optional
vasco-santos May 4, 2023
8c561b0
chore: apply suggestions from code review
vasco-santos May 10, 2023
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
7 changes: 7 additions & 0 deletions .github/workflows/words-to-ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,10 @@ flowAuthorityPrincipal
capabilitiesVerifierComponent
Verifier
sudo
Filecoin
Storefront
capabilty
commPs
dag-cbor
NameDescriptionStorefrontPrincipal
w3upAuthorityPrincipal
380 changes: 380 additions & 0 deletions w3-aggregation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,380 @@
# CAR Aggregation Protocol

![status:wip](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square)

## Editors

- [Vasco Santos], [Protocol Labs]
- [Irakli Gozalishvili], [Protocol Labs]
- [Alan Shaw], [Protocol Labs]

## Authors

- [Vasco Santos], [Protocol Labs]
- [Irakli Gozalishvili], [Protocol Labs]
- [Alan Shaw], [Protocol Labs]

# Abstract

This spec describes a [UCAN] protocol allowing an implementer to receive an aggregate of CAR files for inclusion in a Filecoin deal.

## Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119](https://datatracker.ietf.org/doc/html/rfc2119).

# Terminology

## Roles

There are several roles in the authorization flow:

| Name | Description |
| ----------- | ----------- |
| Storefront | [Principal] identified by [`did:web`] identifier, representing a storage aggregator like w3up |
| Authority | [Principal] that represents service provider that executes invoked capabilities |
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
| Verifier | Component of the [authority] that performs UCAN validation |

### Storefront

A _Storefront_ is a type of [principal] identified by a [`did:web`] identifier.

A Storefront facilitates data storage services to applications and users, getting the requested data stored into Filecoin deals asynchronously.

### Authority

_Authority_ is a [principal] that executes invoked capabilities.

### Verifier

A Component of the [authority] that performs UCAN validation

# Protocol

## Overview

A Storefront is the entry point for user/application data into web3. It will act on behalf of users to move data around into different storage points. One of the key storage presences may be Filecoin Storage Providers.

### Authorization

Broker MUST have an authorization mechanism for allowed Storefront principals (e.g. web3.storage). Either by out-of-bound exchange of information or through a well defined API. In other words, broker can authorize invocations from `did:web:web3.storage` by validating signature from did. This way, it allows web3.storage to rotate keys and/or re-delegate access without having to coordinate with the broker.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

### Storefront offers broker an aggregate

When a Storefront has enough content to fulfill an aggregate (each broker MAY have different requirements), a Filecoin deal for an aggregate MAY be requested by an `aggregate/offer` invocation. Deal negotiations with Filecoin Storage Providers SHOULD be handled out off band. Broker MUST acknowledge a request by issuing a signed receipt.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

```mermaid
sequenceDiagram
participant Storefront as 🌐<br/><br/>did:web:web3.storage
participant Authority as 🌐<br/><br/>did:web:spade.storage

Storefront->>Authority: invoke `aggregate/offer`
Note left of Authority: Request offer to be queued
Authority-->>Storefront: receipt issued
```

### Broker queues the offer
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

Once broker successfully gets an offer, the offer gets queued for review. A receipt is created to proof the transition of `aggregate/offer` state from `null` into `queued`. It is worth mentioning that if an offer is from an aggregate that is already `queued` or `complete` it is ignored.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

This receipt MUST have link to a followup task (using `.fx.join` field) that either succeeds (if aggregate was accepted) or fails (if aggregated was determined to be invalid) so that it's receipt COULD be looked up using it.

> Note: Aggregator MAY have several intermediate steps and states it transitions though, however those intentionally are not captured by this protocol, because storefront will take no action until success / failure condition is met.

### Broker reviews and handles the offer

When a broker dequeues the offer from the queue, its details are retrieved from the provided source URL. With the offer details, the broker will interact with available Filecoin Storage Providers, in order to establish a previously determined (out of band) number of deals. Depending on storage providers availability, as well as the content present in the offer, the aggregate MAY be handled or not. A receipt is created to proof the transition of `aggregate/offer` state from `queued` into `accepted` or `denied`.

```mermaid
sequenceDiagram
participant Storefront as 🌐<br/><br/>did:web:web3.storage
participant Authority as 🌐<br/><br/>did:web:spade.storage

Note right of Storefront: Review and handle offer async
Authority-->>Storefront: receipt issued
```
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

Once offer gets into `accepted` state, broker takes care of renewing deals.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

### Storefront can query state of the aggregate deals

Storefront users MAY want to check details about deals from the content they previously stored. These deals will change over time as they get renewed. Therefore, Storefront should invoke `aggregate/get` capability to gather information about given aggregate identifier.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

```mermaid
sequenceDiagram
participant Storefront as 🌐<br/><br/>did:web:web3.storage
participant Authority as 🌐<br/><br/>did:web:spade.storage

Storefront->>Authority: invoke `aggregate/get`
```

## Capabilities

This section describes the capabilities that form the w3 aggregation protocol, along with the details relevant for invoking capabilities with a service provider.

In this document, we will be looking at `spade.storage` as an implementer of the `aggregate/*` and `offer/*` protocol.

### `aggregate/offer`

A Storefront principal can invoke a capabilty to submit an aggregate ready for offers.
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

```iplsch
type AggregateOffer union {
Aggregate "aggregate/offer"
} representation inline {
discriminantKey "can"
}

type Offer struct {
with StorefrontDID
offer { CARLink: OfferDetails }
}

type struct OfferDetails {
size Int
commP Bytes
src [URL]
}

type CARLink string
```

> `did:web:web3.storage` invokes capability from `did:web:spade.storage`

```json
{
"iss": "did:web:web3.storage",
"aud": "did:web:spade.storage",
Gozala marked this conversation as resolved.
Show resolved Hide resolved
"att": [{
"with": "did:web:web3.storage",
"can": "aggregate/offer",
"nb": {
"offer": {
"link": "bafy...aggregate",
"size": 110101,
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
"src": ["https://w3s.link/ipfs/bafy...aggregate"]
}
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
}
}],
"prf": [],
"sig": "..."
}
```

This capability is invoked to submit a request to a broker service when an aggregate is ready for a Filecoin deal. The `nb.offer.link` is the DAG-CBOR CID that refers to a "Ferry" aggregate. It encodes a dag-cbor block with an array of entries representing all the CAR files to include in the aggregate. Its format is:

```json
[
{
"link": "bafy...",
"size": 110101,
"commP": "commP...",
"src": ["https://.../bafy(...)"]
}
]
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

I was under impression that in the last call we decided we don't want to link to the CAR containing these entries but rather have offer field contain these entries inline instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, text above is changed to be a single block inline, but I forgot to change the JSON example here


A `src` with URLs to fetch the aggregate offer is provided. In addition, the total `size` of every CAR within it is provided, both for convenience and consistency with the dag-cbor blocks.

A receipt will be generated to acknowledge the received request. This receipt MUST contain an [effect](https://github.com/ucan-wg/invocation/#7-effect) with a subsequent task (`.fx.join` field) that is run when submitted aggregate is processed and either succeeds (implying that aggregate was accepted and deals will be arranged) or fail (with `error` describing a problem with an aggregate)
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"ran": "bafy...invocation",
"out": {
"ok": {
"status": "queued"
}
},
"fx": {
"join": { "/": "bafy...dequeue" }
},
"meta": {},
"iss": "did:web:spade.storage",
"prf": []
}
```

### `aggregate/get`

A Storefront principal can invoke a capability to get state of a previously accepted aggregate.

> `did:web:web3.storage` invokes capability from `did:web:spade.storage`

```json
{
"iss": "did:web:web3.storage",
"aud": "did:web:spade.storage",
"att": [{
"with": "did:web:web3.storage",
"can": "aggregate/get",
"nb": {
"link": "bafy...aggregate",
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
}
}],
"prf": [],
"sig": "..."
}
```
Gozala marked this conversation as resolved.
Show resolved Hide resolved

Once this invocation is executed, a receipt is generated with the aggregate information:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we need to consider two things here:

  1. How does cashing affects this ? Ideally invocations are idempotent meaning same instruction should get same result (even if state has changed in the meantime) and nnc supposed to be utilized to cache miss. If we do not want to deal with caching we should specify additional field like current time and request that it be set to e.g. latest drand or a wall clock, that way out dated responses are less surprising, if you request state for old state that has not been computed prior you get an error saying it can not be computed, if we have it cached than response is for that time frame.

  2. We should specify what happens if you request deal info for the aggregate that is in queued state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think if aggregate is queued or done, we do not want to do a new one and it should just be ignored? Therefore, it would be idempotent

Copy link
Collaborator

Choose a reason for hiding this comment

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

That is reasonable, lets just add sentence to state that.


```json
{
"ran": "bafy...get",
"out": {
"ok": {
"deals": {
"111": {
"storageProvider": "f07...",
"status": "Active",
"pieceCid": "bag...",
"dataCid": "bafy...",
"dataModelSelector": "Links/...",
"activation": "2023-04-13T01:58:00+00:00",
"expiration": "2024-09-05T01:58:00+00:00",
"created": "2023-04-11T17:57:30.522198+00:00",
"updated": "2024-04-12T03:42:26.928993+00:00"
}
}
},
},
"fx": {
"fork": []
},
"meta": {},
"iss": "did:web:spade.storage",
"prf": []
}
```

### `offer/arrange`
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved

When a broker receives an `aggregate/offer` invocation from a Storefront Principal, an [Effect](https://github.com/ucan-wg/invocation/#7-effect) for this submission is created with join task to be performed asynchronously.
Gozala marked this conversation as resolved.
Show resolved Hide resolved

```json
{
"iss": "did:web:spade.storage",
"aud": "did:web:web3.storage",
"att": [{
"with": "did:web:spade.storage",
"can": "offer/arrange",
"nb": {
"link": "bafy...aggregate",
}
}],
"prf": [],
"sig": "..."
}
```

Once this invocation is executed, a receipt is generated with the status of the task updated. Accepted aggregate receipt will provide aggregate offer operation info:

```json
{
"ran": "bafy...arrange",
"out": {
"ok": {
"link": "bafy...aggregate"
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
}
},
"fx": {
"fork": []
},
"meta": {},
"iss": "did:web:spade.storage",
"prf": []
}
```

If offered aggregate is invalid, details on failing commPs are also reported:

```json
{
"ran": "bafy...invocation",
"out": {
"error": {
"link": "bafy...aggregate",
"cause": [{
vasco-santos marked this conversation as resolved.
Show resolved Hide resolved
"commP": "commP",
"reason": "reasonCode",
}],
},
},
"fx": {
"fork": []
},
"meta": {},
"iss": "did:web:spade.storage",
"prf": []
}
```

### Schema

```ipldsch
type Aggregate union {
| Link "queued"
| Link "status"
| Link "rejected"
} representation keyed

type AggregateCapability enum {
AggregateOffer "aggregate/offer"
AggregateGet "aggregate/get"
} representation inline {
discriminantKey "can"
}

type AggregateGet struct {
with StorefrontDID
nb SucceedAggregateRef
}

type SucceedAggregateRef struct {
link &AggregateCAR
}

type AggregateRef struct {
link &AggregateCAR
}

type AggregateOffer struct {
with StorefrontDID
nb AggregateOfferDetail
}

type AggregateOfferDetail struct {
offer: Offer
}

type Offer {
link &AggregateCAR
src [URL]
size number
}

type StorefrontDID string
type URL string
type AggregateCAR any
type OfferCapability union {
OfferArrange "offer/arrange"
} representation inline {
discriminantKey "can"
}

type OfferArrange struct {
with BrokerDID nb AggregateRef
}

type BrokerDID string
```

[`did:web`]: https://w3c-ccg.github.io/did-method-web/
[UCAN]: https://github.com/ucan-wg/spec/
[principal]: https://github.com/ucan-wg/spec/#321-principals
[authority]:#authority

[Protocol Labs]:https://protocol.ai/
[Vasco Santos]:https://github.com/vasco-santos
[Irakli Gozalishvili]:https://github.com/Gozala
[Alan Shaw]:https://github.com/alanshaw