Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: improved TimerService type documentation for auto-gen docs #9131

Merged
merged 4 commits into from
Mar 25, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions packages/time/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import type { RankComparison } from '@endo/marshal';
// meant to be globally accessible as a side-effect of importing this module.
/**
* The TimerBrand is a unique object that represents the kind of Time
* used in Timestamp/RelativeTime records. Time from different sources
* is not comparable.
* used in Timestamp/RelativeTime records. Times from different sources
* are not comparable.
*
* Do not call `isMyTimerService(myTimerService)` on an untrusted
* brand, because that will leak your closely-held timer authority. If
* the goal is to check the suitability of a client-provided
* Timestamp, use coerceTimestampRecord() or add/subtract it to a
* known-good Timestamp, or extact its brand and === against
* known-good Timestamp, or extract its brand and === against
* `timerService.getTimerBrand()`.
*
* TODO Not all Timestamps are labeled with the TimerBrand (in much
Expand Down Expand Up @@ -52,11 +52,21 @@ export type TimestampValue = bigint;
*/
export type RelativeTimeValue = bigint;

/**
* The canonical representation of a typed absolute time. It bundles the brand
* with the time, as represented by a TimerService, which might represent time
* since the epoch, or blockheight on a particular chain.
*/
export type TimestampRecord = {
timerBrand: TimerBrand;
absValue: bigint;
};

/**
* The canonical representation of a typed relative time. It bundles the brand
* with an elapsed time, as represented by a TimerService, which might represent
* time since the epoch, or blockheight on a particular chain.
*/
export type RelativeTimeRecord = {
timerBrand: TimerBrand;
relValue: bigint;
Expand Down Expand Up @@ -87,7 +97,8 @@ export type RelativeTime = RelativeTimeRecord | RelativeTimeValue;
/**
* A CancelToken is an arbitrary marker object, passed in with
* each API call that creates a wakeup or repeater, and passed to
* cancel() to cancel them all.
* cancel() to cancel them all. Multiple wakeups can rely on the same
* CancelToken so they can be cancelled collectively.
*/
export type CancelToken = object;

Expand Down Expand Up @@ -171,6 +182,11 @@ export interface TimerService {
getTimerBrand: () => TimerBrand;
}

/**
* Read-only access to a TimeService's current time. This allows reading the
* current time (e.g. to see if a deadline has passed) without the ability to
* schedule events.
*/
export interface Clock {
/**
* Retrieve the latest timestamp
Expand All @@ -182,6 +198,11 @@ export interface Clock {
getTimerBrand: () => TimerBrand;
}

/**
* The interface that must be implemented by objects which are to be invoked at
* scheduled times. Used by `TimerService.repeatAfter()`,
* `TimerService.setWakeup()`, and `TimerRepeater.schedule()`.
*/
export interface TimerWaker {
/**
* The timestamp passed to `wake()` is the time that the call was scheduled
Expand All @@ -190,6 +211,10 @@ export interface TimerWaker {
wake: (timestamp: TimestampRecord) => void;
}

/**
* Provides the ability to schedule wake() calls repeatedly at a regular
* interval, or to disable all future use of this TimerRepeater.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, maybe add "created by the old makeRepeater() API".. which is deprecated (but probably not visibly enough), new code should use repeatAfter(), which doesn't have a control object and doesn't require a second schedule step

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

*/
export interface TimerRepeater {
/**
* Returns the time scheduled for
Expand All @@ -205,6 +230,24 @@ export interface TimerRepeater {
disable: () => void;
}

/**
* TimeMath supports simple arithmetic on typed Time values, enforcing that
* values are combined in type-compatible ways. You can add 3 minutes to 3pm,
* or 5 minutes to a half hour, but it makes no sense to add 3pm and 5pm.
* Subtracting two Timestamps does produce a useful difference.
*
* The brands prevent you from accidentally combining time values from different
* TimerServices. If some chains track time in blocks, while others
* follow wall clock time, using the correct brands means you don't have to worry
* about timezones or how time is represented on a particular chain. This also
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, timezones shouldn't be a factor because they are merely a difference in formatting, and of course all sensible code should be using seconds-since-unix-epoch. But this does help manage the difference between consensus time on chain 1, consensus time on chain 2, and the time on your local computer, all of which might be nominally unix time but can diverge in various interesting ways.

Maybe:

The brands prevent you from accidentally combining time values from different
TimerServices. Some chains track time in blocks, others follow wall clock
time, some do both. Every local computer has its own unique notion of wall
clock time. Even when these clocks are talking about the same thing (UTC),
they can all drift in different ways. Using the correct brands lets you be
precise about which particular source of time you mean, preventing confusion
or attacks when the clocks diverge. Thus it is an error to e.g. use a time
you got from chain A to schedule an event on chain B.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* makes it possible to schedule events according to the time honored by
* different chains.
*
* The basic types are `RelativeTimeRecord` (durations) and `TimestampRecord`. The numeric
* values can be extracted from the typed values, but it's usually better to
* maintain values as their canonical typed form so these operations can be
* applied.
*/
export type TimeMathType = {
/**
* Validates that the operand represents a `Timestamp` and returns the bigint
Expand Down
Loading