Hi @DavidMtl, first of all I’m assuming that when you say offline app you mean a non web app, i.e. a NodeJs app or a Java app, right?
The DOM API is a binding of almost one-to-one with safe_app_nodejs API, so whatever you are able to do with a nodejs app you should be able to do it with the DOM API.
The only reason the DOM API differs a bit from safe_app_nodejs API is just because the safe_app_nodejs objects are instantiated and kept in browser’s main process memory, and the web app (which runs in the a render process) only receives/manages tokens/handles for them, which are used when interacting with the API, but the functionality is just the same.
Now, if when you say low level you mean the same things you could do from a Rust client app using the safe_client_libs libraries directly, then there could be a big difference at least for the moment.
Am I answering your question? please let me know since we are very interested in receive feedback as wee move forward.
ImmutableData address is calculated based on its content, so even that the network would enforce nobody mutate its content, I assume you can actually verify it yourself, although I’m not aware of the details of the hash function used, we can ask some of the other devs to explain in detail if needed.
The getCotnainersNames functions returns the list of only containers names the app is currently authorised to access to.
A container is essentially a MutableData, but as you can see the SAFE network provides a pre-defined set of containers (created upon account creation) which every app can request access to independently.
In addition to this, an app can request to have its own container created when requesting to be authorised (look at the options param of the authorise function here), which is called the App’s Container.
Now, as you must know any app can create any MutableData it wants, and then the NFS emulation can then be used on top of it, which enforces some convention in the way the data entries are stored in it, but the app can also decide to handle data entries manipulation by its own to enforce any other convention needed for the app’s data.
Structured data or mutable data can be made immutable by transferring them to a public key with no known associated private key. A constant is provided in routing crate for such a public key (NO_OWNER_PUB_KEY).
This is a workaround to have both immutability and customizable address.
One use case is when you need to create a chain of data made by different people and you want to make sure no one breaks the chain by removing its part.
For example a chain of comments on a blog. The address of each comment would be the hash of the previous comment. If someone could remove its comment it would break the chain losing track of the following comments. So what you do is require in your protocol that each comment must be an immutable data.
Another example could be for the record of a game of chess. The sequence of move would be recorded in a chain of immutable data so it cannot be changed.
Interesting. So if I create a mutable data with this constant would other be able to validate and confirm the data really cannot be changed? Do you know where I could find more info about it?
I understand, but for this case you don’t really need to be able to choose the address, you take the address calculated for the previous data item in the chain, include it in the content of the new one, and store it as ImmutableData.
The idea from @tfa seems also reasonable if you really need that.
I see, so we can have a single MD contain all comments and each user who insert a new key value pair is only allowed to modify his own entry. I didn’t realize we could do that, that looks good. And reading the RFC I see that if I set the permission to Deny.upgrade to anyone it would prevent them from modifying their entry and effectively create a list of data that can’t be change, is that correct?
Isn’t that just for the reverse order though, going from last to first? How would you go from the first item to the last one? You can’t include the address of the next item in your immutable data since the next item isn’t created yet and you can’t predict what will be its address.
But anyway am not sure this is relevant anymore as @rob and @tfa answers seems to cover my cases.
I agree, I would like to get more detail about it though, is that somewhere in a RFC?
Anyway thanks guys, I fell back a bit behind with the new paradigm so thanks for helping me understand it better.
I was thinking of one MD per comment, that way everything to do with that comment could be stored in that MD. Each update to the MD costs a “PUT” so there really is no difference to one or many comments per MD. The MD overhead header size is about the only storage overhead. And if the user edits their comment then a new field is added with the updated comment. That way you can view the previous edits like discourse allows. Thus you can make the MD as append only and so the MD only allows fields to be added and not deleted. Thus the link fields, and any other info you want to keep on a comment (like userID, Times, etc) are protected too.
EDIT: the above is my understanding of the MD implementation.
Just to make sure I understand correctly. Let’s say I want to create a blog with comments. First I create a MD that anyone can add a key-value pair to it. This MD would be the list of comments. Whenever someone wants to add a comment they would need to insert a new key-value into the “list MD”. The value would be the address of another MD owned by the user where the actual comment is.
Now if I want to list all comments for a blog post I scan the “list MD” and then request all “comment MD” referenced in it. Correct?
There is a number of methods. I was mainly referring to your example above with a link list of comments.
I also was thinking that the comment MD would need to be owned by the APP or owned by nobody and set to append only. So your APP adds the comment MD as Append only type, then appends the link fields and thenappends the user’s comment field. Any edits by the user is appended to that MD. Then change owner of he MD to “nobody” This means that the comment can still edited by appending the changed comment to the MD. You could even mark the comment as deleted by appending a field indicating such. But this way no one can remove the MD or change the linkage information.
Thus your example of a blog would be the Blog is published and you could have a MD point to the blog text which could be in immutable storage, and the MD is the starting point for comments. by storing the link to the first comment when its made.
I expect your blog APP would do this for the user and do all the work.
The comment MD that is created and owned by “nobody” would have had the user’s ID as part of the data stored by the APP so the APP will only recognise comment text fields signed by the APP & user.
I am also unsure how we can implement proper security since anyone can extract the APPs keys it uses to create the MDs from the APP code itself. But that is a subject that hasn’t been answered yet as far as I know.
That’s what I meant, the app is doing it on behalf of the user. Would be tedious if not.
Ah, so each value-key pair are signed by the user who created it and the app would be able to get this information to filter out the bad ones, is this currently how it is implemented? Though now it makes me think that someone with bad intention could fill out the 100 entry of the MD to prevent someone from editing his comment.
But anyway, since we can choose the address of a MD we just have to decide on a protocol to determine where the next comment should be located. For example, the next comment is always at the location defined by the hash of the location of the previous comment. This way you don’t need to go back to the previous comment to add the location of your comment, you just need to follow the protocol to find it. That is the reason why I was asking for “locatable” immutable data. But it looks like we could do it with mutable data set to nobody.
Yeah, we (collectively) need to figure out the proper pattern to use for these kind of features. You guys gave me good food for thought, I think it’s fair to say the API will evolve as we explore all edge cases.
Extra question for @bochaco about setting the owner to nobody: would it be possible to have an option in the API to set it the moment the MD is created instead of doing it with an update to avoid race conditions?
If the MD is set to allow anyone to append then yes.
If the MD is set so only the owner can append then cannot use the “nobody” owner and have to leave the MD as owned by the APP and have the APP to update
Ah but a bad actor could follow this protocol and create all the MDs so your APP cannot. Best to use either random addresses and link them.[quote=“DavidMtl, post:19, topic:703”]
would it be possible to have an option in the API to set it the moment the MD is created
You still have the race don’t you when writing the fields to go into your created MD. If you create with a 128 bit random address then the chances of catching the creation of the MD by another (bad actor) is nigh on impossible