-
Notifications
You must be signed in to change notification settings - Fork 22
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
Conversation
3d0ebf1
to
7331b22
Compare
|
||
export const validateAuthorization = () => ({ ok: {} }) | ||
|
||
// @ts-ignore Parameter | ||
export const setupGetReceipt = (contentGenFn) => { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in w3up-client we are using a mock server as a different process.
run process https://github.com/w3s-project/w3up/blob/604d300dde17521eea7333b949bb3f6796bd80a2/packages/w3up-client/package.json#L115
see that mock runs on npm run test https://github.com/w3s-project/w3up/blob/604d300dde17521eea7333b949bb3f6796bd80a2/packages/w3up-client/package.json#L109
https://github.com/w3s-project/w3up/blob/604d300dde17521eea7333b949bb3f6796bd80a2/packages/w3up-client/test/helpers/receipts-server.js
This is one way to go there, and if you see upload-client already uses this strategy for bucket-server https://github.com/w3s-project/w3up/blob/604d300dde17521eea7333b949bb3f6796bd80a2/packages/upload-client/package.json#L25 to write to a presigned URL
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 🤔
There was a problem hiding this comment.
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/src/blob.js
Outdated
// Fetch receipt from endpoint | ||
const url = new URL( | ||
taskCid.toString(), | ||
options.receiptsEndpoint ?? receiptsEndpoint |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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/src/blob.js
Outdated
onFailedAttempt: console.warn, | ||
retries: options.retries ?? REQUEST_RETRIES, | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
|
||
export const validateAuthorization = () => ({ ok: {} }) | ||
|
||
// @ts-ignore Parameter | ||
export const setupGetReceipt = (contentGenFn) => { |
There was a problem hiding this comment.
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
@@ -453,6 +475,9 @@ describe('uploadDirectory', () => { | |||
onShardStored: (meta) => { | |||
carCID = meta.cid | |||
}, | |||
fetch: setupGetReceipt(() => { | |||
return links[0] |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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
packages/upload-client/src/blob.js
Outdated
@@ -26,6 +27,40 @@ function createUploadProgressHandler(url, handler) { | |||
return onUploadProgress | |||
} | |||
|
|||
// FIXME this code was copied over from w3up-client and modified to parameterise receiptsEndpoint |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
packages/upload-api/src/blob/add.js
Outdated
@@ -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' | |||
|
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM ❤️
Co-authored-by: Vasco Santos <[email protected]>
Co-authored-by: Vasco Santos <[email protected]>
this.receiptsEndpoint = options.receiptsEndpoint ?? receiptsEndpoint | ||
this.retries = options.retries ?? REQUEST_RETRIES | ||
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis) | ||
/* c8 ignore stop */ |
There was a problem hiding this comment.
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'
There was a problem hiding this comment.
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
packages/upload-client/src/blob.js
Outdated
{ | ||
root: /** @type {import('@ucanto/interface').UCANLink} */ ( | ||
// @ts-ignore Property | ||
acceptReceipt.out.ok.site |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
packages/upload-client/src/blob.js
Outdated
null | ||
) | ||
/* c8 ignore next 5 */ | ||
if (!site) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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/index.js
Outdated
* @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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed
headers: {}, | ||
}) | ||
// Get receipt from the potential multiple receipts in the message | ||
const receipt = agentMessage.receipts.get(taskCid.toString()) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok gotcha!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Tests blob client with storacha/w3up#1459
🤖 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>
🤖 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 <[email protected]>
🤖 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 <[email protected]>
blob/accept
has succeeded before concludingblob/add
as per feat: add blob protocol to upload-client #1425 (comment). A location commitment is returned instead of the blob multihash.