From a82c1a6f8e2bbe36116651a322e6775f58e8e59d Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Fri, 5 Apr 2024 15:00:33 -0700 Subject: [PATCH 1/6] chore: save current draft --- w3-blob.md | 255 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 154 insertions(+), 101 deletions(-) diff --git a/w3-blob.md b/w3-blob.md index aae642f..de3113d 100644 --- a/w3-blob.md +++ b/w3-blob.md @@ -51,48 +51,66 @@ Authorized agent MAY invoke `/space/content/add/blob` capability on the [space] ### Add Blob Diagram -Following diagram illustrates execution workflow. +Following diagram illustrates execution flow. Alice invokes `/space/content/add/blob` command which produces receipt with three effects (`allocate`, `put`, `accept`) and awaited `claim`. Effects have dependencies and therefor predict execution flow (from left to right). The output of the main task awaits on the result of the result of the last effect. ```mermaid flowchart TB -Add("▢️ /space/content/add/blob πŸ‘©β€πŸ’» πŸ€–") +Add("⏯️ /space/content/add/blob πŸ‘©β€πŸ’» πŸ€–") +AddOk("🧾 { ok: { claim } }") -Added("🧾 { ok: { claim 🚦 } }") -Allocate("⏭️ /service/blob/allocate πŸ€–") +subgraph accept +Accept("⏯️ /service/blob/accept πŸ€–") +AcceptOk("🧾 { ok: { claim } }") +end -Put("⏭️ /http/put πŸ€–πŸ”‘") +subgraph put +Put("⏯️ /http/put πŸ”‘") +PutOk("🧾 { ok: {} }") +end -Accept("⏭️ /service/blob/accept πŸ€–") - -Accepted("🧾 { ok: { claim 🎫 } }") +subgraph allocate +Allocate("⏯️ /service/blob/allocate πŸ€–") +AllocateOk("🧾 { ok: { url headers } }") +end Claim("🎫 /assert/location πŸ€–πŸ‘©β€πŸ’»") -Add --o Added -Added -.-> Allocate -Added -.-> Accept -Added -.-> Put -Allocate --> Accept -Put --> Accept -Accept --o Accepted -Accepted -- claim --> Claim -Added -- claim --> Accept + +Add -.-> AddOk +AddOk -- ⏭️ --> allocate +AddOk -- ⏭️ --> put +AddOk -- ⏭️ --> accept +AddOk -- 🚦 out.ok.claim --> AcceptOk + + + +Allocate -.-> AllocateOk + +Put -- 🚦url --> AllocateOk +Put -- 🚦headers --> AllocateOk + +Put -.-> PutOk + + + +Accept -- 🚦_put --> PutOk +Accept -.-> AcceptOk +AcceptOk -- claim --> Claim ``` #### Iconography -- Icon on the left describes type of the node -- Icon on the right describes issuer / audience pair if only one audience is the issuer -- ▢️ Task +- ⏯️ Task - ⏭️ Next Task (a.k.a Effect) - 🧾 Receipt -- 🎫 Delegation / Commitment +- 🎫 Delegation - 🚦 Await - πŸ‘©β€πŸ’» Alice - πŸ€– Service +- πŸ”‘ Derived Principal ### Add Blob Invocation Example @@ -105,9 +123,9 @@ Shown Invocation example illustrates Alice requesting to add 2MiB blob to her sp "iss": "did:key:zAlice", "aud": "did:web:web3.storage", "args": { - "blob": { + "site": { // multihash of the blob as byte array - "content": { "/": { "bytes": "mEi...sfKg" } }, + "digest": { "/": { "bytes": "mEi...sfKg" } }, // size of the blob in bytes "size": 2_097_152, } @@ -122,74 +140,102 @@ Shows an example receipt for the above `/space/content/add/blob` capability invo > ℹ️ We use `// "/": "bafy..` comments to denote CID of the parent object. ```js -{ // "/": "bafy..add", +{ // "/": "bafy..work", "iss": "did:web:web3.storage", "aud": "did:key:zAlice", - "cmd": "/ucan/assert/result" + "cmd": "/ucan/assert", "sub": "did:web:web3.storage", "args": { - // refers to the invocation from the example - "ran": { "/": "bafy..add" }, - "out": { - "ok": { - // result of the add is the content (location) claim - // that is produced as result of "bafy..accept" - "claim": { "await/ok": { "/": "bafy...accept" } } - } - }, - // Previously `next` was known as `fx` instead, which is - // set of tasks to be scheduled. - "next": [ - // 1. System attempts to allocate memory in user space for the blob. - { // "/": "bafy...alloc", - "cmd": "/service/blob/allocate", - "sub": "did:web:web3.storage", - "args": { - // space where memory is allocated - "space": "did:key:zAlice", - "blob": { - // multihash of the blob as byte array - "content": { "/": { "bytes": "mEi...sfKg" } }, - // size of the blob in bytes - "size": 2_097_152, + "assert": [ + // refers to the invocation from the example + { "/": "bafy..add" }, + // refers to the receipt corresponding to the above invocation + { + "out": { + "ok": { + // result of the add is the content (location) claim + // that is produced as result of "bafy..accept" + "blob": { + "ucan/await": [ + ".out.ok.blob", + { "/": "bafy...accept" } + ] + } } - } - }, - // 2. System requests user agent (or anyone really) to upload the content - // corresponding to the blob - // via HTTP PUT to given location. - { // "/": "bafy...put", - "cmd": "/http/put", - "sub": "did:key:zMh...der", // <-- Ed299.. derived key from content multihash - "args": { - "content": { "/": { "bytes": "mEi...sfKg" } }, - "address": { "await/ok": { "/": "bafy...alloc" } }, - "_allocate": { "await/ok": { "/": "bafy...alloc" } } }, - "meta": { - // archive of the principal keys - "keys": { - "did:key:zMh...der": { "/": "mEi...sfKg" } - } - } - }, - // 3. System will attempt to accept uploaded content that matches blob - // multihash and size. - { // "/": "bafy...accept", - "cmd": "/service/blob/accept", - "sub": "did:web:web3.storage", - "args": { - "space": "did:key:zAlice", - "blob": { - // multihash of the blob as byte array - "content": { "/": { "bytes": "mEi...sfKg" } }, - "size": 2_097_152, + // Previously `next` was known as `fx` instead, which is + // set of tasks to be scheduled. + "next": [ + // 1. System attempts to allocate memory in user space for the blob. + { // "/": "bafy...alloc", + "cmd": "/service/blob/allocate", + "sub": "did:web:web3.storage", + "args": { + // space where memory is allocated + "space": "did:key:zAlice", + "blob": { + // multihash of the blob as byte array + "digest": { "/": { "bytes": "mEi...sfKg" } }, + // size of the blob in bytes + "size": 2_097_152, + }, + // task that caused this invocation + "cause": { "/": "bafy..add" } + } }, - exp: 1711122994101, - // This task is blocked on allocation - _allocate: { "await/ok": { "/": "bafy...alloc" } }, - _put: { "await/ok", { "/": "bafy...put" } } - } + // 2. System requests user agent (or anyone really) to upload the content + // corresponding to the blob + // via HTTP PUT to given location. + { // "/": "bafy...put", + "cmd": "/http/put", + "sub": "did:key:zMh...der", // <-- Ed299.. derived key from content multihash + "args": { + // pipe url from the allocation result + "url": { + "ucan/await": [ + ".out.ok.address.url", + { "/": "bafy...alloc" } + ] + }, + // pipe headers from the allocation result + "headers": { + "ucan/await": [ + ".out.ok.address.headers", + { "/": "bafy...alloc" } + ] + }, + // body of the http request + "body": { + // multihash of the blob as byte array + "digest": { "/": { "bytes": "mEi...sfKg" } }, + "size": 2_097_152 + }, + }, + "meta": { + // archive of the principal keys + "keys": { + "did:key:zMh...der": { "/": "mEi...sfKg" } + } + } + }, + // 3. System will attempt to accept uploaded content that matches blob + // multihash and size. + { // "/": "bafy...accept", + "cmd": "/service/blob/accept", + "sub": "did:web:web3.storage", + "args": { + "space": "did:key:zAlice", + "blob": { + // multihash of the blob as byte array + "content": { "/": { "bytes": "mEi...sfKg" } }, + "size": 2_097_152, + }, + "exp": 1711122994101, + // This task is blocked on allocation + "_put": { "ucan/await": [".out.ok", { "/": "bafy...put" }] } + } + } + ] } ] } @@ -210,17 +256,17 @@ type AddBlob = { } type Blob = { - content: Multihash - size: int + digest: Multihash + size: int } type Multihash = bytes type SpaceDID = string ``` -#### Blob Content +#### Blob Digest -The `args.blob.content` field MUST be a [multihash] digest of the blob payload bytes. Implementation SHOULD support SHA2-256 algorithm. Implementation MAY in addition support other hashing algorithms. +The `args.blob.digest` field MUST be a [multihash] digest of the blob payload bytes. Implementation SHOULD support SHA2-256 algorithm. Implementation MAY in addition support other hashing algorithms. #### Blob Size @@ -243,8 +289,8 @@ type AddBlobReceipt = { } type AddBlobOk = { - claim: { - "await/ok": Link + site: { + "ucan/await": [".out.ok.site", Link] } } @@ -259,12 +305,12 @@ Invocation MUST fail if any of the following is true 1. Provided **sub**ject space is not provisioned with a provider. 1. Provided `blob.size` is outside of supported range. -1. Provided `blob.content` is not a valid [multihash]. -1. Provided `blob.content` [multihash] hashing algorithm is not supported. +1. Provided `blob.digest` is not a valid [multihash]. +1. Provided `blob.digest` [multihash] hashing algorithm is not supported. -Invocation MUST succeed if non of the above is true. Success value MUST be an object with a `claim` field set to [await/ok] of the task that produces [location claim]. +Invocation MUST succeed if non of the above is true. Success value MUST be an object with a `site` field set to [ucan/await] of the task that produces [location commitment]. -Task linked from the `claim` of the success value MUST be present in the receipt effects _(`next` field)_. +Task linked from the `site` of the success value MUST be present in the receipt effects _(`next` field)_. #### Add Blob Effects @@ -304,7 +350,7 @@ The `args.blob` field MUST be set to the `Blob` the space is allocated for. #### Allocation Cause -The `args.cause` field MUST be set to the [Link] for an [Add Blob] task, that caused an allocation. +The `args.cause` field MUST be set to the [Link] for the [Add Blob] task, that caused an allocation. ### Allocate Blob Receipt @@ -380,15 +426,23 @@ type BlobPut = { ### Put Blob Subject -The subject field SHOULD be [`did:key`] corresponding to the [Ed25519] private key that is first 32 bytes of the blob [multihash]. +The subject field SHOULD be [`did:key`] corresponding to the [Ed25519] private key that is last 32 bytes of the blob [multihash]. ### Put Blob Metadata -Metadata MUST contain `keys` field with an object value that contains [`did:key`] subject as key and corresponding private key as bytes as a value. +Metadata MUST contain `keys` field with an object value that contains [`did:key`] subject as key and corresponding private key bytes as a value. + +### Put Blob URL + +Destination `url` MUST be specified in the arguments and it MUST be an endpoint that can accept HTTP PUT request. + +### Put Blob Headers + +The `headers` map MUST be specified in the arguments. It MUST have string keys corresponding to header names and string values corresponding to header values. -### Put Blob Address +### Put Blob Body -Destination address `url` and required `headers` MUST be specified in the arguments. +The `body` argument MUST be an object with `digest` and `size` fields describing the content of the request body. ### Put Blob Receipt @@ -418,7 +472,7 @@ Receipt MUST not have any effects. ## Accept Blob -Authorized agent MAY invoke `/service/blob/accept` capability on the [provider] subject. Invocation MUST either succeed when content is delivered on allocated `address` or fail if either allocation failed or expired before content was delivered. +Authorized agent MAY invoke `/service/blob/accept` capability on the [provider] subject. Invocation MUST either succeed when content is delivered to an allocated `address` or fail if either allocation failed or expired before content was delivered. Invocation MUST block until content is delivered. Implementation MAY resume when content is sent to the allocated address or await until client signals that content has been delivered using [put blob receipt]. @@ -520,7 +574,6 @@ Blob can be published by authorizing read interface (e.g. IPFS gateway) by deleg [multihash]:https://github.com/multiformats/multihash [space]:#space [IPNI]:https://github.com/ipni/specs/blob/main/IPNI.md -[await/ok]:https://github.com/ucan-wg/invocation?tab=readme-ov-file#await [location claim]:#location-claim [Add Blob]:#add-blob [Put Blob]:#put-blob From 9b70fdc80aa23b0c2295c691f190ba3e0cf904d0 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Mon, 8 Apr 2024 15:29:26 -0700 Subject: [PATCH 2/6] chore: ignore ucan --- .github/workflows/words-to-ignore.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/words-to-ignore.txt b/.github/workflows/words-to-ignore.txt index c097d81..f4eb67b 100644 --- a/.github/workflows/words-to-ignore.txt +++ b/.github/workflows/words-to-ignore.txt @@ -8,6 +8,7 @@ JWT-encoded Pre-Draft TTL UCAN +ucan UCAN's UCANs Zelenka From d7fac89ca896ff44c9394229a8a194a51071e79c Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Mon, 8 Apr 2024 15:30:52 -0700 Subject: [PATCH 3/6] Update w3-blob.md --- w3-blob.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/w3-blob.md b/w3-blob.md index de3113d..7ed2b90 100644 --- a/w3-blob.md +++ b/w3-blob.md @@ -123,7 +123,7 @@ Shown Invocation example illustrates Alice requesting to add 2MiB blob to her sp "iss": "did:key:zAlice", "aud": "did:web:web3.storage", "args": { - "site": { + "blob": { // multihash of the blob as byte array "digest": { "/": { "bytes": "mEi...sfKg" } }, // size of the blob in bytes From f53502e198de12717a28dc7b9177e9e95fdc27c8 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 9 Apr 2024 11:46:41 -0700 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Vasco Santos --- w3-blob.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/w3-blob.md b/w3-blob.md index 7ed2b90..2e0beec 100644 --- a/w3-blob.md +++ b/w3-blob.md @@ -56,12 +56,12 @@ Following diagram illustrates execution flow. Alice invokes `/space/content/add/ ```mermaid flowchart TB Add("⏯️ /space/content/add/blob πŸ‘©β€πŸ’» πŸ€–") -AddOk("🧾 { ok: { claim } }") +AddOk("🧾 { ok: { site } }") subgraph accept Accept("⏯️ /service/blob/accept πŸ€–") -AcceptOk("🧾 { ok: { claim } }") +AcceptOk("🧾 { ok: { site } }") end subgraph put @@ -155,9 +155,9 @@ Shows an example receipt for the above `/space/content/add/blob` capability invo "ok": { // result of the add is the content (location) claim // that is produced as result of "bafy..accept" - "blob": { + "site": { "ucan/await": [ - ".out.ok.blob", + ".out.ok.site", { "/": "bafy...accept" } ] } @@ -472,7 +472,7 @@ Receipt MUST not have any effects. ## Accept Blob -Authorized agent MAY invoke `/service/blob/accept` capability on the [provider] subject. Invocation MUST either succeed when content is delivered to an allocated `address` or fail if either allocation failed or expired before content was delivered. +Authorized agent MAY invoke `/service/blob/accept` capability on the [provider] subject. Invocation MUST either succeed when content is delivered at allocated site or fail if either allocation failed or expired before content was delivered. Invocation MUST block until content is delivered. Implementation MAY resume when content is sent to the allocated address or await until client signals that content has been delivered using [put blob receipt]. From a6c6cbc6370bb1bea3836313cf569c872ac35b2c Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 11 Apr 2024 23:17:23 -0700 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Alan Shaw --- w3-blob.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/w3-blob.md b/w3-blob.md index 2e0beec..061725f 100644 --- a/w3-blob.md +++ b/w3-blob.md @@ -51,7 +51,7 @@ Authorized agent MAY invoke `/space/content/add/blob` capability on the [space] ### Add Blob Diagram -Following diagram illustrates execution flow. Alice invokes `/space/content/add/blob` command which produces receipt with three effects (`allocate`, `put`, `accept`) and awaited `claim`. Effects have dependencies and therefor predict execution flow (from left to right). The output of the main task awaits on the result of the result of the last effect. +Following diagram illustrates execution flow. Alice invokes `/space/content/add/blob` command which produces a receipt with three effects (`allocate`, `put`, `accept`) and awaited `claim`. Effects have dependencies and therefore predict execution flow (from left to right). The output of the main task awaits on the result of the last effect. ```mermaid flowchart TB @@ -75,7 +75,7 @@ Allocate("⏯️ /service/blob/allocate πŸ€–") AllocateOk("🧾 { ok: { url headers } }") end -Claim("🎫 /assert/location πŸ€–πŸ‘©β€πŸ’»") +Site("🎫 /assert/location πŸ€–πŸ‘©β€πŸ’»") @@ -83,7 +83,7 @@ Add -.-> AddOk AddOk -- ⏭️ --> allocate AddOk -- ⏭️ --> put AddOk -- ⏭️ --> accept -AddOk -- 🚦 out.ok.claim --> AcceptOk +AddOk -- 🚦 out.ok.site --> AcceptOk @@ -98,7 +98,7 @@ Put -.-> PutOk Accept -- 🚦_put --> PutOk Accept -.-> AcceptOk -AcceptOk -- claim --> Claim +AcceptOk -- site --> Site ``` #### Iconography From ee5344d1cf2bec14ff0f9abd9e235810bb639283 Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Thu, 11 Apr 2024 23:39:14 -0700 Subject: [PATCH 6/6] Update w3-blob.md --- w3-blob.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/w3-blob.md b/w3-blob.md index 061725f..426ddbb 100644 --- a/w3-blob.md +++ b/w3-blob.md @@ -51,7 +51,7 @@ Authorized agent MAY invoke `/space/content/add/blob` capability on the [space] ### Add Blob Diagram -Following diagram illustrates execution flow. Alice invokes `/space/content/add/blob` command which produces a receipt with three effects (`allocate`, `put`, `accept`) and awaited `claim`. Effects have dependencies and therefore predict execution flow (from left to right). The output of the main task awaits on the result of the last effect. +Following diagram illustrates execution flow. Alice invokes `/space/content/add/blob` command which produces a receipt with three effects (`allocate`, `put`, `accept`) and awaited `site` commitment. Effects have dependencies and therefore predict execution flow (from left to right). The output of the main task awaits on the result of the last effect. ```mermaid flowchart TB @@ -117,7 +117,7 @@ AcceptOk -- site --> Site Shown Invocation example illustrates Alice requesting to add 2MiB blob to her space. ```js -{ +{ // "/": "bafy..add" "cmd": "/space/content/add/blob", "sub": "did:key:zAlice", "iss": "did:key:zAlice", @@ -153,7 +153,7 @@ Shows an example receipt for the above `/space/content/add/blob` capability invo { "out": { "ok": { - // result of the add is the content (location) claim + // result of the add is the content (location) commitment // that is produced as result of "bafy..accept" "site": { "ucan/await": [ @@ -230,7 +230,7 @@ Shows an example receipt for the above `/space/content/add/blob` capability invo "content": { "/": { "bytes": "mEi...sfKg" } }, "size": 2_097_152, }, - "exp": 1711122994101, + "expires": 1712903125, // This task is blocked on allocation "_put": { "ucan/await": [".out.ok", { "/": "bafy...put" }] } } @@ -373,6 +373,8 @@ type BlobAllocateOk = { type BlobAddress = { url: string headers: {[key:string]: string} + # Unix timestamp (in seconds precision) of when this address expires + expires Int } ``` @@ -505,7 +507,7 @@ type BlobAcceptReceipt = { } type BlobAcceptOk = { - claim: Link + site: Link } type BlobAcceptError = { @@ -517,12 +519,12 @@ type BlobAcceptError = { Receipt MUST not have any effects. -## Location Claim +## Location Commitment -Location claim represents commitment from the issuer to the audience that +Location commitment represents commitment from the issuer to the audience that content matching the `content` [multihash] can be read via HTTP [range request] -### Location Claim Delegation Example +### Location Commitment Delegation Example ```js { @@ -545,12 +547,12 @@ content matching the `content` [multihash] can be read via HTTP [range request] } ``` -### Location Claim Capability +### Location Commitment Capability -#### Location Claim Capability Schema +#### Location Commitment Capability Schema ```ts -type LocationClaim = { +type LocationCommitment = { cmd: "/assert/location" sub: ProviderDID args: { @@ -565,16 +567,16 @@ type LocationClaim = { ## Publishing Blob -Blob can be published by authorizing read interface (e.g. IPFS gateway) by delegating it [Location Claim] that has been obtained from the provider. +Blob can be published by authorizing read interface (e.g. IPFS gateway) by delegating it [Location Commitment] that has been obtained from the provider. -> Note that same applies to publishing blob on [IPNI], new capability is not necessary, user simply needs to re-delegate `LocationClaim` to the DID representing [IPNI] publisher. [IPNI] publisher in turn may publish delegation to DID with publicly known private key allowing anyone to perform the reads. +> Note that same applies to publishing blob on [IPNI], new capability is not necessary, user simply needs to re-delegate `LocationCommitment` to the DID representing [IPNI] publisher. [IPNI] publisher in turn may publish delegation to DID with publicly known private key allowing anyone to perform the reads. [store protocol]:./w3-store.md [CAR]:https://ipld.io/specs/transport/car/ [multihash]:https://github.com/multiformats/multihash [space]:#space [IPNI]:https://github.com/ipni/specs/blob/main/IPNI.md -[location claim]:#location-claim +[location commitment]:#location-commitment [Add Blob]:#add-blob [Put Blob]:#put-blob [put blob receipt]:#put-blob-receipt