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

fix: check for blob/accept receipts before blob/add is concluded #1459

Merged
merged 39 commits into from
Jun 4, 2024

Conversation

joaosa
Copy link
Contributor

@joaosa joaosa commented May 15, 2024


export const validateAuthorization = () => ({ ok: {} })

// @ts-ignore Parameter
export const setupGetReceipt = (contentGenFn) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would recommend to simplify this to either have a separate process mocking the getReceipt endpoint, or create a http server within this process instead of mocking the actual fetch implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

there is an alternative that maybe is more on the direction you are taking that you could also consider. you can rely on node http Server directly, freeway uses this kind of approach here https://github.com/web3-storage/freeway/blob/main/test/helpers/bucket.js. So, instead of a different process to run a mock server, the server runs in same process as the tests, and its URL and port are used by fetch to perfrom requests against.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you! I don't think the first approach would work as I need to load dynamic content into the receipt server. the 2nd approach should work and it does make sense, but I'm wondering if it's worth given the client refactor 🤔

Copy link
Contributor

Choose a reason for hiding this comment

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

if you could make this work I think it is fine. I think there is no impact on the client refactor but this was just to try to help out with not working tests.
However, I feel it would be much more cleaner than all the yield's in the tests below where I don't really understand some of them without going through the entire code path and logic, while a "real" server running would make it more close to what reality actually is. In addition, all the tests now need to change and have way more information being passed, while just relying on the Request to a real server with the path as the CID would simplify everything

