Skip to content

feat(types): u64 entry point for Timestamp - #260

Open
poszu wants to merge 1 commit into
mainfrom
feat/timestamp-u64-entry-point
Open

feat(types): u64 entry point for Timestamp#260
poszu wants to merge 1 commit into
mainfrom
feat/timestamp-u64-entry-point

Conversation

@poszu

@poszu poszu commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Timestamps are microseconds since the epoch, and every caller that stores or reads one already holds it in a u64 — database rows, indexer state, node config. from_micros takes a u128, so all of them write x as u128 at the call site purely to satisfy the signature (in pod: r.timestamp_micros as u128, ts as u128, included_batch as u128, and more). from_micros_u64 removes that cast. µs in a u64 reach year 586524, so nothing representable is lost.

Additive only — the inner representation stays u128. That matters because Hashable for Timestamp hashes as_micros().to_be_bytes(), the 16 big-endian bytes validators sign: narrowing the field would change every attestation digest and invalidate historical vote certificates. The rmp persistence encoding (a u128 is a 16-byte Bin8, a u64 is a uint, and they are not cross-readable) and the whole existing public API are likewise untouched. Nothing that exists today changes behaviour or representation; this only adds a constructor.

A named constructor rather than impl From<u64> is deliberate. from_seconds already takes a u64, so a bare From impl would make x.into() silently mean microseconds sitting beside a seconds constructor of the identical type — and a µs/s mixup is a 1e6 error in a timestamp. std draws the same line: Duration::from_micros / from_secs, no From<u64>.

Note for pod: the pod repo pins pod-types to git rev acd1565 in three places in its root Cargo.toml, and the two fuzz workspaces pin 13a2da8d, so this constructor is invisible to that build until those pins bump. Tracked in CORE-94 along with the call-site cleanup.

🤖 Generated with Claude Code

Timestamps are microseconds since the epoch, and every caller that stores
or reads one holds it in a u64 — database rows, indexer state, node config.
`from_micros` takes a u128, so all of them write `x as u128` at the call
site purely to satisfy the signature.

`from_micros_u64` removes that cast. µs in a u64 reach year 586524, so
nothing representable is lost.

Additive only: the inner representation stays u128, so the signed
attestation digest (Hashable hashes the 16 big-endian bytes), the rmp
persistence encoding, and every existing signature are untouched.

A named constructor rather than `impl From<u64>`: `from_seconds` already
takes a u64, so a bare From impl would make `x.into()` silently mean
microseconds next to a seconds constructor of the same type, and a µs/s
mixup is a 1e6 error in a timestamp. std draws the same line with
Duration::from_micros / from_secs.

Refs CORE-94
@poszu
poszu force-pushed the feat/timestamp-u64-entry-point branch from 2301765 to 3102ef5 Compare July 31, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant