String encoded as a hex string with Big Endian bytes.
Applications might use UUID native types like MySQL’s UUID field type, or C#’s Guid class. However, an event Id will not validate to a known UUID version.
If two events occur at the exact same microsecond, Evently increments the timestamp by one microsecond. Thus, no two events will ever occur at the exact same time. If the current time on the system is behind the last event’s time component, Evently will disregard current time and utilize the time value of the last event time, incrementing the microsecond to move past the previous event time. This will keep the event ledger in order if the clock is reset into the past.
NOTE: this is how Google’s TrueTime works; it does not duplicate timestamps but will increment ahead in case timestamps collide.
An Event ID can be traced to the event ledger it belongs to, and its place therein. It is a reference to a point in the ledger that marks the event. It also contains a verification checksum to validate the event contents matches the Event ID.
A Ledger ID is a 32-bit signed integer. It is computed as a partial checksum of the ledger’s genesis event, ANDed with the Ledger ID version. The genesis event is the ledger’s very first event and does not have a Ledger ID itself for the checksum. As a result, the Ledger ID is computed by following steps 1-5 of the Event checksum algorithm.
Here is an example genesis event:
{copyText = 'Copy'}, 300)" class="language-json">{"entity":"📒","key":"testing⑆preview","event":"刅","eventId":"0005cd7556b050928fed8a064f832abc","timestamp":"2021-10-03T16:32:12.816530Z","meta":{"actor":"matt","created":"2021-09-04T20:27:17.300Z"},"data":{"name":"My Ledger","description":"This ledger is for my events."}}
Evently anticipates that future event IDs will need different data structures, so versioning is built into the ID.
00: 30 bit Ledger ID, 2 bit version
To apply the version to Ledger ID: ledgerId & 0xfffffffc
The reader can examine the end of the Ledger ID to determine its version.
Versioning allows for future changes to the Ledger ID format to be identified and utilized. A ledger should be able to contain events with Ledger IDs that have different versions over time.
The checksum calculation utilizes CRC32C and requires each event's attribute to be fed to the CRC32C calculator in this order. Note that ledger ID checksums omit the last three steps.
Entity name
Entity key
Event name
Sorted1 meta object as a compact2 JSON string
Sorted1 data value, if an object, as a compact2 JSON string
Skip the following steps for Ledger ID calculation
Ledger ID as lower-case, base-16 hex string
Timestamp as lower-case base-16 hex string. When parsing the timestamp field in the event body, be sure to parse the microsecond portion. Some Date parsing libraries can only parse up to the millisecond.
Previous Event ID as lower-case base-16 hex string. If this is the genesis event, then this value is 000000000000000000000000 + Ledger ID as lower-case base-16 hex string. This is an event ID at timestamp 0, checksum 0, for this ledger.
1 A “sorted” object has its keys sorted in case-sensitive, ascending order. An object’s properties, if they are themselves objects, are sorted in the same way. This guarantees the objects are serialized to JSON consistently from the JSON parser’s results, which may be an unordered map. Array values are never sorted, but the object entries in an array are sorted in this manner.
2 A “compact” JSON string is represented as a single line with no whitespace between the braces, brackets, commas or other separators.
A collision is when two different events share the same event ID. While theoretically possible, a collision is unlikely for these reasons:
Monotonic timestamp means a ledger will never have a duplicate timestamp for any event.
Very rare checksum collisions: two different events will almost never have the same checksum.
If #1 does not hold, and a ledger's event timestamps could be the same, the checksum would also have to collide for the event id to point to two different events that occur at the same time in the ledger.
The checksum can be used to validate an event ledger. It can validate the entire ledger, or a subsection of the ledger if one trusts the starting point of the ledger section being validated. Validation follows these steps.