// Fetch receipt from endpoint
const url = new URL(
taskCid.toString(),
options.receiptsEndpoint ?? receiptsEndpoint
Copy link
Contributor Author

@joaosa joaosa May 28, 2024

Choose a reason for hiding this comment

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

One thing I'm wondering about is if there's a better way to achieve this param config and what kind implications this would have in terms of configuration in a testing environment 🤔 . Also, I'm usually wary of defaulting to production, but I see this is a pattern on the codebase and is, as such, likely to be okay here.

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, I think this is the pattern here of defaulting to prod. So would say is good

packages/upload-client/package.json Outdated Show resolved Hide resolved
packages/upload-client/src/blob.js Outdated Show resolved Hide resolved
packages/upload-client/src/blob.js Outdated Show resolved Hide resolved
Comment on lines 354 to 356
onFailedAttempt: console.warn,
retries: options.retries ?? REQUEST_RETRIES,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

would be great to test that these defaults work nicely in a real environment, as they may exist a delay in between the receipt to be there. Did you try it against staging?

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 have not tried this but that is a good point

packages/upload-client/src/index.js Outdated Show resolved Hide resolved

export const validateAuthorization = () => ({ ok: {} })

// @ts-ignore Parameter
export const setupGetReceipt = (contentGenFn) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

if you could make this work I think it is fine. I think there is no impact on the client refactor but this was just to try to help out with not working tests.
However, I feel it would be much more cleaner than all the yield's in the tests below where I don't really understand some of them without going through the entire code path and logic, while a "real" server running would make it more close to what reality actually is. In addition, all the tests now need to change and have way more information being passed, while just relying on the Request to a real server with the path as the CID would simplify everything

packages/upload-client/test/index.test.js Outdated Show resolved Hide resolved
packages/w3up-client/test/capability/blob.test.js Outdated Show resolved Hide resolved
@joaosa joaosa requested a review from vasco-santos June 3, 2024 11:15
@@ -453,6 +475,9 @@ describe('uploadDirectory', () => {
onShardStored: (meta) => {
carCID = meta.cid
},
fetch: setupGetReceipt(() => {
return links[0]
Copy link
Contributor

Choose a reason for hiding this comment

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

could we by the path from the url used in fetch figure out which one is the CID for this link instead?

Copy link
Member

Choose a reason for hiding this comment

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

Oh yes that would be nicer, and allow it to respond appropriately when not found.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sadly, I don't think we can as we would need to compute the task ID from the initial links. I think it's best I remove this altogether

const taskID = url.pathname.replace('/receipt/', '')
const issuer = await Signer.generate()

const content = contentGen()
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this content gen should pass the CID of the receipt being requested do that caller does what it needs

@@ -26,6 +27,40 @@ function createUploadProgressHandler(url, handler) {
return onUploadProgress
}

// FIXME this code was copied over from w3up-client and modified to parameterise receiptsEndpoint
Copy link
Contributor

Choose a reason for hiding this comment

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

I though I wrote this earlier, but can't find it now. Can we make w3up to use this function from upload-client instead of having same code in both places?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed. I think I somehow mixed it with doing the same for the receipts endpoint

@@ -5,7 +5,6 @@ import * as Blob from '@web3-storage/capabilities/blob'
import * as W3sBlob from '@web3-storage/capabilities/web3.storage/blob'
import * as HTTP from '@web3-storage/capabilities/http'
import * as API from '../types.js'

Copy link
Contributor

Choose a reason for hiding this comment

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

could we take this out to avoid a upload-api release?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed

Copy link
Contributor

@vasco-santos vasco-santos left a comment

Choose a reason for hiding this comment

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

LGTM ❤️

packages/upload-client/src/receipts.js Outdated Show resolved Hide resolved
packages/upload-client/src/receipts.js Outdated Show resolved Hide resolved
joaosa and others added 2 commits June 4, 2024 12:13
Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
packages/upload-client/src/receipts.js Outdated Show resolved Hide resolved
this.receiptsEndpoint = options.receiptsEndpoint ?? receiptsEndpoint
this.retries = options.retries ?? REQUEST_RETRIES
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis)
/* c8 ignore stop */
Copy link
Member

Choose a reason for hiding this comment

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

nit: IMHO it's overkill to use a class here, since there's no state that changes for the lifetime of the instance and in usage you're never storing the instance to a variable (i.e. await new ReceiptPoller(options).poll(...)).

You could just export 2 methods, poll and get, pass them options objects and import like import * as Receipt from './receipts.js'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

alright sounds good. addressed as well

{
root: /** @type {import('@ucanto/interface').UCANLink} */ (
// @ts-ignore Property
acceptReceipt.out.ok.site
Copy link
Member

Choose a reason for hiding this comment

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

You should check for error and then you don't need to ts-ignore here.

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 don't think I need at all anymore, as previously the receipt acquisition method could return null. Now it's either a receipt or it throws.

null
)
/* c8 ignore next 5 */
if (!site) {
Copy link
Member

Choose a reason for hiding this comment

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

Why would this be falsey?

Copy link
Member

Choose a reason for hiding this comment

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

Oh you need to not pass null above (pass undefined or simply omit) for view(...) to throw in the case where the root does not exist in the passed blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed

* @param {import('./types.js').CARLink[]} shards
* @param {Array<Map<import('./types.js').SliceDigest, import('./types.js').Position>>} shardIndexes
*/
export async function indexShardedDAG(root, shards, shardIndexes) {
Copy link
Member

Choose a reason for hiding this comment

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

This should be an export from the blob-index utils.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed

packages/upload-client/src/receipts.js Outdated Show resolved Hide resolved
headers: {},
})
// Get receipt from the potential multiple receipts in the message
const receipt = agentMessage.receipts.get(taskCid.toString())
Copy link
Member

Choose a reason for hiding this comment

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

nit: It's kinda odd that this endpoint returns an AgentMessage but is not a ucanto endpoint...

I wonder if this should just always return an agent message (but with no receipts in it if not found) and then you wouldn't have to check for HTTP 404 status as well.

Copy link
Contributor

@vasco-santos vasco-santos Jun 4, 2024

Choose a reason for hiding this comment

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

This is because we in the past decided to redirect to the workflow object in S3, so there is really no way to know it exists, unless we would do redundant HEAD Request... We will need to UCANify the gets for workflows/receipts and, we may do changes at that point to the endpoint

Copy link
Member

Choose a reason for hiding this comment

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

Ah ok gotcha!

@joaosa joaosa requested a review from alanshaw June 4, 2024 11:55
Copy link
Member

@alanshaw alanshaw left a comment

Choose a reason for hiding this comment

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

LGTM

vasco-santos added a commit to storacha/w3infra that referenced this pull request Jun 4, 2024
@vasco-santos vasco-santos merged commit 462518c into main Jun 4, 2024
15 checks passed
@vasco-santos vasco-santos deleted the fix/blob-add-cli branch June 4, 2024 12:40
vasco-santos pushed a commit that referenced this pull request Jun 4, 2024
🤖 I have created a release *beep* *boop*
---


##
[1.0.3](blob-index-v1.0.2...blob-index-v1.0.3)
(2024-06-04)


### Fixes

* check for blob/accept receipts before blob/add is concluded
([#1459](#1459))
([462518c](462518c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
vasco-santos added a commit that referenced this pull request Jun 4, 2024
🤖 I have created a release *beep* *boop*
---


##
[16.0.2](upload-client-v16.0.1...upload-client-v16.0.2)
(2024-06-04)


### Fixes

* check for blob/accept receipts before blob/add is concluded
([#1459](#1459))
([462518c](462518c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
vasco-santos added a commit that referenced this pull request Jun 4, 2024
🤖 I have created a release *beep* *boop*
---


##
[14.0.0](w3up-client-v13.1.1...w3up-client-v14.0.0)
(2024-06-04)


### ⚠ BREAKING CHANGES

* **upload-api:** integrate agent store for idempotence &
invocation/receipt persistence
([#1444](#1444))
* delegated capabilities required to use `uploadFile`, `uploadDirectory`
and `uploadCAR` have changed. In order to use these methods your agent
will now need to be delegated `blob/add`, `index/add`, `filecoin/offer`
and `upload/add` capabilities. Note: no code changes are required.

### Features

* generate sharded DAG index on client and invoke w `index/add`
([#1451](#1451))
([a6d9026](a6d9026))
* **upload-api:** integrate agent store for idempotence &
invocation/receipt persistence
([#1444](#1444))
([c9bf33e](c9bf33e))


### Fixes

* check for blob/accept receipts before blob/add is concluded
([#1459](#1459))
([462518c](462518c))
* export blob client
([#1485](#1485))
([7944077](7944077))
* rename blob and index client capabilities
([#1478](#1478))
([17e3a31](17e3a31))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Vasco Santos <santos.vasco10@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants