-
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
Rebasing nft.storage on top of web3.storage #167
Comments
why does the delegation we already have not accomplish this? eg nft storage would have a paid space on web3-storage. nft storage would run a lambda that delegates UCAN access to upload to that space, to anyone with an nft storage API key |
is it because that means NFT storage also would have to manage a database mapping NFTuser -> web3space, if there was gonna be one space per user? I think that is OK to ask our customers to do. They will probably do it anyway |
It would work, but that would imply that nft.storage either delegates "list" capability allowing users to list everyone's uploads or it does not delegate "list" capability not allowing users to list any uploads. By adding tags we simply provide a way for nft.storage to delegate limited "list" capability by that tag.
I'm not sure I follow this bit, although I think it is irrelevant how nft.storage chooses who to delegate capability to |
I think you're asking why not make nft.storage create a new "space" per user. They could, but that adds complexity:
With tags above complexity is gone.
|
I have though a bit more about one vs many tags and I have came around to supporting many tags idea because:
LimitationsImplying "intersection" behavior implies that "*/list" on tag unions can not be expressed (or at least with current ucanto toolchain, because it does not has support for compounding multiple delegations together) However I do think we could address join listing use case differently, more on this later. ProposalWe add type Tag = string | Pattern<string>
// Prefix implies match semantics as in anything that starts with `T`.
type Prefix<T extends string> = `${T}*`
// Keys are all the tags with intersection semantics
type Tags = {[key:Tag]: true} This allows nft.storage to delegate sub(space) prefixed with Alice can add more tags on add / write as well. [
{
can: 'store/add',
with: 'did:key:space',
tags: { ['alice*']: true }
},
{
can: 'store/list',
with: 'did:key:space',
tags: { ["alice*"]: true }
}
] Alice can (sub)delegate tagged (sub)space by adding more tags [
{
can: 'store/add',
with: 'did:key:space',
tags: { alice: true, bob: true }
},
{
can: 'store/list',
with: 'did:key:space',
tags: { alice: true, public: true }
}
{
can: 'store/list',
with: 'did:key:space',
tags: { alice: true, bob: true }
}
] Alice could also sub-delegate (sub) space to Mallory be extending a tag prefix, allowing Mallory to add / list things tagged as [
{
can: 'store/add',
with: 'did:key:space',
tags: {["alice+mallory*"]:true}
},
{
can: 'store/list',
with: 'did:key:space',
tags: {["alice+mallory*"]: true}
}
] Why objects and not arrays ?Arrays elements have order which affects hashes etc... IPLD codecs take care of encoding object keys in deterministic order making things more hash consistent. Why tag prefixes doesn't multiple tags give us that ?Multiple tags could be used to narrow down scope, but if you then want to list things tagged as Using tag prefixes a pragmatic solution by tagging things "alice/bob" and "alice/mallory" and then listing things that are tagged Hold on a second aren't you just recreating paths and hierarchies you claimed where bad ?Nope! Problem with paths isn't the paths themself but with implied semantics adding different things to same paths causes conflict. Tagging multiple things with a same path on the other hand isn't a conflict, so we avoid conflicts by making them impossible. |
i had a similar question (not because i disagree, but just don't know)
@jchris not sure i understand your second question as much - i think we're aligned here that there would just be one NFT.Storage space? |
we can, but users won’t because such capability wouldn’t be express-able and there for would not be possible to delegate.
Nothing they can tag their uploads as they want but those uploads will land in user space not nft.storage space so user will be billed instead. wouldn't it be better to use the same protocol for the ability to verifiably store in NFT.Storage's space and to track this storage (i.e., why would we make the tracking not part of the verifiable protocol)? you lost me here. We’re not proposing any new protocols here just adding extra field to capabilities so delegations could be constrained. if you are asking why not limit queries based on delegation chain, e.g why not limit list based on
Just adding a field to are capabilities is lot simpler, can be queried more efficiently and has non of the above listed issues. It is also a lot more flexible allowing nft.storage to organize space as it makes most sense for that use case as opposed to us trying to infer desired behavior from delegation chain and if we get it right for nft.storage it’s unlikely to be the right one for slightly different use case |
With UCANs it best to always think of them as movie 🎟️. If I have to ask for id in addition or know every pair hands it exchanged before it got here I’m doing it wrong. In other words delegation chain should not be used for anything other than validation of claimed capability check. Everything else should be in the capabilities, if that’s not enough we should add more stuff into capacities |
I think even better rule of thumb is: I should be able to swap a UCAN delegation chain with another valid chain without affecting behavior. |
Nice! That works for me. May we have ucanto accept a Listing and pagination in DynamoDB is limited. You can only get |
In the examples why do the |
Perhaps, I'm bit hesitant because experience may be bit of a surprise for a user, right now having set will simply throw an exception. I also had some chats during IPFS Camp and chances are we might get set data structure in IPLD data model in which case it would be no brainer. Also on related note I had attempted to have something like that for URLs instances, but that end up been problematic so I end up ripping it out, mostly because intention is clear on encode side, but not necessarily on decode side (do you mean actual object or do you mean set ?) In the meantime our SDK can take sets and turn those into objects so end user does not have to care about IPLD representation details
I mean listing API should have pagination, and if it does not we should fix that. Also I don't want to tie our protocol to the DynamoDB as we may use something in the future. Others implementing same protocol may never reach for dynamo etc... |
Yes, I'm not proposing we adjust things to suit dynamo. I'm flagging that dynamo might be less of a good fit here, but it's not gonna be a blocker. |
Works for me! |
Had a call with @mikeal @jchris @dchoi27 about this proposal where @mikeal raised serious concerns over it. I may not be able to convey all of the points, but I'll try and let @mikeal correct me and fill all the gaps where needed.
At the end of the day I think there no real difference that I can see from the table layout boiling down to the table like follows
That said using dedicated "space" over tags forces a single tag, which is what I was advocating initially as well. But then again last two records in the example above are still adding same CID to the same table but with two different "contract ID" which I don't think we can prevent in any way so in other words we wind up with two tables if we want to optimize for size
Or alternatively with layout like
If I'm understand correctly ☝️ is more along the lines of what @mikeal has in mind, but instead of Again I feel like beyond names of things it's all the same, but here are the tradeoffs as I see them
|
Personally I would much rather have something between two extremes, that is you get "storage contract" from the provider like {
can: 'contract/add',
with: 'did:dns:nft.storage'
} Which you can then enroll your space into, in other words invoke above delegated capability like {
can: 'contract/add',
with: 'did:dns:nft.storage',
nb: { target: 'did:key:zAlice' }
} Once enrolled, Now store invocations can (optionally) signal which storage contract data is billed by (or in other words who to bill) {
can: 'store/add',
with: 'did:key:zAlice',
nb: {
link: carLink,
contract: 'did:dns:nft.storage'
}
} If contract is not specified default contract is applied. E.g |
In this scenario, is nft.storage creating the spaces and apply funds on behalf of the users? If yes it also needs to keep keypairs(maybe not?), delegations, recovery kits (invoke recovery for users) and probably other stuff. That may be ok for nft.storage but probably too much for other customers. Example: A marketplace wants to handle/pay for user spaces but has a backend written in go, java, anything but js is it feasible that they need to write dag-ucan and probably more ucan code in golang ? |
@Gozala I like this proposal 👍 |
No nft.storage does not create any spaces, it just gives out capability to tie whichever space to it's billing account basically. It won't have to store things and we'll probably provide some API to list all the spaces that were added to it's billing account |
I had a review session with @mikeal of the latest draft of the protocol that ties bunch of things together:
More simply I think we want to proceed with the plan outlined in #167 (comment) with few caveats to reduce the scope further:
It is also worth calling out that we considered how write pipeline would be affected by idea of having multiple (storage) contracts.
Concrete action items:
|
Ok I'm afraid I can no longer wave my hands around naming this thing. So I'll try to persuade you all that we should use term "provider" and try to explain why:
I hope I'll convinced you that "provider" is a good name for this! In fact it makes whole lot of sense that space on it's own is pretty useless until you fill it with some providers to do a job for you! It also allows to be not too generic with fields name e.g. instead of having something like: {
can: 'store/add',
with: 'did:key:zAlice',
nb: {
link: carLink,
contract: 'did:dns:nft.storage'
}
} It turns into something like 🎉: {
can: 'store/add',
with: 'did:key:zAlice',
nb: {
link: carLink,
store: 'did:dns:nft.storage' <-- this is your storage provider
}
} For other things it could be called differently with domain specific term: {
can: 'worker/execute',
with: 'did:key:zAlice',
nb: {
worker: 'did:dns:vm.web3.storage' <-- this is your worker provider
code: codeCID,
data: dataCID
}
} |
This makes sense to me. Do want to try for a correspondence between the prefix of
|
Yeah I was kind of going for it & probably in most case it would build up intuition. If I want to invoke "foo/*" capability I need to hire "foo" service provider.
Yeah if we want reserve same name across all capabilities we could certainly generalize and call it "provider", but than again we could also always claim field name in |
Ok here is another cool piece that finally fits right into #167 (comment)
Obviously just like stated before we don't have to support multiple providers in MVP, but it is cool that we can in the future and that it will address problems we're already finding with current limitations |
this is cool!
fwiw, "upload provider" makes sense to me as an app developer - the
That is, I'd both like the ability to delegate parameterized upload capabilities to other folks AND would like to be able to do stuff like "specify a content type" or "set access control" during invocation (eg, "upload this note and give Irakli and Mikeal read and write access to it") - maybe this is the wrong way to do these specific things, but it seems like some sort of parameterization of the various Which is all to say that intuitively this choice of name makes sense to me! |
Well it does not really let you upload though, you use |
We've discussed viable path for the MVP, such that enables us handle nft.storage use case with following goals:
We decided that best solution for the MVP is following:
store/*
andupload/*
capabilities to be tagged with arbitrary string.store/*
andupload/*
capabilities with usersstore/list
andupload/list
capabilities will be tagged per user identifier.How is this better than creating dedicated spaces for each nft.storage user ?
Why tags and not paths ?
The text was updated successfully, but these errors were encountered: