In looking at mixin zomes for entry timestamping, one of the (currently) simpler options to consider is that of “trusted time”. This ideally means generating creation timestamps on the fly, according to the time at which the user specifies the event occurred.
However, I’m not currently aware of any way of doing this within a Holochain app; since I was under the impression that Iso8601 input data had to be provided from outside the zome API, due to a need to enforce deterministic behaviour for writing entries.
Is this still accurate, or is there a simple way that I can access this parameter or have it injected by the zome callback handler at the time the request is processed?
When you say “trusted” you mean “trusted authority” rather than “implicitly trusted”, right? (Although I suppose my question doesn’t matter; you still need to somehow get the timestamp either way.) So the issue is that there’s no way to call SystemTime::now() from within a zome, right? Two options come to mind, both involving node-to-node messaging and the timestamping authority writing an entry to their source chain:
Built-in source chain header timestamps
Alice asks Tom (trusted timestamper) to timestamp her content’s hash via N2N messaging.
Tom writes a public source chain entry containing her hash.
Tom retrieves his just-published entry and header using hdk::get_entry_result() and returns both to Alice (but only if Alice needs to incorporate his timestamp into her entry; not sure if this is part of your design).
Timestamping bot
Alice asks Tom to sign/timestamp her entry hash, as before.
Tom’s DNA emits a signal to a service on his device listening for such signals via WebSocket. The signal consists of Alice’s entry hash.
The service checks the system time and passes it (along with the hash) to a zome function that writes/publishes the timestamp and pings Alice to let her know it’s ready.
The good thing about option 2 is that it’s async. The bad thing about it is that it’s async.
This is useful, but not what I was asking (sorry, bad naming). You’re talking firstly about what I’m calling “quorum time” and secondly about what I’m calling “trusted notary”. I would love to see those patterns implemented, especially the “online countersigning” pattern (which sounds quite complex).
It looks like for the kind of trust I’m talking about (“implicit trust”, in your words), the field I’m looking for can be found in the chain headers via get_entry_result (if there’s a more efficient method that only returns the header and only for the latest entry, lmk). But I can’t get this info until after I’ve written the record, can I?
Okay, yeah, you’re right — in that case it doesn’t exist until an agent commits the entry into their source chain. I just reread my earlier response… Both examples are for the ‘trusted notary’ case. Example 1 forces the trusted notary to commit an entry right then and there, so he can get the timestamp from the header, whereas example 2 gets the notary to make a call out to a timestamping daemon on his own machine.
But if you’re asking about ‘implicit trust’, then all my incredibly clever suggestions are useless I think the simple answer is, yeah, the agent would have to pass the timestamp in from her UI along with the rest of the entry data. If her instance needs do any timestamping headlessly, it could use the signal-to-timestamping-daemon (or signal-to-UI) idea as per the second trusted notary example above.
timestamp is written to a separate entry and linked to the main entry. Timestamp is part of the link tag.
timestamp is injected into response data as creation_time or similar
response data is sent; request ends
It would necessitate an extra link read to provide creation_time when reading the record later, but I think one additional DHT operation is pretty minimal- you can skip reading the entry itself if the timestamp is written to the link tag.
It’s a good MVP, IMO. In other timestamping scenarios there are just capabilities governing who gets to write the timestamps. I’m pretty sure the retrieval logic could be generic for all cases (ie. read all linked timestamps and average them).
Nice. One thing in particular stands out: the interface to the data being timestamped is clean; it doesn’t introduce any dependencies into the timestamping zome. That is, the only thing the timestamping zome understands is a request to timestamp some data (probably the hash of the content, for simplicity’s sake).
I presume that the response from the zome includes the creation_timeas well as the proof of timestamping (either a generated signature or the hash of the timestamp entry), which can then be incorporated into the caller’s data?
I guess it could return that stuff if external callers are interested in knowing about it; but I can also see how timestamping nodes on the DHT might want to be “more anonymous” than to have their public keys broadcast to anyone asking.
So… I suppose I’m more or less happy with this approach. It feels like a bit of a screwaround but I can see how it’s actually the most appropriate way of managing it when I think through how data flows through Holochain core (local chain first; then DHT broadcast…)
Oh, this changes my understanding of what you’re working on — I’d assumed that you’d want the timestamping nodes to be well-known public nodes that everyone can trust. Can you tell me more about anonymous timestamping nodes?
Oh no, all of the above. Per the types outlined in my original post:
Trusted notary = timestamping nodes are well-known public nodes
Quorum time = timestamping nodes are random agents who are holding the content on the DHT
Trusted time (the topic of this thread) = there are no timestamping nodes, just the timestamp of when the entry was first written to its author’s local source chain
I think we’re on the same page with how this should work. My only query is why you think there needs to be some “signature” of the timestamping present. What you mean is that we just need to store a regular entry, right? 'Cos the entry will have a signature as part of its provenance data?
I’ve just realised that the above approach won’t work, because what I actually need is for the entry time to be part of the entry so that it automatically disambiguates new entries as they are created. Otherwise, creating a new entry with the same content as a previous one results in the same record being written and returned - this is not always what you want.
So this means we’re back to the only option being passing the timestamp in from the external client app - there is as yet no way to provide this information automatically.
I’m curious how people feel about adding the concept of a “request time” to Holochain API calls, that is automatically injected into the request as it enters the zome API membrane for the first time. Is such a differentiation even possible given the core architecture?
So you’re problem is you want to put asynchronous events in a time series. Using approaches like this, you can really only guarantee that an event happened after a point in time. I believe this is more of a use case for a blockchain than a DHT. But that kind of goes back to something I’ve mentioned before, I think there needs to be a blockchain zome. If you want to take events, and put them in a “block” of time, that’s going to be a straightforward way to do it in a decentralized system.
The issue with a centralized authority is that you kind of remove the benefits of a decentralized system. What you have is a distributed database with a centralized API. If I can only post once a signature authority approves my post, there’s not much benefit to using a decentralized framework.
I think IOTA came up with an interesting solution that could work in Holochain. If you say that the confidence of an events occurrence in time increases with the amount of entries downstream from it, it helps to create a chronology. It wouldn’t be precise but it would help to establish that events happened after other events. Once again, this is moving in the direction of a “entry chain”. So I make a post, other people make posts and reference my header hash. Other people reference those posts. I now have a growing dag of entries that can establish a chronology. If users post entries to this DAG, they will help to establish a chronology that will be reasonably secure.
I would recommend reading about Lamport Clocks: https://en.wikipedia.org/wiki/Lamport_timestamps to see how this problem was handled historically. Also, verifiable delay functions https://eprint.iacr.org/2018/601.pdf are a modern approach that have some really interesting applications to these sorts of problems. Solana uses a combination of these techniques to build a chronology, and I would love to see a translation of these concepts to a DHT.
@rlkel0 that’s a great comment and set of links to go towards building robust timestamping solutions, like I’m exploring here:
For the purposes of this thread though, I’m just looking for the simplest option to get some kind of timestamp for records. Putting things in time series etc is well outside the scope, I’m just curious to know whether this can be left as a back-end implementation detail or has to be coded into the application layer of every app.
Currently the answer seems to be that if you want to record an authoring timestamp within the content of an entry, the UI needs to provide this. There is no metadata generated automatically by Holochain until after the entry is committed to the DHT.
If that be the case it would be nice to have such metadata. To provide for this, the initial request made to a Holochain DHT needs to be differentiated from all subsequent requests that are just syncing the initial entry. I’m not sure if this is possible; it depends on the internals of Holochain’s syncing logic. Can any core devs elaborate?
You could potentially use the header timestamps, although I think you’d need to ensure they’re monotonically increasing. I’m not sure if there’s anything that prevents a malicious agent from providing unreasonable timestamps. Agreeing on time in a distributed system is a whole other problem in itself though.
I don’t think so. Not something I’m concerned about for this more permissive implementation, anyway.
The issue remains that ChainHeader::new is called during the write phase (internally in commit_entry or update_entry)- you can’t generate a ChainHeader in the pre-write phase of a transaction like you can with entry_address, in order to provide for API_CALL_TIME_SOURCE in something like:
Yes. But it’s not only adding the field to the Entry type definition and assigning it, is it? It’s also:
Adding a parameter to the inbound API request payload
Adding a parameter to the client-side GraphQL schema or zome API request adapter
Passing a new Date() in every client-side request
I don’t want to have to deal with all that plumbing… in any client/server system I would not have to do any of those things because I would have access to the system clock, or at least to the time the request was initiated. Why not allow for Holochain apps to do the same? In my view, the client shouldn’t have to be responsible for this logic- the conductor node should figure it out and report back. A request time determined by the zome API function handler is no more or less trustworthy than a request time passed in from the client app.
The issue remains that ChainHeader::new is called during the write phase (internally in commit_entry or update_entry)- you can’t generate a ChainHeader in the pre-write phase of a transaction like you can with entry_address, in order to provide for API_CALL_TIME_SOURCE in something like:
but then you also say:
I don’t want to have to deal with all that plumbing…
You’re asking for custom logic but you don’t want to write it? Literally every thing you add to your app is another thing you need to implement, so I’m not sure what the issue is? If you’re concerned about your ability to code this, there’s an example of this here: https://developer.holochain.org/docs/tutorials/coreconcepts/simple_micro_blog/ so you could pretty much copy it verbatim.
This makes me wonder, is your plan to have a website that runs on Holochain but not require users to operate nodes? There’s been some discussion about this, where user would be able to salt their private key using the data on nodes but keeping their password secret. So they would be able to sign and authenticate their requests on the frontend without running a node, it’s just a slightly different architecture. Then you would be able to make node operators function as notaries. You can have multiple nodes sign a transaction, perhaps you encourage node operators to co-sign time stamps to increase security?
@rlkel0 I think that what @pospi is looking for is a way for a node to add a simple timestamp to their entry content, no guarantees about whether it’s accurate or monotonic or anything. I can understand the desire to do this in the zome function itself; there are times (e.g., node-to-node messaging) when you don’t have access to the client/GUI’s time functions.
It seems reasonable to me — after all, the conductor already timestamps things — and it’s not the first time someone has asked for it. I’m already tracking it in this Trello card, and @freesig and I are going to start making feature requests as PRs rather than tickets. I think there are some other things higher up in the queue right now, but hang tight and we’ll see where it goes!