Sashité for Developers
  1. Sashité for Developers
  2. Nostr
  3. NIPs
  4. Canonical Timing

NIP-XX

Canonical Timing

draft optional

This NIP defines canonical timing: a deterministic rule by which consumers assign an authoritative timestamp to events whose author-declared created_at cannot be taken at face value. It is the timing foundation for the turn-based game-session kinds (34183425, 3430) and for any other kind that declares its timing “canonical per this NIP” (e.g. kind 3441). It composes two primitives defined elsewhere: the Event Timestamp Attestation (kind 3410) and the Self-Timed Timing Relay profile.

Motivation

An event’s created_at is set by its author, who may have an incentive to misrepresent it. Applications where per-event timing is decisive — clocks, deadlines, move order — need a timestamp that every consumer derives identically from public data. This NIP fixes that derivation once, so that the consuming kinds can share one rule instead of each defining (and drifting on) their own.

Timing modes and mode selection

A founding event (a kind that opens a timed context — in the game suite: kinds 3418, 3420, 3430) selects the timing mode for its whole context by carrying exactly one of the following two designations:

["timing_relay", "<wss://relay.example.com>"]

A founding event carrying neither designation, or both, is non-conforming. Events that respond to or ratify a founding event (in the game suite: kinds 3419, 3421, 3422) mirror the founding designations verbatim, so that every consumer can determine the mode — and the parties to trust — from any one of them.

Designating several timing relays widens availability, not safety: canonical timing is established by acceptance at any one designated relay, so every designated relay must individually deserve the consumers’ trust (see §Security).

Canonical timing of an event

Attested mode. The canonical timing of an event is the created_at of the designated timestamper’s canonical attestation of that event — per the Event Timestamp Attestation NIP §Same-signer equivocation: the attestation with the smallest created_at, tie-broken by the smallest attestation id. An event none of whose attestations by the designated timestamper are known has no canonical timing.

Self-timed mode. The canonical timing of an event is the event’s own created_at, once its acceptance by at least one designated timing relay is established. A consumer establishes acceptance by retrieving the event from a designated relay: a conforming relay serves only what it accepted, and its ingestion window bounds how far the created_at can deviate from the moment of acceptance. An event that cannot be retrieved from any designated relay has no canonical timing for that consumer.

Undesignated events. A kind may adopt this NIP’s self-timed rule without a founding designation (e.g. kind 3441, whose events belong to no session). Its canonical timing is the event’s own created_at, once acceptance by a profile-conforming relay that the consumer trusts is established. The choice of trusted timing relays is then explicit consumer configuration, exactly as the choice of trusted signers is elsewhere.

The pending state

An event that has no canonical timing is pending. A pending event is not part of any canonical history:

Pending is observer-relative by construction — a consumer who cannot reach the designated relay establishes nothing — and this NIP makes that relativity explicit and bounded: it never yields two different timings for one event, only “this timing” or “not established”. A pending event may leave the state at any moment (the attestation arrives; the designated relay becomes reachable); it never changes timing by doing so.

Meta-resolution: competing events for one slot

Where a consuming kind defines a slot — a position that exactly one event may canonically occupy (one Game Session per founding, one Adjudication per session, one verdict per validator and subject) — and several conforming candidates compete, the canonical occupant is:

the candidate with the smallest canonical timing, tie-broken by the smallest event id (lexicographic, lowercase hex),

evaluated over the candidates known to the consumer whose canonical timing is established. A pending candidate cannot win a slot. If no candidate’s canonical timing can be established, the slot is unresolved and the parties’ competing claims are void for that consumer.

Under this rule, in either mode, a candidate published later cannot displace an established earlier one — later publication means larger canonical timing — so slots are stable in the nominal regime, and displacing one retroactively requires both a misbehaving signer and a colluding (or non-conforming) timing infrastructure that the consumer nonetheless trusts.

t₀ — the start of a timed context

Where a consuming kind anchors clocks at a context start (in the game suite: the Game Session, kind 3422), t₀ is:

the later of the context’s start_at tag value (when present) and the context event’s own canonical timing.

Consequences: with no start_at, t₀ is simply the context’s canonical timing; with a future start_at, the context is scheduled and no time is charged before it; if canonical timing is established only after start_at has passed, t₀ is that later moment — no participant is ever charged for an interval during which no valid action existed. No wall-clock observer is involved: an action event is early or late by comparing its own canonical timing to t₀ and to the budgets derived from it.

Security considerations

References