From fe884feea0701cc6350aa1533c64dc478a99fa07 Mon Sep 17 00:00:00 2001 From: Karim <98668332+khadni@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:01:58 -0500 Subject: [PATCH 1/6] TS SDK v1.0.5 release + TS Time clarifications --- public/changelog.json | 14 +++ src/config/sidebar.ts | 1 + .../{time-in-cre.mdx => time-in-cre-go.mdx} | 1 + src/content/cre/concepts/time-in-cre-ts.mdx | 118 ++++++++++++++++++ src/content/cre/release-notes.mdx | 16 ++- 5 files changed, 149 insertions(+), 1 deletion(-) rename src/content/cre/concepts/{time-in-cre.mdx => time-in-cre-go.mdx} (99%) create mode 100644 src/content/cre/concepts/time-in-cre-ts.mdx diff --git a/public/changelog.json b/public/changelog.json index 5f8597f87bc..40d5c278ab9 100644 --- a/public/changelog.json +++ b/public/changelog.json @@ -358,6 +358,13 @@ } }, "data": [ + { + "category": "release", + "date": "2026-01-28", + "description": "TypeScript SDK version 1.0.5 fixes an issue with `runtime.now()` returning incorrect timestamps. See [Time in CRE](https://docs.chain.link/cre/concepts/time-in-cre) for usage details.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5)", + "title": "CRE TS SDK v1.0.5", + "topic": "CRE" + }, { "category": "integration", "date": "2026-01-26", @@ -366,6 +373,13 @@ "title": "CRE Expands to ZKSync Era", "topic": "CRE" }, + { + "category": "release", + "date": "2026-01-26", + "description": "TypeScript SDK version 1.0.4 is now available with internal improvements.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4)", + "title": "CRE TS SDK v1.0.4", + "topic": "CRE" + }, { "category": "integration", "date": "2026-01-25", diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index 0407f5c9b98..689af0cbcdf 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -409,6 +409,7 @@ export const SIDEBAR: Partial> = { { title: "Time in CRE", url: "cre/concepts/time-in-cre", + highlightAsCurrent: ["cre/concepts/time-in-cre-go", "cre/concepts/time-in-cre-ts"], }, { title: "Random in CRE", diff --git a/src/content/cre/concepts/time-in-cre.mdx b/src/content/cre/concepts/time-in-cre-go.mdx similarity index 99% rename from src/content/cre/concepts/time-in-cre.mdx rename to src/content/cre/concepts/time-in-cre-go.mdx index 1c2ca0ea5b1..6515bd79819 100644 --- a/src/content/cre/concepts/time-in-cre.mdx +++ b/src/content/cre/concepts/time-in-cre-go.mdx @@ -2,6 +2,7 @@ section: cre title: "Time in CRE" sdkLang: "go" +pageId: "time-in-cre" date: Last Modified metadata: description: "Understand DON Time in CRE: learn why all nodes need the same timestamp and how to use runtime.Now() for deterministic workflows." diff --git a/src/content/cre/concepts/time-in-cre-ts.mdx b/src/content/cre/concepts/time-in-cre-ts.mdx new file mode 100644 index 00000000000..ad6cebfe841 --- /dev/null +++ b/src/content/cre/concepts/time-in-cre-ts.mdx @@ -0,0 +1,118 @@ +--- +section: cre +title: "Time in CRE" +sdkLang: "ts" +pageId: "time-in-cre" +date: Last Modified +metadata: + description: "Understand DON Time in CRE: learn why all nodes need the same timestamp and how to use runtime.now() for deterministic workflows." + datePublished: "2026-01-28" + lastModified: "2026-01-28" +--- + +import { Aside } from "@components" + + + +## The problem: Why time needs consensus + +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: + +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. + +**DON Time** removes these divergences by making time **deterministic in the DON**. + +## The solution: DON time + +**DON Time** is a timestamp computed by an OCR (Off-Chain Reporting) plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.now()`, not via JavaScript's `Date.now()`. The `runtime.now()` method returns a standard JavaScript `Date` object. + +**Key properties:** + +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. + + + +## How it works: A high-level view + +1. Your workflow calls **`runtime.now()`**. +1. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +1. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +1. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +1. The result is written back into the WebAssembly execution, and your workflow continues. + +Because requests are sequenced, _Call 1_ for a workflow instance will always return the same DON timestamp on every node. If Node A hits _Call 2_ before Node B, A will block until the DON timestamp for _Call 2_ is produced; when B reaches _Call 2_, it immediately reuses that value. + +## Execution modes: DON mode vs. Node mode + +### DON mode (default for workflows) + +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) + +### Node mode (advanced / special cases) + +- Workflow authors handle consensus themselves. +- `runtime.now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. +- Useful in situations where you already expect non-determinism (e.g., inherently variable HTTP responses). + + + +## Best practices: Avoiding non-determinism in DON mode + +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. + +**Avoid** these patterns: + +- **Reading local time** (`Date.now()`, `new Date()`, etc.). Always use `runtime.now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. + +**Deterministic patterns:** + +- ✅ Gate behavior with: + ```typescript + const now = runtime.now() + if (isMarketOpen(now)) { + // proceed + } + ``` +- ✅ Compute windows from DON Time: + ```typescript + const now = runtime.now() + const fifteenMinutesMs = 15 * 60 * 1000 + const windowStart = new Date(now.getTime() - fifteenMinutesMs) + fetchData(windowStart, now) + ``` + +## FAQ + +**Is DON Time "real UTC time"?** + +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. + +**What is the resolution?** + +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. + +**Why can't I use `Date.now()`?** + +`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. Think of it like using `Math.random()`: it introduces non-determinism that's incompatible with CRE's consensus model. diff --git a/src/content/cre/release-notes.mdx b/src/content/cre/release-notes.mdx index a5b3b99290b..c3a7ec21152 100644 --- a/src/content/cre/release-notes.mdx +++ b/src/content/cre/release-notes.mdx @@ -5,19 +5,33 @@ date: Last Modified metadata: description: "Discover what's new in CRE: latest features, changes, and improvements in each release of the Chainlink Runtime Environment." datePublished: "2025-11-04" - lastModified: "2026-01-21" + lastModified: "2026-01-28" --- import { Aside } from "@components" This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/concepts/time-in-cre). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + ## ZKSync Era Support - January 26, 2026 CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. See the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page for chain names and forwarder addresses. +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + ## CLI v1.0.6 - January 21, 2026 **CRE CLI version 1.0.6 is now available.** From 3d349f6713b159ace88c1ef7f757297682720b86 Mon Sep 17 00:00:00 2001 From: Karim <98668332+khadni@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:10:44 -0500 Subject: [PATCH 2/6] TS SDK v1.0.5 release + TS Time clarifications --- src/content/cre/concepts/time-in-cre-ts.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/cre/concepts/time-in-cre-ts.mdx b/src/content/cre/concepts/time-in-cre-ts.mdx index ad6cebfe841..598543b29b8 100644 --- a/src/content/cre/concepts/time-in-cre-ts.mdx +++ b/src/content/cre/concepts/time-in-cre-ts.mdx @@ -115,4 +115,4 @@ New DON timestamps are produced continuously (multiple per second). Treat it as **Why can't I use `Date.now()`?** -`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. Think of it like using `Math.random()`: it introduces non-determinism that's incompatible with CRE's consensus model. +`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. From e57c649f4efa53bc9d36da3cb3804d4f9de99049 Mon Sep 17 00:00:00 2001 From: Karim <98668332+khadni@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:11:07 -0500 Subject: [PATCH 3/6] TS SDK v1.0.5 release + TS Time clarifications --- src/content/cre/llms-full-go.txt | 228 ++++++++++++++++--------------- src/content/cre/llms-full-ts.txt | 127 ++++++++++++++++- 2 files changed, 247 insertions(+), 108 deletions(-) diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt index 55644e4d2c2..3f4fd28a065 100644 --- a/src/content/cre/llms-full-go.txt +++ b/src/content/cre/llms-full-go.txt @@ -442,16 +442,30 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2026-01-21 +Last Updated: 2026-01-28 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/concepts/time-in-cre). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + ## ZKSync Era Support - January 26, 2026 CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. See the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page for chain names and forwarder addresses. +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + ## CLI v1.0.6 - January 21, 2026 **CRE CLI version 1.0.6 is now available.** @@ -7258,111 +7272,6 @@ Learn more about how to use CRE capabilities with built-in consensus: --- -# Time in CRE -Source: https://docs.chain.link/cre/concepts/time-in-cre -Last Updated: 2025-11-04 - - - -## The problem: Why time needs consensus - -Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: - -- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). -- Logs across nodes become **hard to correlate**. -- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. - -**DON Time** removes these divergences by making time **deterministic in the DON**. - -## The solution: DON time - -**DON Time** is a timestamp computed by an OCR (Off-Chain Reporting) plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.Now()`, not via an OS/System clock. The `runtime.Now()` function returns a standard Go `time.Time` object. - -**Key properties:** - -- **Deterministic across nodes**: nodes see the same timestamp. -- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. -- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. -- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. - - - -## How it works: A high-level view - -1. Your workflow calls **`runtime.Now()`**. -2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. -3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). -4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. -5. The result is written back into the WebAssembly execution, and your workflow continues. - -Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. - -## Execution modes: DON mode vs. Node mode - -### DON mode (default for workflows) - -- Time is **consensus-based** and **deterministic**. -- Use for **any** logic where different outcomes across nodes would be a bug. Examples: - - Market-hours gates - - Time-windowed queries ("last 15 minutes") - - Retry/backoff logic that must align across nodes - - Timestamps used for cross-node correlation (logging, audit trails) - -### Node mode (advanced / special cases) - -- Workflow authors handle consensus themselves. -- `runtime.Now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. This is the same mechanism used by standard Go `time.Now()` calls within the Wasm environment. -- Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses). - - - -## Best practices: Avoiding non-determinism in DON mode - -When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. - -**Avoid** these patterns: - -- **Reading host/system time** (`time.Now()`, etc.). Always use `runtime.Now()` from the CRE SDK. -- **Mixing time sources** in the same control path. -- **Per-node "sleeps" based on local time** that gate deterministic decisions. - -**Deterministic patterns:** - -- ✅ Gate behavior with: - ```go - now := runtime.Now() - if market.IsOpenAt(now): - // proceed - ``` -- ✅ Compute windows from DON Time: - ```go - now := runtime.Now() - windowStart := now.Add(-15 * time.Minute) - fetchData(windowStart, now) - ``` - -## FAQ - -**Is DON Time "real UTC time"?** - -It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. - -**What is the resolution?** - -New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. - ---- - # Random in CRE Source: https://docs.chain.link/cre/concepts/random-in-cre Last Updated: 2025-11-04 @@ -8939,6 +8848,111 @@ Large Language Models (LLMs) generate different responses for the same prompt, e --- +# Time in CRE +Source: https://docs.chain.link/cre/concepts/time-in-cre-go +Last Updated: 2025-11-04 + + + +## The problem: Why time needs consensus + +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: + +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. + +**DON Time** removes these divergences by making time **deterministic in the DON**. + +## The solution: DON time + +**DON Time** is a timestamp computed by an OCR (Off-Chain Reporting) plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.Now()`, not via an OS/System clock. The `runtime.Now()` function returns a standard Go `time.Time` object. + +**Key properties:** + +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. + + + +## How it works: A high-level view + +1. Your workflow calls **`runtime.Now()`**. +2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +5. The result is written back into the WebAssembly execution, and your workflow continues. + +Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. + +## Execution modes: DON mode vs. Node mode + +### DON mode (default for workflows) + +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) + +### Node mode (advanced / special cases) + +- Workflow authors handle consensus themselves. +- `runtime.Now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. This is the same mechanism used by standard Go `time.Now()` calls within the Wasm environment. +- Useful in situation where you already expect non-determinism (e.g., inherently variable HTTP responses). + + + +## Best practices: Avoiding non-determinism in DON mode + +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. + +**Avoid** these patterns: + +- **Reading host/system time** (`time.Now()`, etc.). Always use `runtime.Now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. + +**Deterministic patterns:** + +- ✅ Gate behavior with: + ```go + now := runtime.Now() + if market.IsOpenAt(now): + // proceed + ``` +- ✅ Compute windows from DON Time: + ```go + now := runtime.Now() + windowStart := now.Add(-15 * time.Minute) + fetchData(windowStart, now) + ``` + +## FAQ + +**Is DON Time "real UTC time"?** + +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. + +**What is the resolution?** + +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. + +--- + # Part 1: Project Setup & Simulation Source: https://docs.chain.link/cre/getting-started/part-1-project-setup-go Last Updated: 2026-01-14 @@ -14399,7 +14413,7 @@ The `Timeout` field specifies how long to wait for an HTTP request to complete b **Format:** -- Use `*durationpb.Duration` from the [`google.golang.org/protobuf/types/known/durationpb` package](google.golang.org/protobuf/types/known/durationpb) +- Use `*durationpb.Duration` from the [`google.golang.org/protobuf/types/known/durationpb` package](https://pkg.go.dev/google.golang.org/protobuf/types/known/durationpb) - Create using `durationpb.New()` with a `time.Duration` value - Or manually construct with `&durationpb.Duration{Seconds: int64}` diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index 7988b255793..acd51b8f736 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -442,16 +442,30 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2026-01-21 +Last Updated: 2026-01-28 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## TS SDK v1.0.5 - January 28, 2026 + +- **Bug Fix**: Fixed an issue with `runtime.now()` returning incorrect timestamps + +For details on using time in workflows, see [Time in CRE](/cre/concepts/time-in-cre). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.4...v1.0.5) + ## ZKSync Era Support - January 26, 2026 CRE now supports **ZKSync Era mainnet and testnet** for workflow simulation and production deployment. You can now build and test workflows that interact with ZKSync Era chains. See the [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks) page for chain names and forwarder addresses. +## TS SDK v1.0.4 - January 26, 2026 + +**TypeScript SDK version 1.0.4** includes internal improvements. + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-typescript/compare/v1.0.3...v1.0.4) + ## CLI v1.0.6 - January 21, 2026 **CRE CLI version 1.0.6 is now available.** @@ -7691,6 +7705,117 @@ Large Language Models (LLMs) generate different responses for the same prompt, e --- +# Time in CRE +Source: https://docs.chain.link/cre/concepts/time-in-cre-ts +Last Updated: 2026-01-28 + + + +## The problem: Why time needs consensus + +Workflows often rely on time for decisions (market-hours checks), scheduling (retries/backoffs), and observability (log timestamps). In a decentralized network, nodes do not share an identical clock—clock drift, resource contention, and OS scheduling can skew each node's local time. If each node consults its own clock: + +- Different nodes may take **different branches** of your logic (e.g., one thinks the market is open, another does not). +- Logs across nodes become **hard to correlate**. +- Data fetched using time (e.g., "fetch price at timestamp N") can be **inconsistent**. + +**DON Time** removes these divergences by making time **deterministic in the DON**. + +## The solution: DON time + +**DON Time** is a timestamp computed by an OCR (Off-Chain Reporting) plugin and agreed upon by the nodes participating in CRE. You access it through the SDK's runtime call, `runtime.now()`, not via JavaScript's `Date.now()`. The `runtime.now()` method returns a standard JavaScript `Date` object. + +**Key properties:** + +- **Deterministic across nodes**: nodes see the same timestamp. +- **Sequenced per workflow**: time responses are associated with a **time-call sequence number** inside each workflow execution (1st call, 2nd call, …). Node execution timing might be slightly off, but a given call will resolve to the **same DON timestamp**. +- **Low latency**: the plugin runs continuously with **delta round = 0**, and each node **transmits** results back to outstanding requests at the end of every round. +- **Tamper-resistant**: workflows don't expose host machine time, reducing timing-attack surface. + + + +## How it works: A high-level view + +1. Your workflow calls **`runtime.now()`**. +2. **The Chainlink network takes this request**: The Workflow Engine's **TimeProvider** assigns that call a **sequence number** and enqueues it in the **DON Time Store**. +3. **All the nodes agree on a single time (the DON Time)**: The **OCR Time Plugin** on each node reaches consensus on a new DON timestamp (the median of observed times). +4. Each node **returns** the newest DON timestamp to every pending request and updates its **last observed DON time** cache. +5. The result is written back into the WebAssembly execution, and your workflow continues. + +Because requests are sequenced, *Call 1* for a workflow instance will always return the same DON timestamp on every node. If Node A hits *Call 2* before Node B, A will block until the DON timestamp for *Call 2* is produced; when B reaches *Call 2*, it immediately reuses that value. + +## Execution modes: DON mode vs. Node mode + +### DON mode (default for workflows) + +- Time is **consensus-based** and **deterministic**. +- Use for **any** logic where different outcomes across nodes would be a bug. Examples: + - Market-hours gates + - Time-windowed queries ("last 15 minutes") + - Retry/backoff logic that must align across nodes + - Timestamps used for cross-node correlation (logging, audit trails) + +### Node mode (advanced / special cases) + +- Workflow authors handle consensus themselves. +- `runtime.now()` in Node Mode is a non-blocking call that returns the **last generated DON timestamp** from the local node's cache. +- Useful in situations where you already expect non-determinism (e.g., inherently variable HTTP responses). + + + +## Best practices: Avoiding non-determinism in DON mode + +When running in DON Mode, you get determinism **if and only if** you base time-dependent logic on DON Time. + +**Avoid** these patterns: + +- **Reading local time** (`Date.now()`, `new Date()`, etc.). Always use `runtime.now()` from the CRE SDK. +- **Mixing time sources** in the same control path. +- **Per-node "sleeps" based on local time** that gate deterministic decisions. + +**Deterministic patterns:** + +- ✅ Gate behavior with: + ```typescript + const now = runtime.now() + if (isMarketOpen(now)) { + // proceed + } + ``` +- ✅ Compute windows from DON Time: + ```typescript + const now = runtime.now() + const fifteenMinutesMs = 15 * 60 * 1000 + const windowStart = new Date(now.getTime() - fifteenMinutesMs) + fetchData(windowStart, now) + ``` + +## FAQ + +**Is DON Time "real UTC time"?** + +It's the **median of node observations** per round. It closely tracks real time but prioritizes **consistency** over absolute accuracy. + +**What is the resolution?** + +New DON timestamps are produced continuously (multiple per second). Treat it as coarse-grained real time suitable for gating and logging, not sub-millisecond measurement. + +**Why can't I use `Date.now()`?** + +`Date.now()` reads the local system clock, which differs slightly on each node. This breaks consensus—nodes may execute different code paths and fail to agree on the workflow result. + +--- + # Part 1: Project Setup & Simulation Source: https://docs.chain.link/cre/getting-started/part-1-project-setup-ts Last Updated: 2026-01-20 From a13f097dcd9ae903790e59d0296ac488142fac37 Mon Sep 17 00:00:00 2001 From: Karim <98668332+khadni@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:21:43 -0500 Subject: [PATCH 4/6] TS SDK v1.0.5 release + TS Time clarifications --- src/content/cre/llms-full-ts.txt | 2 +- src/content/cre/reference/sdk/core-ts.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index acd51b8f736..ef03bfcbc53 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -13123,7 +13123,7 @@ To learn more about how to aggregate results from `NodeRuntime`, see the [Consen Both `Runtime` and `NodeRuntime` provide: - **`config`**: Access to your workflow's configuration -- **`now()`**: Returns the current `Date` object +- **`now()`**: Returns the current `Date` object. See [Time in CRE](/cre/concepts/time-in-cre-ts) for details. - **`log(message: string)`**: Logs a message (see [Logging](#logging) below) - **`callCapability(...)`**: Internal method for calling capabilities (used by generated code) diff --git a/src/content/cre/reference/sdk/core-ts.mdx b/src/content/cre/reference/sdk/core-ts.mdx index 01894a5e922..16dd5bebc54 100644 --- a/src/content/cre/reference/sdk/core-ts.mdx +++ b/src/content/cre/reference/sdk/core-ts.mdx @@ -99,7 +99,7 @@ To learn more about how to aggregate results from `NodeRuntime`, see the [Consen Both `Runtime` and `NodeRuntime` provide: - **`config`**: Access to your workflow's configuration -- **`now()`**: Returns the current `Date` object +- **`now()`**: Returns the current `Date` object. See [Time in CRE](/cre/concepts/time-in-cre-ts) for details. - **`log(message: string)`**: Logs a message (see [Logging](#logging) below) - **`callCapability(...)`**: Internal method for calling capabilities (used by generated code) From 4205eb3a1243efb35716def105e825786a0d587d Mon Sep 17 00:00:00 2001 From: Karim <98668332+khadni@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:33:34 -0500 Subject: [PATCH 5/6] TS SDK v1.0.5 release + TS Time clarifications --- src/content/cre/reference/sdk/overview-ts.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/cre/reference/sdk/overview-ts.mdx b/src/content/cre/reference/sdk/overview-ts.mdx index a7a8d8ace24..6d56cec2830 100644 --- a/src/content/cre/reference/sdk/overview-ts.mdx +++ b/src/content/cre/reference/sdk/overview-ts.mdx @@ -7,13 +7,13 @@ pageId: "reference-sdk-overview" metadata: description: "Explore the TypeScript SDK API: complete technical reference for workflows, handlers, triggers, capabilities, and runtime methods." datePublished: "2025-11-04" - lastModified: "2026-01-20" + lastModified: "2026-01-28" --- import { Aside } from "@components" -