---
title: Logical Clocks
tags: docs
---
# Logical Clocks
## Single-writer-log
For the single-writer-log (SWL) structure, Mosaic adopts the log structure described in ThreadsDB protocol[^ThreadsDB-ipfs] as a logical clock for a single writer. Validity of the log relies on valid signature from the LogId (equated to PeerId).
CodedLogNode(N) (encrypted w ServiceKey)
|-Sig (signs cidEventNode+cidPrevLogNode)
|-PubKey (ServiceKey, ReadKey) (optional)
|-PrevLogNode
| |-Sig
| |...
|-EventNode
|-CodedBodyNode (encrypted w ContentKey)
| |-Body
|-CodedEventHeaderNode (encrypted w ReadKey)
|-ContentKey
Here the signature signs a payload `(cidEventNode, cidPrevLogNode)` with the private key of the PeerId. Any node who has the service key can traverse the log history. A node that has the read key can decrypt the header of the record, and therefor the content key to decrypt the body. See code-reference[^cbor-record].
Content, read and service keys are symmetric keys.
Content key is randomly generated for each body.
In a first simple model, read and service keys are constant over the lifetime of SWL. Service keys can be rotated, and the old service key can be included in the `PubKey` field of the logNode, such that the history remains traversable[^qn-rot-servicekey].
A Thread is a topic-based collection of single-writer-logs. Conventiently these SWLs can share a service key and read key across the logs.[^thread-def]
As the service key is not globally shared, we call SWL local. Logs are part of the IPFS MerkleForest but there is a priori no global consensus over the head of a log. In the next chapter, strings and rings will be described as contracts to govern references to the heads of logs within a global consensus state.
## Ethereum as a global clock
A single-chain blockchain as Ethereum creates a global clock with each ordered transaction moving the global state forward. For convenience the transactions are grouped in blocks, and the block number is a global clock for the global state maintained in the state trie.
## multiple global sub-clocks
[describe variations of systems with multiple sub-clocks; including but not limited to cosmos, polkadot, (Eth2 sortition), metachains, ava]
## multi-writer-logs
Smart contract code executed within the state of a global (sub-)clock can serve as a multi-writer-log tracking the head of a similar log structure^[TODO:specify]. New record entries are appended by a threshold (of) signature(s) of participants in the multi-writer-log.
By using a majority vote on a Byzantine Fault-Tolerant (BFT) substrate[^substrate-explainer], the multi-writer-log is BFT without introducing strong synchronicity requirements[^strong-synchronicity] among the multi-writer-log participants ^[ie. without reconstructing a new blockchain among the participants, eg. using Tendermint]. This allows a multi-writer-log to be much more lightweight than if it would be constructed from the networking layer up; leveraging the presence of the global (sub-)clock that is already present in a blockchain network.
Participants in a multi-writer-log can each use single-writer-logs to communicate among eachother by sharing a thread. Those SW-log-entries must be mergable (with a logical clock or CRDT, depending on the application). A multi-writer-log environment itself is not intended to be BFT.
# Simultaneity
To consistently interact between independent logs (SW or MW), we can construct merkle-clocks by exchanging data objects in an event-driven architecture[^exploration-is-it-a-merkle-clock]
# Random references
- [go-threads/cbor/record](https://github.com/textileio/go-threads/blob/v0.1.18/cbor/record.go#L41)
# Footnotes
[^ThreadsDB-ipfs]: [ThreadsDB paper version dec 2020](https://ipfs.io/ipfs/QmRjgbB5pTxUnoLFbXtDHs1ph5t5pUhRnYn1wFiYEpP5s1?filename=201912TextileThreads.pdf)
[^cbor-record]: A LogNode is the CBORNode wrapping of the `record` struct (go-threads/cbor/record.go)
```go
// record defines the node structure of a record.
type record struct {
Block cid.Cid
Sig []byte
PubKey []byte
Prev cid.Cid `refmt:",omitempty"`
}
```
where `Block` should resolve to an EventNode (go-threads/cbor/event.go)
```go
// event defines the node structure of an event.
type event struct {
Body cid.Cid
Header cid.Cid
}
```
where `Header` is
```go
// eventHeader defines the node structure of an event header.
type eventHeader struct {
Key []byte `refmt:",omitempty"`
}
```
[^thread-def]: A `ThreadId` is a random identifier for raw (ie. not-ACL) threads. `LogId` identifies the log, derived from the IdentityKey (can be, but doesnt need to be the privkey of PeerId {assumption})
[^qn-rot-servicekey]: Is `PubKey` intended to rotate the service key, such that the history remains traversable? Is this implemented as such in go-threads? Does it make sense to rotate the read key in a similar way?
[^strong-synchronicity]: Here strong synchronicity is understood to be a system where the client requires timely updates to assert validity of the state (eg. no network partition); for a multi-writer-log with its head written to a BFT substrate the validity of the multi-writer-log is given by the validity of the substrate and the integrity checks on the log itself from the head down. [todo: well-defined?]
[^substrate-explainer]: a BFT substrate can be a suitable candidate from any of the following: Ethereum, metachains over Ethereum(testnet), cosmos zone, polkadot parachain, ava(testnet), or others
[^exploration-is-it-a-merkle-clock]: metachains / IBC / ... is a merkleclock
http? make request: this is not a merkleclock, because we dont want wait for client's log update;
BUT, we actually do, if we have a compound action `{mtx_to_update_SWL; record}`