From 24437deb7822a5c95c3d7ba366c7ae5625958d1c Mon Sep 17 00:00:00 2001 From: devin distefano Date: Wed, 20 May 2026 18:55:37 -0500 Subject: [PATCH 1/6] initial pass --- src/config/sidebar.ts | 8 + .../generating-reports-single-values.mdx | 12 +- .../generating-reports-structs.mdx | 4 +- .../onchain-write/overview-go.mdx | 11 + .../onchain-write/overview-ts.mdx | 11 + .../submitting-reports-onchain.mdx | 7 +- .../workflow/using-http-client/index.mdx | 31 +- .../submitting-reports-http-go.mdx | 30 +- .../submitting-reports-http-ts.mdx | 30 +- .../verifying-reports-offchain-go.mdx | 300 +++++++++++ .../verifying-reports-offchain-ts.mdx | 257 +++++++++ src/content/cre/llms-full-go.txt | 488 +++++++++++++++++- src/content/cre/llms-full-ts.txt | 401 +++++++++++++- src/content/cre/reference/sdk/core-go.mdx | 81 ++- src/content/cre/reference/sdk/core-ts.mdx | 72 ++- .../cre/reference/sdk/http-client-go.mdx | 19 +- .../cre/reference/sdk/http-client-ts.mdx | 7 +- src/content/cre/reference/sdk/overview-go.mdx | 2 +- src/content/cre/reference/sdk/overview-ts.mdx | 2 +- 19 files changed, 1708 insertions(+), 65 deletions(-) create mode 100644 src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-go.mdx create mode 100644 src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index b541d804798..75f13155597 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -387,6 +387,14 @@ export const SIDEBAR: Partial> = { "cre/guides/workflow/using-http-client/submitting-reports-http-go", ], }, + { + title: "Verifying CRE Reports Offchain", + url: "cre/guides/workflow/using-http-client/verifying-reports-offchain", + highlightAsCurrent: [ + "cre/guides/workflow/using-http-client/verifying-reports-offchain-ts", + "cre/guides/workflow/using-http-client/verifying-reports-offchain-go", + ], + }, ], }, { diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx index ca4ca5793d8..a505db987cd 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx @@ -11,7 +11,9 @@ metadata: import { Aside } from "@components" -This guide shows how to manually generate a report containing a single value (like `uint256`, `address`, or `bool`). This is useful when you need to send a simple value onchain but don't have a struct or binding helper available. +This guide shows how to manually generate a **CRE report** containing a single value (like `uint256`, `address`, or `bool`). A CRE report is a DON-signed package from `runtime.GenerateReport()` / `runtime.report()`—your encoded data plus workflow metadata and signatures. It is **not** a [Data Streams](/data-streams) report. + +This guide covers **creating** the report (step 2 in the sender flow). **Delivering** it is a separate step—see the table below. **Use this approach when:** @@ -31,10 +33,12 @@ Manually generating a report for a single value involves two main steps: 1. **ABI-encode the value** into bytes using the `go-ethereum/accounts/abi` package 1. **Generate a cryptographically signed report** using `runtime.GenerateReport()` -The resulting report can then be: +| After `GenerateReport()` / `report()` | Guide | Who verifies? | +| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | +| `evm.Client.WriteReport()` / `writeReport()` | [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | `KeystoneForwarder` onchain | +| `http.Client` `SendReport()` | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) | Receiver: [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) or your API | -- Submitted to the blockchain via `evm.Client.WriteReport()` (see [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)) -- Sent to an HTTP endpoint via `http.Client` (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http)) +See [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver mental model. +## Where this guide fits + +| Question | Answer | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | Output of `runtime.report()` after your workflow DON reaches consensus: encoded payload + metadata + signatures. Not a Data Streams report. | +| Where does it come from? | **Inside this workflow**—after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | +| What does this guide cover? | Steps 2–3: generate the report, then `sendReport()` to your API. | +| Who verifies it? | The **receiver**—your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). | + +**Sender flow in one workflow execution:** + +1. Trigger fires (cron, HTTP, …). +2. Your callback runs (API calls, encoding, etc.). +3. `runtime.report()` — DON produces a signed `ReportResponse`. +4. `sendReport()` — format and POST to your URL. + +For a conceptual overview and diagram, see [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). + ## Prerequisites - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) @@ -560,15 +578,13 @@ const onCronTrigger = (runtime: Runtime): MyResult => { 1. **Always use `cacheSettings`**: Include caching in every transformation function to prevent worst-case duplicate submission scenarios 1. **Implement API-side deduplication**: Your receiving API must implement deduplication using the **hash of the report** (`keccak256(rawReport)`) to detect and reject duplicate submissions -1. **Verify signatures before processing**: Your API must verify the cryptographic signatures against DON public keys before trusting report data (see note below about signature verification) +1. **Verify on the receiver**: The sender does not validate the report—your API or a [receiver CRE workflow](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts) must verify before trusting payload data 1. **Match your API's format exactly**: Study your API's documentation to understand the expected format (binary, JSON, headers, etc.) 1. **Handle errors gracefully**: Check HTTP status codes and provide meaningful error messages {/* prettier-ignore */} ## Troubleshooting @@ -586,6 +602,8 @@ const onCronTrigger = (runtime: Runtime): MyResult => { ## Learn more +- **[API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http)** — Sender → receiver overview +- **[Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts)** — Receiver workflow: verify before trusting payload - **[HTTP Client SDK Reference](/cre/reference/sdk/http-client-ts)** — Complete API reference including `sendReport()` and `ReportResponse` - **[POST Requests](/cre/guides/workflow/using-http-client/post-request)** — Learn about HTTP request patterns and caching - **[Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain)** — Detailed guide on encoding single values, structs, and complex types using Viem diff --git a/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-go.mdx b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-go.mdx new file mode 100644 index 00000000000..24e90663a0f --- /dev/null +++ b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-go.mdx @@ -0,0 +1,300 @@ +--- +section: cre +title: "Verifying CRE Reports Offchain" +date: Last Modified +sdkLang: "go" +pageId: "guides-workflow-http-verify-reports-offchain" +metadata: + description: "Verify CRE report signatures offchain in Go: parse reports, validate DON signatures against the onchain registry, and read workflow metadata." + datePublished: "2026-05-20" + lastModified: "2026-05-20" +--- + +import { Aside } from "@components" + +This guide is for the **receiver** side: you already received a CRE report package (usually via HTTP) and need to **prove it is authentic** before using the payload. + +When a workflow delivers results via HTTP (or another offchain channel), nothing onchain automatically validates the report. **You must verify signatures before trusting the data.** + +The CRE SDK provides `cre.ParseReport()` to do this inside a workflow. Verification runs offchain in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. + +{/* prettier-ignore */} + + +{/* prettier-ignore */} + + +## Where this guide fits + +| Question | Answer | +| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | Same CRE report the **sender** created with `runtime.GenerateReport()`—not a Data Streams report. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#where-this-guide-fits). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `GenerateReport()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 4: `cre.ParseReport()` before you use `Body()` or take side effects. | +| Same workflow as the sender? | Often **no**—common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | + +**Receiver flow:** + +1. HTTP trigger (or your API) receives the POST payload. +2. Decode hex fields into bytes. +3. `cre.ParseReport()` — verify signatures and read metadata. +4. Use trusted `Body()` in your logic. + +For the full sender → receiver diagram, see [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). + +## What you'll learn + +- When to verify reports offchain vs relying on onchain forwarders +- How `cre.ParseReport()` validates signatures and reads metadata +- How to build a receiver workflow that accepts reports over HTTP +- How to restrict verification to specific CRE environments or zones + +## Prerequisites + +- **SDK**: `cre-sdk-go` v1.8.0 or later (report verification support) +- Familiarity with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go) (report structure and JSON payload patterns) +- For HTTP-triggered receivers: [HTTP Trigger configuration](/cre/guides/workflow/using-triggers/http-trigger/configuration-go) + +## Onchain vs offchain verification + +| Aspect | Offchain (`cre.ParseReport`) | Onchain (`KeystoneForwarder`) | +| -------------------- | ------------------------------------------------------------ | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | + +Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. + +Default (`cre.ProductionEnvironment()`): + +- **Chain**: Ethereum Mainnet (chain selector `5009297550715157269`) +- **Registry**: `0x76c9cf548b4179F8901cda1f8623568b58215E62` + +## How verification works + +1. **Parse the report header** from `rawReport` (109-byte metadata + body). +2. **Fetch DON info** from the registry (if not cached): fault tolerance `f` and signer addresses. +3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. +4. **Return a `*cre.Report`** with accessors for workflow ID, owner, execution ID, body, and more. + +If verification fails, `cre.ParseReport()` returns an error (for example, `ErrUnknownSigner`, `ErrWrongSignatureCount`, or registry read failure). + +## Complete example: HTTP receiver workflow + +This workflow accepts a JSON payload (matching the format from [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#pattern-4-json-formatted-report)), verifies it, then processes the trusted body. + +```go +package main + +import ( + "encoding/hex" + "encoding/json" + "log/slog" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/networking/http" + "github.com/smartcontractkit/cre-sdk-go/cre" +) + +type Config struct { + AuthorizedKey string `json:"authorized_key"` +} + +func InitWorkflow(cfg *Config, _ *slog.Logger, _ cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler(http.Trigger(&http.Config{AuthorizedKeys: []*http.AuthorizedKey{{PublicKey: cfg.AuthorizedKey}}}), run), + }, nil +} + +type ParsedPayload struct { + Report string `json:"report"` + Context string `json:"context"` + Sigs []string `json:"signatures"` +} + +func (p *ParsedPayload) Decode() (*DecodedReport, error) { + report := &DecodedReport{} + var err error + + if report.Report, err = hex.DecodeString(p.Report); err != nil { + return nil, err + } + if report.Context, err = hex.DecodeString(p.Context); err != nil { + return nil, err + } + + report.Sigs = make([][]byte, len(p.Sigs)) + for i, sigHex := range p.Sigs { + report.Sigs[i], err = hex.DecodeString(sigHex) + if err != nil { + return nil, err + } + } + + return report, nil +} + +type DecodedReport struct { + Report []byte + Context []byte + Sigs [][]byte +} + +func run(_ *Config, runtime cre.Runtime, payload *http.Payload) (bool, error) { + parsed := &ParsedPayload{} + if err := json.Unmarshal(payload.Input, parsed); err != nil { + return false, err + } + + decoded, err := parsed.Decode() + if err != nil { + return false, err + } + + report, err := cre.ParseReport(runtime, decoded.Report, decoded.Sigs, decoded.Context) + if err != nil { + return false, err + } + + runtime.Logger().Info("Verified report", + "workflowId", report.WorkflowID(), + "executionId", report.ExecutionID(), + ) + + // Use report.Body() for your application logic (ABI-encoded payload from the sender workflow) + _ = report.Body() + + return true, nil +} +``` + +**What's happening:** + +1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. +2. `cre.ParseReport()` verifies signatures against the production CRE registry. +3. On success, you read metadata and `Body()` safely. + +{/* prettier-ignore */} + + +## Report payload format + +Receivers need three fields (plus optional metadata your API may add): + +| Field | Description | +| ------------ | ------------------------------------------------------------------ | +| `report` | Hex-encoded `rawReport` bytes (metadata header + workflow payload) | +| `context` | Hex-encoded `reportContext` (config digest + sequence number) | +| `signatures` | Array of hex-encoded 65-byte ECDSA signatures from DON nodes | + +The `reportContext` layout used by the SDK: + +- Bytes 0–31: config digest +- Bytes 32–39: sequence number (big-endian `uint64`) + +## API reference + +See [SDK Reference: Core — Report verification](/cre/reference/sdk/core-go#report-verification) for full signatures, types, and errors. + +### `cre.ParseReport()` + +```go +func ParseReport(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte) (*Report, error) +``` + +Parses and verifies a report against the production CRE environment. Use `ParseReportWithConfig` for custom environments or zones. + +### `*cre.Report` accessors + +After a successful parse: + +| Method | Description | +| ----------------- | ----------------------------------------- | +| `WorkflowID()` | Workflow hash (`bytes32` as hex) | +| `WorkflowOwner()` | Deployer address (hex) | +| `WorkflowName()` | Workflow name field from metadata | +| `ExecutionID()` | Unique execution identifier | +| `DONID()` | DON that produced the report | +| `Timestamp()` | Report timestamp (Unix seconds) | +| `Body()` | Encoded payload after the 109-byte header | +| `SeqNr()` | Sequence number from report context | +| `ConfigDigest()` | Config digest from report context | + +### `cre.ReportParseConfig` + +```go +config := cre.ReportParseConfig{ + AcceptedZones: []cre.Zone{ + cre.ZoneFromEnvironment(cre.ProductionEnvironment(), 1), + }, + AcceptedEnvironments: []cre.Environment{cre.ProductionEnvironment()}, + SkipSignatureVerification: false, +} +report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext, config) +``` + +| Field | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `AcceptedEnvironments` | Registry environments to check (defaults to production) | +| `AcceptedZones` | Restrict to specific DON IDs within an environment | +| `SkipSignatureVerification` | Parse header only; call `report.VerifySignatures()` or `VerifySignaturesWithConfig()` afterward when ready | + +### Deferred verification + +If you set `SkipSignatureVerification: true` in `ParseReportWithConfig`, parse the header first (for filtering), then verify: + +```go +report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext, cre.ReportParseConfig{ + SkipSignatureVerification: true, +}) +if err != nil { + return false, err +} + +// Optional: inspect report.WorkflowID(), report.DONID(), etc. before registry reads + +if err := report.VerifySignatures(runtime); err != nil { + return false, err +} +``` + +## Best practices + +1. **Verify before side effects**: Call `cre.ParseReport()` before writing to databases, chains, or external systems. +2. **Permission on metadata**: After verification, check `WorkflowID()`, `WorkflowOwner()`, or `DONID()` match your expectations. +3. **Deduplicate by execution ID**: Use `ExecutionID()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#understanding-cachesettings-for-reports)). +4. **Do not skip signature verification in production** unless you have another trust path. + +## Troubleshooting + +**`ErrUnknownSigner`** + +- Signatures may be from a different DON or stale registry config. +- Confirm the sender workflow used production CRE and the report was not tampered with. + +**`ErrWrongSignatureCount`** + +- At least **f+1** valid signatures are required. + +**`could not read from chain ...`** + +- Registry read failed (RPC/network). Retry or check simulation vs production EVM access. + +**`ErrRawReportTooShort`** + +- `rawReport` is missing the 109-byte metadata header. + +## Learn more + +- **[API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http)** — Sender → receiver overview +- **[Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go)** — Sender workflow: create and POST the report +- **[SDK Reference: Core — Report verification](/cre/reference/sdk/core-go#report-verification)** — `ParseReport`, `Report`, and `ReportParseConfig` +- **[HTTP Trigger Overview](/cre/guides/workflow/using-triggers/http-trigger/overview-go)** — Trigger deployed receiver workflows +- **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)** — Onchain forwarder verification path +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** — Permissioning `onReport` with workflow metadata diff --git a/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx new file mode 100644 index 00000000000..4aa4f3e519c --- /dev/null +++ b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx @@ -0,0 +1,257 @@ +--- +section: cre +title: "Verifying CRE Reports Offchain" +date: Last Modified +sdkLang: "ts" +pageId: "guides-workflow-http-verify-reports-offchain" +metadata: + description: "Verify CRE report signatures offchain in TypeScript: parse reports, validate DON signatures against the onchain registry, and read workflow metadata." + datePublished: "2026-05-20" + lastModified: "2026-05-20" +--- + +import { Aside } from "@components" + +This guide is for the **receiver** side: you already received a CRE report package (usually via HTTP) and need to **prove it is authentic** before using the payload. + +When a workflow delivers results via HTTP (or another offchain channel), nothing onchain automatically validates the report. **You must verify signatures before trusting the data.** + +The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. + +{/* prettier-ignore */} + + +{/* prettier-ignore */} + + +## Where this guide fits + +| Question | Answer | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | Same CRE report the **sender** created with `runtime.report()`—not a Data Streams report. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#where-this-guide-fits). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `runtime.report()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 4: `Report.parse()` before you use `body()` or take side effects. | +| Same workflow as the sender? | Often **no**—common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | + +**Receiver flow:** + +1. HTTP trigger (or your API) receives the POST payload. +2. Decode hex fields into bytes. +3. `Report.parse()` — verify signatures and read metadata. +4. Use trusted `body()` in your logic. + +For the full sender → receiver diagram, see [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). + +## What you'll learn + +- When to verify reports offchain vs relying on onchain forwarders +- How `Report.parse()` validates signatures and reads metadata +- How to build a receiver workflow that accepts reports over HTTP +- How to restrict verification to specific CRE environments or zones + +## Prerequisites + +- **SDK**: `@chainlink/cre-sdk` v1.8.0 or later (report verification support) +- Familiarity with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts) (report structure and JSON payload patterns) +- For HTTP-triggered receivers: [HTTP Trigger configuration](/cre/guides/workflow/using-triggers/http-trigger/configuration-ts) + +## Onchain vs offchain verification + +| Aspect | Offchain (`Report.parse`) | Onchain (`KeystoneForwarder`) | +| -------------------- | ------------------------------------------------------------ | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | + +Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. + +Default (`productionEnvironment()`): + +- **Chain**: Ethereum Mainnet (chain selector `5009297550715157269`) +- **Registry**: `0x76c9cf548b4179F8901cda1f8623568b58215E62` + +## How verification works + +1. **Parse the report header** from `rawReport` (109-byte metadata + body). +2. **Fetch DON info** from the registry (if not cached): fault tolerance `f` and signer addresses. +3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. +4. **Return a `Report` object** with accessors for workflow ID, owner, execution ID, body, and more. + +If verification fails, `Report.parse()` throws (for example, unknown signer, insufficient signatures, or registry read failure). + +## Complete example: HTTP receiver workflow + +This workflow accepts a JSON payload (matching the format from [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#pattern-4-json-formatted-report)), verifies it, then processes the trusted body. + +```typescript +import { + HTTPCapability, + handler, + Report, + type HTTPPayload, + type Runtime, + type SecretsProvider, +} from "@chainlink/cre-sdk" +import { hexToBytes } from "viem" +import { z } from "zod" + +export const configSchema = z + .object({ + authorized_key: z.string(), + }) + .transform((data) => ({ + authorizedKey: data.authorized_key, + })) + +export type Config = z.infer + +type ParsedPayload = { + report: string + context: string + signatures: string[] +} + +export async function run(runtime: Runtime, payload: HTTPPayload): Promise { + const parsed: ParsedPayload = JSON.parse(new TextDecoder().decode(payload.input)) + + const rawReport = hexToBytes(`0x${parsed.report}`) + const reportContext = hexToBytes(`0x${parsed.context}`) + const sigs = parsed.signatures.map((s) => hexToBytes(`0x${s}`)) + + const report = await Report.parse(runtime, rawReport, sigs, reportContext) + + runtime.log(`Verified report from workflow ${report.workflowId()}, execution ${report.executionId()}`) + + // Use report.body() for your application logic (ABI-encoded payload from the sender workflow) + void report.body() + + return true +} + +export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) => { + const http = new HTTPCapability() + return [ + handler(http.trigger({ authorizedKeys: [{ type: "KEY_TYPE_ECDSA_EVM", publicKey: config.authorizedKey }] }), run), + ] +} +``` + +**What's happening:** + +1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. +2. `Report.parse()` verifies signatures against the production CRE registry. +3. On success, you read metadata and `body()` safely. + +{/* prettier-ignore */} + + +## Report payload format + +Receivers need three fields (plus optional metadata your API may add): + +| Field | Description | +| ------------ | ------------------------------------------------------------------ | +| `report` | Hex-encoded `rawReport` bytes (metadata header + workflow payload) | +| `context` | Hex-encoded `reportContext` (config digest + sequence number) | +| `signatures` | Array of hex-encoded 65-byte ECDSA signatures from DON nodes | + +The `reportContext` layout used by the SDK: + +- Bytes 0–31: config digest +- Bytes 32–39: sequence number (big-endian `uint64`) + +## API reference + +See [SDK Reference: Core — Report verification](/cre/reference/sdk/core-ts#report-verification) for full signatures, types, and configuration. + +### `Report.parse()` + +```typescript +Report.parse( + runtime: Runtime, + rawReport: Uint8Array, + signatures: Uint8Array[], + reportContext: Uint8Array, + config?: ReportParseConfig, +): Promise +``` + +Parses and verifies a report. Throws if verification fails. + +### `Report` accessors + +After a successful parse: + +| Method | Description | +| ----------------- | ----------------------------------------- | +| `workflowId()` | Workflow hash (`bytes32` as hex) | +| `workflowOwner()` | Deployer address (hex) | +| `workflowName()` | Workflow name field from metadata | +| `executionId()` | Unique execution identifier | +| `donId()` | DON that produced the report | +| `timestamp()` | Report timestamp (Unix seconds) | +| `body()` | Encoded payload after the 109-byte header | +| `seqNr()` | Sequence number from report context | +| `configDigest()` | Config digest from report context | + +### `ReportParseConfig` + +```typescript +import { productionEnvironment, zoneFromEnvironment, type ReportParseConfig } from "@chainlink/cre-sdk" + +const config: ReportParseConfig = { + acceptedZones: [zoneFromEnvironment(productionEnvironment(), 1)], + acceptedEnvironments: [productionEnvironment()], + skipSignatureVerification: false, +} +``` + +| Option | Description | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `acceptedEnvironments` | Registry environments to check (defaults to production) | +| `acceptedZones` | Restrict to specific DON IDs within an environment | +| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript—call `Report.parse()` without this flag for production verification. | + +Most workflows should use the default config (production environment only). + +## Best practices + +1. **Verify before side effects**: Call `Report.parse()` before writing to databases, chains, or external systems. +2. **Permission on metadata**: After verification, check `workflowId()`, `workflowOwner()`, or `donId()` match your expectations. +3. **Deduplicate by execution ID**: Use `executionId()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#understanding-cachesettings-for-reports)). +4. **Do not skip signature verification in production** unless you have another trust path. + +## Troubleshooting + +**`invalid signature` / `unknown signer`** + +- Signatures may be from a different DON or stale registry config. +- Confirm the sender workflow used production CRE and the report was not tampered with. + +**`wrong number of signatures`** + +- At least **f+1** valid signatures are required. Extra invalid signatures are skipped; too few valid ones fails verification. + +**`could not read from chain ...`** + +- Registry read failed (RPC/network). Retry or check simulation vs production EVM access. + +**`raw report too short`** + +- `rawReport` is missing the 109-byte metadata header. + +## Learn more + +- **[API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http)** — Sender → receiver overview +- **[Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts)** — Sender workflow: create and POST the report +- **[SDK Reference: Core — Report verification](/cre/reference/sdk/core-ts#report-verification)** — `Report.parse`, accessors, and `ReportParseConfig` +- **[HTTP Trigger Overview](/cre/guides/workflow/using-triggers/http-trigger/overview-ts)** — Trigger deployed receiver workflows +- **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain-ts)** — Onchain forwarder verification path +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts-ts)** — Permissioning `onReport` with workflow metadata diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt index c4ba2c00ff9..311ef505e98 100644 --- a/src/content/cre/llms-full-go.txt +++ b/src/content/cre/llms-full-go.txt @@ -3770,7 +3770,9 @@ writePromise := reserveManager.WriteReportFromUpdateReserves(runtime, updateData Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values Last Updated: 2025-11-04 -This guide shows how to manually generate a report containing a single value (like `uint256`, `address`, or `bool`). This is useful when you need to send a simple value onchain but don't have a struct or binding helper available. +This guide shows how to manually generate a **CRE report** containing a single value (like `uint256`, `address`, or `bool`). A CRE report is a DON-signed package from `runtime.GenerateReport()` / `runtime.report()`—your encoded data plus workflow metadata and signatures. It is **not** a [Data Streams](/data-streams) report. + +This guide covers **creating** the report (step 2 in the sender flow). **Delivering** it is a separate step—see the table below. **Use this approach when:** @@ -3790,10 +3792,12 @@ Manually generating a report for a single value involves two main steps: 1. **ABI-encode the value** into bytes using the `go-ethereum/accounts/abi` package 2. **Generate a cryptographically signed report** using `runtime.GenerateReport()` -The resulting report can then be: +| After `GenerateReport()` / `report()` | Guide | Who verifies? | +| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | +| `evm.Client.WriteReport()` / `writeReport()` | [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | `KeystoneForwarder` onchain | +| `http.Client` `SendReport()` | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) | Receiver: [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) or your API | -- Submitted to the blockchain via `evm.Client.WriteReport()` (see [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)) -- Sent to an HTTP endpoint via `http.Client` (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http)) +See [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver mental model. +## Report verification + +Parse and verify CRE reports received over HTTP or other offchain channels. Requires **cre-sdk-go v1.8.0** or later. + + + + +Verification runs in your callback: signatures are checked offchain, while authorized signers are loaded from the onchain **Capability Registry** (default: `cre.ProductionEnvironment()` on Ethereum Mainnet). This is not the workflow deployment registry (`private` or onchain). + +### `cre.ParseReport` + +**Signature:** + +```go +func ParseReport(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte) (*Report, error) +``` + +Parses a report and verifies signatures against `cre.ProductionEnvironment()`. Registry reads are cached per chain and DON. + +### `cre.ParseReportWithConfig` + +**Signature:** + +```go +func ParseReportWithConfig(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte, config ReportParseConfig) (*Report, error) +``` + +Same as `ParseReport`, with custom accepted environments or zones. Set `SkipSignatureVerification: true` to parse metadata only; call `report.VerifySignatures()` afterward when ready. + +### `Report` accessors + +After a successful parse: + +| Method | Returns | Description | +| ----------------- | -------- | ------------------------------------------ | +| `WorkflowID()` | `string` | Workflow hash (hex) | +| `WorkflowOwner()` | `string` | Workflow owner (hex) | +| `WorkflowName()` | `string` | Workflow name from metadata | +| `ExecutionID()` | `string` | Execution identifier (hex) | +| `DONID()` | `uint32` | DON that produced the report | +| `Body()` | `[]byte` | Payload after the 109-byte metadata header | +| `SeqNr()` | `uint64` | Sequence number | +| `ConfigDigest()` | `[]byte` | Config digest | +| `ReportContext()` | `[]byte` | Full report context bytes | +| `RawReport()` | `[]byte` | Full raw report bytes | + +### `ReportParseConfig` + +| Field | Type | Description | +| --------------------------- | --------------- | ----------------------------------------------------- | +| `AcceptedEnvironments` | `[]Environment` | Registry environments to try (defaults to production) | +| `AcceptedZones` | `[]Zone` | Restrict verification to specific DON IDs | +| `SkipSignatureVerification` | `bool` | Parse header only; call `VerifySignatures` separately | + +### `cre.ProductionEnvironment` and `cre.ZoneFromEnvironment` + +```go +func ProductionEnvironment() Environment // mainnet Capability Registry +func ZoneFromEnvironment(env Environment, donId uint32) Zone +``` + +| `Environment` field | Type | Description | +| ------------------- | -------- | -------------------------------------------------------- | +| `ChainSelector` | `uint64` | Chain selector for EVM reads (default: Ethereum Mainnet) | +| `RegistryAddress` | `string` | Capability Registry contract address | + +### Verification errors + +| Error | When | +| ------------------------ | -------------------------------------------- | +| `ErrUnknownSigner` | Recovered signer not in registry allowlist | +| `ErrWrongSignatureCount` | Fewer than f+1 valid signatures | +| `ErrRawReportTooShort` | `rawReport` missing 109-byte metadata header | +| `ErrDuplicateSigner` | Same signer twice in accepted set | + ## `cre.OrderedEntries` and `cre.OrderedEntriesFunc` Go maps iterate in random order, which causes consensus failures in DON mode because different nodes process entries in different sequences. These helpers return a deterministic iterator over a map's entries, sorted by key, so all nodes process items in the same order. @@ -18629,15 +19068,17 @@ The HTTP Client lets you make requests to external APIs from your workflow. Each - Fetching data from REST APIs ([GET requests](/cre/guides/workflow/using-http-client/get-request)) - Sending data to webhooks ([POST requests](/cre/guides/workflow/using-http-client/post-request)) - Submitting reports to offchain systems ([Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http)) +- Verifying reports received over HTTP ([Report verification](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go)) ## Quick reference -| Method | Use When | Guide | -| ------------------------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| [`http.SendRequest`](#httpsendrequest) | Making HTTP calls (recommended) | [GET](/cre/guides/workflow/using-http-client/get-request) / [POST](/cre/guides/workflow/using-http-client/post-request) | -| [`client.SendRequest`](#clientsendrequest) | Complex scenarios requiring fine control | [GET](/cre/guides/workflow/using-http-client/get-request#2-the-creruninnodemode-pattern-low-level) | -| [`sendRequester.SendReport`](#sendrequestersendreport) | Submitting reports via HTTP (recommended) | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http) | -| [`client.SendReport`](#clientsendreport) | Complex report submission scenarios | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http#advanced-low-level-pattern) | +| Method | Use When | Guide | +| ------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [`http.SendRequest`](#httpsendrequest) | Making HTTP calls (recommended) | [GET](/cre/guides/workflow/using-http-client/get-request) / [POST](/cre/guides/workflow/using-http-client/post-request) | +| [`client.SendRequest`](#clientsendrequest) | Complex scenarios requiring fine control | [GET](/cre/guides/workflow/using-http-client/get-request#2-the-creruninnodemode-pattern-low-level) | +| [`sendRequester.SendReport`](#sendrequestersendreport) | Submitting reports via HTTP (recommended) | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http) | +| [`client.SendReport`](#clientsendreport) | Complex report submission scenarios | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http#advanced-low-level-pattern) | +| [`cre.ParseReport`](/cre/reference/sdk/core-go#report-verification) | Verifying received reports (receiver) | [Report verification](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go) | ## Core types @@ -19009,6 +19450,11 @@ func formatReport(r *sdk.ReportResponse) (*http.Request, error) { For complete examples of including signatures in different formats (body, headers, JSON), see the [Submitting Reports via HTTP guide](/cre/guides/workflow/using-http-client/submitting-reports-http#formatting-patterns). + + + --- # SDK Reference @@ -19021,7 +19467,7 @@ This section provides a detailed technical reference for the public interfaces o The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.Handler`, `cre.Runtime`, `cre.Promise`, and map iteration helpers `cre.OrderedEntries` / `cre.OrderedEntriesFunc`. +- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.Handler`, `cre.Runtime`, `cre.Promise`, report verification (`cre.ParseReport`), and map iteration helpers `cre.OrderedEntries` / `cre.OrderedEntriesFunc`. - **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `evm.Client`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `http.Client`, used for making offchain API requests from individual nodes. diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index f63f5974f4d..81209ecf093 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -4030,7 +4030,7 @@ if (writeResult.txStatus === TxStatus.SUCCESS) { # API Interactions Source: https://docs.chain.link/cre/guides/workflow/using-http-client -Last Updated: 2026-03-17 +Last Updated: 2026-05-20 The CRE SDK provides an HTTP client that allows your workflows to interact with external APIs. Use it to fetch offchain data, send results to other systems, or trigger external events. @@ -4046,11 +4046,40 @@ The CRE SDK provides an HTTP client that allows your workflows to interact with These guides will walk you through the common use cases for the HTTP client. +## CRE reports over HTTP + +A **CRE report** is a DON-signed package your workflow creates with `runtime.report()` (TypeScript) or `runtime.GenerateReport()` (Go). It contains your encoded payload, workflow metadata, and cryptographic signatures. It is **not** a [Data Streams](/data-streams) report—those come from a different product. + +Most secure HTTP integrations use two roles: + +```mermaid +flowchart LR + subgraph sender ["Sender workflow (this guide's focus)"] + A[Trigger] --> B[Your logic] + B --> C["runtime.report()"] + C --> D["sendReport() → HTTP POST"] + end + subgraph receiver ["Receiver (separate system)"] + D --> E[Your API or CRE HTTP trigger] + E --> F["Report.parse() before trusting data"] + end +``` + +| Step | Who | What happens | +| ---- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | **Sender** (CRE workflow) | Run business logic, encode payload | +| 2 | **Sender** | `runtime.report()` — DON agrees and signs | +| 3 | **Sender** | `sendReport()` — POST report bytes to your URL | +| 4 | **Receiver** | Verify signatures, then use payload — see [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) | + +You do **not** download a report from elsewhere before submitting. The sender workflow **creates** it in step 2. Validation always happens on the **receiver** side (CRE workflow, your API, or an onchain forwarder). + ## Guides - **[Making GET Requests](/cre/guides/workflow/using-http-client/get-request)**: Learn how to fetch data from a public API using a `GET` request. - **[Making POST Requests](/cre/guides/workflow/using-http-client/post-request)**: Learn how to send data to an external endpoint using a `POST` request. - **[Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http)**: Learn how to submit cryptographically signed reports to an external HTTP endpoint. +- **[Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain)**: Verify report signatures and read workflow metadata when receiving reports over HTTP or other offchain channels. --- @@ -13988,6 +14017,17 @@ Here's the journey your workflow's data takes to reach the blockchain: In your workflow code, this process involves two steps: calling `runtime.report()` to generate the signed report, then calling `evmClient.writeReport()` to submit it to the blockchain. +### Where reports can go after generation + +The same signed report from `runtime.report()` can be delivered in different ways: + +| Destination | Guide | Verification | +| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Smart contract (via Forwarder) | This section + [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | Onchain in `KeystoneForwarder` | +| HTTP API | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts) | [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts) on the receiver | + +See [CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver flow. CRE reports are not [Data Streams](/data-streams) reports. + ## What you need: A consumer contract Before you can write data onchain, you need a **consumer contract**. This is the smart contract that will receive your workflow's data. @@ -14977,9 +15017,9 @@ export async function main() { # Submitting Reports via HTTP Source: https://docs.chain.link/cre/guides/workflow/using-http-client/submitting-reports-http-ts -Last Updated: 2026-01-20 +Last Updated: 2026-05-20 -This guide shows how to send a cryptographically signed report (generated by your workflow) to an external HTTP API. You'll learn how to write a transformation function that formats the report for your specific API's requirements. +This guide is for the **sender** side: a CRE workflow that **creates** a signed report and **POSTs** it to an HTTP endpoint. **What you'll learn:** @@ -14992,6 +15032,24 @@ This guide shows how to send a cryptographically signed report (generated by you This guide covers HTTP submission. For submitting reports to smart contracts, see [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). +## Where this guide fits + +| Question | Answer | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | Output of `runtime.report()` after your workflow DON reaches consensus: encoded payload + metadata + signatures. Not a Data Streams report. | +| Where does it come from? | **Inside this workflow**—after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | +| What does this guide cover? | Steps 2–3: generate the report, then `sendReport()` to your API. | +| Who verifies it? | The **receiver**—your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). | + +**Sender flow in one workflow execution:** + +1. Trigger fires (cron, HTTP, …). +2. Your callback runs (API calls, encoding, etc.). +3. `runtime.report()` — DON produces a signed `ReportResponse`. +4. `sendReport()` — format and POST to your URL. + +For a conceptual overview and diagram, see [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). + ## Prerequisites - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) @@ -15527,15 +15585,13 @@ const onCronTrigger = (runtime: Runtime): MyResult => { 1. **Always use `cacheSettings`**: Include caching in every transformation function to prevent worst-case duplicate submission scenarios 2. **Implement API-side deduplication**: Your receiving API must implement deduplication using the **hash of the report** (`keccak256(rawReport)`) to detect and reject duplicate submissions -3. **Verify signatures before processing**: Your API must verify the cryptographic signatures against DON public keys before trusting report data (see note below about signature verification) +3. **Verify on the receiver**: The sender does not validate the report—your API or a [receiver CRE workflow](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts) must verify before trusting payload data 4. **Match your API's format exactly**: Study your API's documentation to understand the expected format (binary, JSON, headers, etc.) 5. **Handle errors gracefully**: Check HTTP status codes and provide meaningful error messages ## Troubleshooting @@ -15553,6 +15609,8 @@ const onCronTrigger = (runtime: Runtime): MyResult => { ## Learn more +- **[API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http)** — Sender → receiver overview +- **[Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts)** — Receiver workflow: verify before trusting payload - **[HTTP Client SDK Reference](/cre/reference/sdk/http-client-ts)** — Complete API reference including `sendReport()` and `ReportResponse` - **[POST Requests](/cre/guides/workflow/using-http-client/post-request)** — Learn about HTTP request patterns and caching - **[Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain)** — Detailed guide on encoding single values, structs, and complex types using Viem @@ -15560,6 +15618,256 @@ const onCronTrigger = (runtime: Runtime): MyResult => { --- +# Verifying CRE Reports Offchain +Source: https://docs.chain.link/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts +Last Updated: 2026-05-20 + +This guide is for the **receiver** side: you already received a CRE report package (usually via HTTP) and need to **prove it is authentic** before using the payload. + +When a workflow delivers results via HTTP (or another offchain channel), nothing onchain automatically validates the report. **You must verify signatures before trusting the data.** + +The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. + + + + + + + +## Where this guide fits + +| Question | Answer | +| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | Same CRE report the **sender** created with `runtime.report()`—not a Data Streams report. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#where-this-guide-fits). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `runtime.report()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 4: `Report.parse()` before you use `body()` or take side effects. | +| Same workflow as the sender? | Often **no**—common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | + +**Receiver flow:** + +1. HTTP trigger (or your API) receives the POST payload. +2. Decode hex fields into bytes. +3. `Report.parse()` — verify signatures and read metadata. +4. Use trusted `body()` in your logic. + +For the full sender → receiver diagram, see [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). + +## What you'll learn + +- When to verify reports offchain vs relying on onchain forwarders +- How `Report.parse()` validates signatures and reads metadata +- How to build a receiver workflow that accepts reports over HTTP +- How to restrict verification to specific CRE environments or zones + +## Prerequisites + +- **SDK**: `@chainlink/cre-sdk` v1.8.0 or later (report verification support) +- Familiarity with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts) (report structure and JSON payload patterns) +- For HTTP-triggered receivers: [HTTP Trigger configuration](/cre/guides/workflow/using-triggers/http-trigger/configuration-ts) + +## Onchain vs offchain verification + +| Aspect | Offchain (`Report.parse`) | Onchain (`KeystoneForwarder`) | +| -------------------- | ------------------------------------------------------------ | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | + +Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. + +Default (`productionEnvironment()`): + +- **Chain**: Ethereum Mainnet (chain selector `5009297550715157269`) +- **Registry**: `0x76c9cf548b4179F8901cda1f8623568b58215E62` + +## How verification works + +1. **Parse the report header** from `rawReport` (109-byte metadata + body). +2. **Fetch DON info** from the registry (if not cached): fault tolerance `f` and signer addresses. +3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. +4. **Return a `Report` object** with accessors for workflow ID, owner, execution ID, body, and more. + +If verification fails, `Report.parse()` throws (for example, unknown signer, insufficient signatures, or registry read failure). + +## Complete example: HTTP receiver workflow + +This workflow accepts a JSON payload (matching the format from [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#pattern-4-json-formatted-report)), verifies it, then processes the trusted body. + +```typescript +import { + HTTPCapability, + handler, + Report, + type HTTPPayload, + type Runtime, + type SecretsProvider, +} from "@chainlink/cre-sdk" +import { hexToBytes } from "viem" +import { z } from "zod" + +export const configSchema = z + .object({ + authorized_key: z.string(), + }) + .transform((data) => ({ + authorizedKey: data.authorized_key, + })) + +export type Config = z.infer + +type ParsedPayload = { + report: string + context: string + signatures: string[] +} + +export async function run(runtime: Runtime, payload: HTTPPayload): Promise { + const parsed: ParsedPayload = JSON.parse(new TextDecoder().decode(payload.input)) + + const rawReport = hexToBytes(`0x${parsed.report}`) + const reportContext = hexToBytes(`0x${parsed.context}`) + const sigs = parsed.signatures.map((s) => hexToBytes(`0x${s}`)) + + const report = await Report.parse(runtime, rawReport, sigs, reportContext) + + runtime.log(`Verified report from workflow ${report.workflowId()}, execution ${report.executionId()}`) + + // Use report.body() for your application logic (ABI-encoded payload from the sender workflow) + void report.body() + + return true +} + +export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) => { + const http = new HTTPCapability() + return [ + handler(http.trigger({ authorizedKeys: [{ type: "KEY_TYPE_ECDSA_EVM", publicKey: config.authorizedKey }] }), run), + ] +} +``` + +**What's happening:** + +1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. +2. `Report.parse()` verifies signatures against the production CRE registry. +3. On success, you read metadata and `body()` safely. + + + + +## Report payload format + +Receivers need three fields (plus optional metadata your API may add): + +| Field | Description | +| ------------ | ------------------------------------------------------------------ | +| `report` | Hex-encoded `rawReport` bytes (metadata header + workflow payload) | +| `context` | Hex-encoded `reportContext` (config digest + sequence number) | +| `signatures` | Array of hex-encoded 65-byte ECDSA signatures from DON nodes | + +The `reportContext` layout used by the SDK: + +- Bytes 0–31: config digest +- Bytes 32–39: sequence number (big-endian `uint64`) + +## API reference + +See [SDK Reference: Core — Report verification](/cre/reference/sdk/core-ts#report-verification) for full signatures, types, and configuration. + +### `Report.parse()` + +```typescript +Report.parse( + runtime: Runtime, + rawReport: Uint8Array, + signatures: Uint8Array[], + reportContext: Uint8Array, + config?: ReportParseConfig, +): Promise +``` + +Parses and verifies a report. Throws if verification fails. + +### `Report` accessors + +After a successful parse: + +| Method | Description | +| ----------------- | ----------------------------------------- | +| `workflowId()` | Workflow hash (`bytes32` as hex) | +| `workflowOwner()` | Deployer address (hex) | +| `workflowName()` | Workflow name field from metadata | +| `executionId()` | Unique execution identifier | +| `donId()` | DON that produced the report | +| `timestamp()` | Report timestamp (Unix seconds) | +| `body()` | Encoded payload after the 109-byte header | +| `seqNr()` | Sequence number from report context | +| `configDigest()` | Config digest from report context | + +### `ReportParseConfig` + +```typescript +import { productionEnvironment, zoneFromEnvironment, type ReportParseConfig } from "@chainlink/cre-sdk" + +const config: ReportParseConfig = { + acceptedZones: [zoneFromEnvironment(productionEnvironment(), 1)], + acceptedEnvironments: [productionEnvironment()], + skipSignatureVerification: false, +} +``` + +| Option | Description | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `acceptedEnvironments` | Registry environments to check (defaults to production) | +| `acceptedZones` | Restrict to specific DON IDs within an environment | +| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript—call `Report.parse()` without this flag for production verification. | + +Most workflows should use the default config (production environment only). + +## Best practices + +1. **Verify before side effects**: Call `Report.parse()` before writing to databases, chains, or external systems. +2. **Permission on metadata**: After verification, check `workflowId()`, `workflowOwner()`, or `donId()` match your expectations. +3. **Deduplicate by execution ID**: Use `executionId()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#understanding-cachesettings-for-reports)). +4. **Do not skip signature verification in production** unless you have another trust path. + +## Troubleshooting + +**`invalid signature` / `unknown signer`** + +- Signatures may be from a different DON or stale registry config. +- Confirm the sender workflow used production CRE and the report was not tampered with. + +**`wrong number of signatures`** + +- At least **f+1** valid signatures are required. Extra invalid signatures are skipped; too few valid ones fails verification. + +**`could not read from chain ...`** + +- Registry read failed (RPC/network). Retry or check simulation vs production EVM access. + +**`raw report too short`** + +- `rawReport` is missing the 109-byte metadata header. + +## Learn more + +- **[API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http)** — Sender → receiver overview +- **[Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts)** — Sender workflow: create and POST the report +- **[SDK Reference: Core — Report verification](/cre/reference/sdk/core-ts#report-verification)** — `Report.parse`, accessors, and `ReportParseConfig` +- **[HTTP Trigger Overview](/cre/guides/workflow/using-triggers/http-trigger/overview-ts)** — Trigger deployed receiver workflows +- **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain-ts)** — Onchain forwarder verification path +- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts-ts)** — Permissioning `onReport` with workflow metadata + +--- + # Cron Trigger Source: https://docs.chain.link/cre/guides/workflow/using-triggers/cron-trigger-ts Last Updated: 2026-01-20 @@ -17868,7 +18176,7 @@ If all nodes fail or consensus cannot be reached, the default value (`0n` in thi # SDK Reference: Core Source: https://docs.chain.link/cre/reference/sdk/core-ts -Last Updated: 2026-01-20 +Last Updated: 2026-05-20 This page provides a reference for the core data structures and functions of the CRE TypeScript SDK. These are the fundamental building blocks that every workflow uses, regardless of trigger types or capabilities. @@ -17965,7 +18273,7 @@ Both `Runtime` and `NodeRuntime` provide: - **`runInNodeMode(...)`**: Execute code on individual nodes with consensus aggregation - **`getSecret(...)`**: Access to workflow secrets -- **`report(...)`**: Generate cryptographically signed reports +- **`report(...)`**: Generate cryptographically signed reports. To verify received reports, use [`Report.parse()`](#report-verification). ### Logging @@ -18400,6 +18708,72 @@ const onTrigger = (runtime: Runtime): string => { For a complete walkthrough on creating, storing, and using secrets, see the [Secrets guide](/cre/guides/workflow/secrets). +## Report verification + +Parse and verify CRE reports received over HTTP or other offchain channels. Requires **`@chainlink/cre-sdk` v1.8.0** or later. + + + + +Verification runs in your callback: signatures are checked offchain, while authorized signers are loaded from the onchain **Capability Registry** (default: `productionEnvironment()` on Ethereum Mainnet). This is not the workflow deployment registry (`private` or onchain). + +Import from `@chainlink/cre-sdk`: `Report`, `productionEnvironment`, `zoneFromEnvironment`, and `ReportParseConfig`. + +### `Report.parse()` + +**Signature:** + +```typescript +Report.parse( + runtime: Runtime, + rawReport: Uint8Array, + signatures: Uint8Array[], + reportContext: Uint8Array, + config?: ReportParseConfig, +): Promise +``` + +Parses a report and verifies signatures. Throws on failure. Registry reads are cached per chain and DON. + +### `Report` accessors + +After a successful parse: + +| Method | Returns | Description | +| ----------------- | ------------ | ------------------------------------------ | +| `workflowId()` | `string` | Workflow hash (hex) | +| `workflowOwner()` | `string` | Workflow owner (hex) | +| `workflowName()` | `string` | Workflow name from metadata | +| `executionId()` | `string` | Execution identifier (hex) | +| `donId()` | `number` | DON that produced the report | +| `body()` | `Uint8Array` | Payload after the 109-byte metadata header | +| `seqNr()` | `bigint` | Sequence number | +| `configDigest()` | `Uint8Array` | Config digest | +| `reportContext()` | `Uint8Array` | Full report context bytes | +| `rawReport()` | `Uint8Array` | Full raw report bytes | + +### `ReportParseConfig` + +| Field | Type | Description | +| --------------------------- | --------------- | ------------------------------------------------------------------ | +| `acceptedEnvironments` | `Environment[]` | Registry environments to try (defaults to production) | +| `acceptedZones` | `Zone[]` | Restrict verification to specific DON IDs | +| `skipSignatureVerification` | `boolean` | Parse metadata only; not for production without another trust path | + +### `productionEnvironment()` and `zoneFromEnvironment()` + +```typescript +function productionEnvironment(): Environment +function zoneFromEnvironment(environment: Environment, donID: number): Zone +``` + +| `Environment` field | Type | Description | +| ------------------- | -------- | -------------------------------------------------------- | +| `chainSelector` | `bigint` | Chain selector for EVM reads (default: Ethereum Mainnet) | +| `registryAddress` | `string` | Capability Registry contract address | + --- # SDK Reference: EVM Client @@ -19374,7 +19748,7 @@ Because it operates at the node level, all HTTP requests are wrapped in a consen - **[High-level (recommended)](#high-level-sendrequest-recommended):** Automatically wraps your request in the `runtime.runInNodeMode()` pattern with consensus aggregation. - **[Low-level](#low-level-sendrequest):** Requires manual wrapping in a `runtime.runInNodeMode()` block for complex scenarios. -For complete step-by-step examples, see the [GET requests](/cre/guides/workflow/using-http-client/get-request) and [POST requests](/cre/guides/workflow/using-http-client/post-request) guides. +For complete step-by-step examples, see the [GET requests](/cre/guides/workflow/using-http-client/get-request) and [POST requests](/cre/guides/workflow/using-http-client/post-request) guides. To **submit** signed reports, see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts). To **verify** received reports, see [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) and [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). ## High-level `sendRequest()` (recommended) @@ -19510,6 +19884,11 @@ const submitReport = (sendRequester: HTTPSendRequester, report: Report): string } ``` + + + ## Low-level `sendRequest()` The low-level `sendRequest()` method requires manual wrapping in a `runtime.runInNodeMode()` block. It provides more flexibility for complex scenarios but requires more boilerplate code. @@ -20016,7 +20395,7 @@ This section provides a detailed technical reference for the public interfaces o The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, and the `.result()` pattern for promise resolution. +- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, report verification (`Report.parse`), and the `.result()` pattern for promise resolution. - **[Triggers](/cre/reference/sdk/triggers/overview-ts)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client-ts)**: Provides a reference for the `EVMClient`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client-ts)**: Provides a reference for the `HTTPClient`, used for making offchain API requests from individual nodes. diff --git a/src/content/cre/reference/sdk/core-go.mdx b/src/content/cre/reference/sdk/core-go.mdx index 8e324138bee..df48dc5c80e 100644 --- a/src/content/cre/reference/sdk/core-go.mdx +++ b/src/content/cre/reference/sdk/core-go.mdx @@ -5,9 +5,9 @@ date: Last Modified sdkLang: "go" pageId: "reference-sdk-core" metadata: - description: "Reference for core Go SDK: Workflow, Handler, Runtime, NodeRuntime, and essential functions every CRE workflow uses." + description: "Reference for core Go SDK: Workflow, Handler, Runtime, NodeRuntime, report verification (ParseReport), and essential functions every CRE workflow uses." datePublished: "2025-11-04" - lastModified: "2026-04-20" + lastModified: "2026-05-20" --- import { Aside } from "@components" @@ -321,6 +321,83 @@ func onTrigger(config *Config, runtime cre.Runtime, ...) (string, error) { guide](/cre/guides/workflow/secrets). +## Report verification + +Parse and verify CRE reports received over HTTP or other offchain channels. Requires **cre-sdk-go v1.8.0** or later. + +{/* prettier-ignore */} + + +Verification runs in your callback: signatures are checked offchain, while authorized signers are loaded from the onchain **Capability Registry** (default: `cre.ProductionEnvironment()` on Ethereum Mainnet). This is not the workflow deployment registry (`private` or onchain). + +### `cre.ParseReport` + +**Signature:** + +```go +func ParseReport(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte) (*Report, error) +``` + +Parses a report and verifies signatures against `cre.ProductionEnvironment()`. Registry reads are cached per chain and DON. + +### `cre.ParseReportWithConfig` + +**Signature:** + +```go +func ParseReportWithConfig(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte, config ReportParseConfig) (*Report, error) +``` + +Same as `ParseReport`, with custom accepted environments or zones. Set `SkipSignatureVerification: true` to parse metadata only; call `report.VerifySignatures()` afterward when ready. + +### `Report` accessors + +After a successful parse: + +| Method | Returns | Description | +| ----------------- | -------- | ------------------------------------------ | +| `WorkflowID()` | `string` | Workflow hash (hex) | +| `WorkflowOwner()` | `string` | Workflow owner (hex) | +| `WorkflowName()` | `string` | Workflow name from metadata | +| `ExecutionID()` | `string` | Execution identifier (hex) | +| `DONID()` | `uint32` | DON that produced the report | +| `Body()` | `[]byte` | Payload after the 109-byte metadata header | +| `SeqNr()` | `uint64` | Sequence number | +| `ConfigDigest()` | `[]byte` | Config digest | +| `ReportContext()` | `[]byte` | Full report context bytes | +| `RawReport()` | `[]byte` | Full raw report bytes | + +### `ReportParseConfig` + +| Field | Type | Description | +| --------------------------- | --------------- | ----------------------------------------------------- | +| `AcceptedEnvironments` | `[]Environment` | Registry environments to try (defaults to production) | +| `AcceptedZones` | `[]Zone` | Restrict verification to specific DON IDs | +| `SkipSignatureVerification` | `bool` | Parse header only; call `VerifySignatures` separately | + +### `cre.ProductionEnvironment` and `cre.ZoneFromEnvironment` + +```go +func ProductionEnvironment() Environment // mainnet Capability Registry +func ZoneFromEnvironment(env Environment, donId uint32) Zone +``` + +| `Environment` field | Type | Description | +| ------------------- | -------- | -------------------------------------------------------- | +| `ChainSelector` | `uint64` | Chain selector for EVM reads (default: Ethereum Mainnet) | +| `RegistryAddress` | `string` | Capability Registry contract address | + +### Verification errors + +| Error | When | +| ------------------------ | -------------------------------------------- | +| `ErrUnknownSigner` | Recovered signer not in registry allowlist | +| `ErrWrongSignatureCount` | Fewer than f+1 valid signatures | +| `ErrRawReportTooShort` | `rawReport` missing 109-byte metadata header | +| `ErrDuplicateSigner` | Same signer twice in accepted set | + ## `cre.OrderedEntries` and `cre.OrderedEntriesFunc` Go maps iterate in random order, which causes consensus failures in DON mode because different nodes process entries in different sequences. These helpers return a deterministic iterator over a map's entries, sorted by key, so all nodes process items in the same order. diff --git a/src/content/cre/reference/sdk/core-ts.mdx b/src/content/cre/reference/sdk/core-ts.mdx index 5b7cb3edeff..51e4ae7a929 100644 --- a/src/content/cre/reference/sdk/core-ts.mdx +++ b/src/content/cre/reference/sdk/core-ts.mdx @@ -5,9 +5,9 @@ date: Last Modified sdkLang: "ts" pageId: "reference-sdk-core" metadata: - description: "Reference for core TypeScript SDK: Workflow, Handler, Runtime, and essential functions every CRE workflow uses." + description: "Reference for core TypeScript SDK: Workflow, Handler, Runtime, report verification (Report.parse), and essential functions every CRE workflow uses." datePublished: "2025-11-04" - lastModified: "2026-01-20" + lastModified: "2026-05-20" --- import { Aside } from "@components" @@ -107,7 +107,7 @@ Both `Runtime` and `NodeRuntime` provide: - **`runInNodeMode(...)`**: Execute code on individual nodes with consensus aggregation - **`getSecret(...)`**: Access to workflow secrets -- **`report(...)`**: Generate cryptographically signed reports +- **`report(...)`**: Generate cryptographically signed reports. To verify received reports, use [`Report.parse()`](#report-verification). ### Logging @@ -542,3 +542,69 @@ const onTrigger = (runtime: Runtime): string => { + +## Report verification + +Parse and verify CRE reports received over HTTP or other offchain channels. Requires **`@chainlink/cre-sdk` v1.8.0** or later. + +{/* prettier-ignore */} + + +Verification runs in your callback: signatures are checked offchain, while authorized signers are loaded from the onchain **Capability Registry** (default: `productionEnvironment()` on Ethereum Mainnet). This is not the workflow deployment registry (`private` or onchain). + +Import from `@chainlink/cre-sdk`: `Report`, `productionEnvironment`, `zoneFromEnvironment`, and `ReportParseConfig`. + +### `Report.parse()` + +**Signature:** + +```typescript +Report.parse( + runtime: Runtime, + rawReport: Uint8Array, + signatures: Uint8Array[], + reportContext: Uint8Array, + config?: ReportParseConfig, +): Promise +``` + +Parses a report and verifies signatures. Throws on failure. Registry reads are cached per chain and DON. + +### `Report` accessors + +After a successful parse: + +| Method | Returns | Description | +| ----------------- | ------------ | ------------------------------------------ | +| `workflowId()` | `string` | Workflow hash (hex) | +| `workflowOwner()` | `string` | Workflow owner (hex) | +| `workflowName()` | `string` | Workflow name from metadata | +| `executionId()` | `string` | Execution identifier (hex) | +| `donId()` | `number` | DON that produced the report | +| `body()` | `Uint8Array` | Payload after the 109-byte metadata header | +| `seqNr()` | `bigint` | Sequence number | +| `configDigest()` | `Uint8Array` | Config digest | +| `reportContext()` | `Uint8Array` | Full report context bytes | +| `rawReport()` | `Uint8Array` | Full raw report bytes | + +### `ReportParseConfig` + +| Field | Type | Description | +| --------------------------- | --------------- | ------------------------------------------------------------------ | +| `acceptedEnvironments` | `Environment[]` | Registry environments to try (defaults to production) | +| `acceptedZones` | `Zone[]` | Restrict verification to specific DON IDs | +| `skipSignatureVerification` | `boolean` | Parse metadata only; not for production without another trust path | + +### `productionEnvironment()` and `zoneFromEnvironment()` + +```typescript +function productionEnvironment(): Environment +function zoneFromEnvironment(environment: Environment, donID: number): Zone +``` + +| `Environment` field | Type | Description | +| ------------------- | -------- | -------------------------------------------------------- | +| `chainSelector` | `bigint` | Chain selector for EVM reads (default: Ethereum Mainnet) | +| `registryAddress` | `string` | Capability Registry contract address | diff --git a/src/content/cre/reference/sdk/http-client-go.mdx b/src/content/cre/reference/sdk/http-client-go.mdx index 2db1b44cf90..4e46e4be51a 100644 --- a/src/content/cre/reference/sdk/http-client-go.mdx +++ b/src/content/cre/reference/sdk/http-client-go.mdx @@ -19,15 +19,17 @@ The HTTP Client lets you make requests to external APIs from your workflow. Each - Fetching data from REST APIs ([GET requests](/cre/guides/workflow/using-http-client/get-request)) - Sending data to webhooks ([POST requests](/cre/guides/workflow/using-http-client/post-request)) - Submitting reports to offchain systems ([Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http)) +- Verifying reports received over HTTP ([Report verification](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go)) ## Quick reference -| Method | Use When | Guide | -| ------------------------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -| [`http.SendRequest`](#httpsendrequest) | Making HTTP calls (recommended) | [GET](/cre/guides/workflow/using-http-client/get-request) / [POST](/cre/guides/workflow/using-http-client/post-request) | -| [`client.SendRequest`](#clientsendrequest) | Complex scenarios requiring fine control | [GET](/cre/guides/workflow/using-http-client/get-request#2-the-creruninnodemode-pattern-low-level) | -| [`sendRequester.SendReport`](#sendrequestersendreport) | Submitting reports via HTTP (recommended) | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http) | -| [`client.SendReport`](#clientsendreport) | Complex report submission scenarios | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http#advanced-low-level-pattern) | +| Method | Use When | Guide | +| ------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| [`http.SendRequest`](#httpsendrequest) | Making HTTP calls (recommended) | [GET](/cre/guides/workflow/using-http-client/get-request) / [POST](/cre/guides/workflow/using-http-client/post-request) | +| [`client.SendRequest`](#clientsendrequest) | Complex scenarios requiring fine control | [GET](/cre/guides/workflow/using-http-client/get-request#2-the-creruninnodemode-pattern-low-level) | +| [`sendRequester.SendReport`](#sendrequestersendreport) | Submitting reports via HTTP (recommended) | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http) | +| [`client.SendReport`](#clientsendreport) | Complex report submission scenarios | [Report submission](/cre/guides/workflow/using-http-client/submitting-reports-http#advanced-low-level-pattern) | +| [`cre.ParseReport`](/cre/reference/sdk/core-go#report-verification) | Verifying received reports (receiver) | [Report verification](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go) | ## Core types @@ -397,3 +399,8 @@ func formatReport(r *sdk.ReportResponse) (*http.Request, error) { ``` For complete examples of including signatures in different formats (body, headers, JSON), see the [Submitting Reports via HTTP guide](/cre/guides/workflow/using-http-client/submitting-reports-http#formatting-patterns). + +{/* prettier-ignore */} + diff --git a/src/content/cre/reference/sdk/http-client-ts.mdx b/src/content/cre/reference/sdk/http-client-ts.mdx index 1506ca5bfe9..5a61a390f7b 100644 --- a/src/content/cre/reference/sdk/http-client-ts.mdx +++ b/src/content/cre/reference/sdk/http-client-ts.mdx @@ -19,7 +19,7 @@ Because it operates at the node level, all HTTP requests are wrapped in a consen - **[High-level (recommended)](#high-level-sendrequest-recommended):** Automatically wraps your request in the `runtime.runInNodeMode()` pattern with consensus aggregation. - **[Low-level](#low-level-sendrequest):** Requires manual wrapping in a `runtime.runInNodeMode()` block for complex scenarios. -For complete step-by-step examples, see the [GET requests](/cre/guides/workflow/using-http-client/get-request) and [POST requests](/cre/guides/workflow/using-http-client/post-request) guides. +For complete step-by-step examples, see the [GET requests](/cre/guides/workflow/using-http-client/get-request) and [POST requests](/cre/guides/workflow/using-http-client/post-request) guides. To **submit** signed reports, see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts). To **verify** received reports, see [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) and [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). ## High-level `sendRequest()` (recommended) @@ -155,6 +155,11 @@ const submitReport = (sendRequester: HTTPSendRequester, report: Report): string } ``` +{/* prettier-ignore */} + + ## Low-level `sendRequest()` The low-level `sendRequest()` method requires manual wrapping in a `runtime.runInNodeMode()` block. It provides more flexibility for complex scenarios but requires more boilerplate code. diff --git a/src/content/cre/reference/sdk/overview-go.mdx b/src/content/cre/reference/sdk/overview-go.mdx index 10fcf432b8b..faa00b9dc36 100644 --- a/src/content/cre/reference/sdk/overview-go.mdx +++ b/src/content/cre/reference/sdk/overview-go.mdx @@ -18,7 +18,7 @@ This section provides a detailed technical reference for the public interfaces o The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.Handler`, `cre.Runtime`, `cre.Promise`, and map iteration helpers `cre.OrderedEntries` / `cre.OrderedEntriesFunc`. +- **[Core SDK](/cre/reference/sdk/core)**: Covers the fundamental building blocks of any workflow, including `cre.Handler`, `cre.Runtime`, `cre.Promise`, report verification (`cre.ParseReport`), and map iteration helpers `cre.OrderedEntries` / `cre.OrderedEntriesFunc`. - **[Triggers](/cre/reference/sdk/triggers)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client)**: Provides a reference for the `evm.Client`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client)**: Provides a reference for the `http.Client`, used for making offchain API requests from individual nodes. diff --git a/src/content/cre/reference/sdk/overview-ts.mdx b/src/content/cre/reference/sdk/overview-ts.mdx index ee95f7e9685..a1881db3db6 100644 --- a/src/content/cre/reference/sdk/overview-ts.mdx +++ b/src/content/cre/reference/sdk/overview-ts.mdx @@ -18,7 +18,7 @@ This section provides a detailed technical reference for the public interfaces o The SDK Reference is broken down into several pages, each corresponding to a core part of the SDK's functionality: -- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, and the `.result()` pattern for promise resolution. +- **[Core SDK](/cre/reference/sdk/core-ts)**: Covers the fundamental building blocks of any workflow, including `handler`, `Runtime`, report verification (`Report.parse`), and the `.result()` pattern for promise resolution. - **[Triggers](/cre/reference/sdk/triggers/overview-ts)**: Details the configuration and payload structures for all available trigger types (`Cron`, `HTTP`, `EVM Log`). - **[EVM Client](/cre/reference/sdk/evm-client-ts)**: Provides a reference for the `EVMClient`, the primary tool for all EVM interactions, including reads and writes. - **[HTTP Client](/cre/reference/sdk/http-client-ts)**: Provides a reference for the `HTTPClient`, used for making offchain API requests from individual nodes. From 57caa9367a30d0d4f6cf0145355e95ce5111c249 Mon Sep 17 00:00:00 2001 From: devin distefano Date: Wed, 20 May 2026 19:14:32 -0500 Subject: [PATCH 2/6] cleanup --- .../generating-reports-single-values.mdx | 6 +- .../generating-reports-structs.mdx | 2 +- .../onchain-write/overview-go.mdx | 2 +- .../onchain-write/overview-ts.mdx | 2 +- .../submitting-reports-onchain.mdx | 4 +- .../workflow/using-http-client/index.mdx | 40 +++---- .../submitting-reports-http-go.mdx | 34 +++--- .../submitting-reports-http-ts.mdx | 32 ++--- .../verifying-reports-offchain-go.mdx | 30 ++--- .../verifying-reports-offchain-ts.mdx | 42 +++---- src/content/cre/llms-full-go.txt | 110 ++++++++---------- src/content/cre/llms-full-ts.txt | 110 ++++++++---------- .../cre/reference/sdk/http-client-ts.mdx | 2 +- 13 files changed, 193 insertions(+), 223 deletions(-) diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx index a505db987cd..ac36c54224b 100644 --- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx +++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values.mdx @@ -11,9 +11,9 @@ metadata: import { Aside } from "@components" -This guide shows how to manually generate a **CRE report** containing a single value (like `uint256`, `address`, or `bool`). A CRE report is a DON-signed package from `runtime.GenerateReport()` / `runtime.report()`—your encoded data plus workflow metadata and signatures. It is **not** a [Data Streams](/data-streams) report. +This guide shows how to manually generate a **CRE report** containing a single value (like `uint256`, `address`, or `bool`). A CRE report is a DON-signed package from `runtime.GenerateReport()` / `runtime.report()`: your encoded data plus workflow metadata and signatures. -This guide covers **creating** the report (step 2 in the sender flow). **Delivering** it is a separate step—see the table below. +This guide covers **creating** the signed report (`GenerateReport()` / `runtime.report()`). **Delivering** it is a separate step: see the table below. **Use this approach when:** @@ -38,7 +38,7 @@ Manually generating a report for a single value involves two main steps: | `evm.Client.WriteReport()` / `writeReport()` | [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | `KeystoneForwarder` onchain | | `http.Client` `SendReport()` | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) | Receiver: [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) or your API | -See [API Interactions — CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver mental model. +See [API Interactions: CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver mental model. +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package another workflow (or system) created with [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values). You receive its bytes over HTTP (or another channel) as `rawReport`, `reportContext`, and `signatures`. Before you use the encoded payload, you must confirm the signatures match authorized DON signers on the Capability Registry. + +This guide is the **receiver** path: decode the POST body, call [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport), then read trusted metadata and `Body()`. See [Key Terms: Report](/cre/key-terms#report-cre-report) for how reports are created and delivered. + ## Where this guide fits -| Question | Answer | -| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Same CRE report the **sender** created with `runtime.GenerateReport()`. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#where-this-guide-fits). | -| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `GenerateReport()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | -| What does this guide cover? | Step 3 below: `cre.ParseReport()` before you use `Body()` or take side effects. | -| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | +| Question | Answer | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| What is the report? | Same [CRE report](/cre/key-terms#report-cre-report) the **sender** created with [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#what-is-a-cre-report). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 3 below: [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) before you use `Body()` or take side effects. | +| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | **Receiver flow:** 1. HTTP trigger (or your API) receives the POST payload. 2. Decode hex fields into bytes. -3. `cre.ParseReport()`: verify signatures and read metadata. +3. [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport): verify signatures and read metadata. 4. Use trusted `Body()` in your logic. Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go) on the sender side. This guide covers local simulation first, then the deploy example with `AuthorizedKeys`. @@ -49,7 +55,7 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## What you'll learn - When to verify reports offchain vs relying on onchain forwarders -- How `cre.ParseReport()` validates signatures and reads metadata +- How [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) validates signatures and reads metadata - How to build a receiver workflow that accepts reports over HTTP - How to restrict verification to specific CRE environments or zones @@ -61,12 +67,12 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## Onchain vs offchain verification -| Aspect | Offchain (`cre.ParseReport`) | Onchain (`KeystoneForwarder`) | -| -------------------- | ------------------------------------------------------------ | --------------------------------- | -| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | -| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | -| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | -| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | +| Aspect | Offchain ([`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport)) | Onchain (`KeystoneForwarder`) | +| -------------------- | --------------------------------------------------------------------------- | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. @@ -82,7 +88,7 @@ Default (`cre.ProductionEnvironment()`): 3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. 4. **Return a `*cre.Report`** with accessors for workflow ID, owner, execution ID, body, and more. -If verification fails, `cre.ParseReport()` returns an error (for example, `ErrUnknownSigner`, `ErrWrongSignatureCount`, or registry read failure). +If verification fails, [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) returns an error (for example, `ErrUnknownSigner`, `ErrWrongSignatureCount`, or registry read failure). ## Testing locally with simulation @@ -94,7 +100,7 @@ After you run the [submit guide complete example](/cre/guides/workflow/using-htt ### Minimal receiver for simulation -Use an empty HTTP trigger for sim. Set `SkipSignatureVerification: true` in staging config (or pass it to `ParseReportWithConfig`). The CLI delivers `--http-payload` file contents as `payload.Input` bytes. +Use an empty HTTP trigger for sim. Set `SkipSignatureVerification: true` in staging config (or pass it to [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig)). The CLI delivers `--http-payload` file contents as `payload.Input` bytes. `config.staging.json`: @@ -183,10 +189,10 @@ func main() { ### Sim wiring vs full verify -| Mode | Config | What it validates | -| ---------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | -| **Wiring / decode** | `SkipSignatureVerification: true` in `ParseReportWithConfig` | JSON + hex decode, metadata accessors, `Body()` | -| **Full crypto verify** | Default `cre.ParseReport()` (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification. | +| Mode | Config | What it validates | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| **Wiring / decode** | `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig) | JSON + hex decode, metadata accessors, `Body()` | +| **Full crypto verify** | Default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification. | ```bash cre workflow simulate verify-report-receiver \ @@ -198,8 +204,8 @@ cre workflow simulate verify-report-receiver \ **Pass criteria** -- **Sim wiring:** `SkipSignatureVerification: true` in `ParseReportWithConfig`: logs show metadata and a successful handler return. -- **Full crypto verify:** default `ParseReport` with a **production-signed** report (not typical for sender-sim → receiver-sim alone). +- **Sim wiring:** `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig): logs show metadata and a successful handler return. +- **Full crypto verify:** default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) with a **production-signed** report (not typical for sender-sim → receiver-sim alone). `project.yaml` needs **`ethereum-mainnet` RPC** for default verify (registry reads). @@ -303,7 +309,7 @@ func main() { **What's happening:** 1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. -2. `cre.ParseReport()` verifies signatures against the production CRE registry. +2. [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) verifies signatures against the production CRE registry. 3. On success, you read metadata and `Body()` safely. {/* prettier-ignore */} @@ -313,7 +319,7 @@ func main() { ## Report payload format -Receivers need three JSON fields. The JSON key is `context` even though the SDK field is `ReportContext`: +When a sender POSTs a [CRE report](/cre/key-terms#report-cre-report) as JSON for offchain verification, receivers need three fields. The JSON key is `context` even though the SDK field is `ReportContext`: | JSON field | SDK field | Description | | ------------ | --------------- | --------------------------------------------------------------- | @@ -336,7 +342,7 @@ See [SDK Reference: Core: Report verification](/cre/reference/sdk/core-go#report func ParseReport(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte) (*Report, error) ``` -Parses and verifies a report against the production CRE environment. Use `ParseReportWithConfig` for custom environments or zones. +Parses and verifies a report against the production CRE environment. Use [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig) for custom environments or zones. ### `*cre.Report` accessors @@ -377,7 +383,7 @@ report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext This is a **different pattern** from the simulation testing use of `SkipSignatureVerification`. In testing, you skip verification permanently. Here, you parse the header first to inspect metadata (such as `WorkflowID()` or `DONID()` for filtering), then call `VerifySignatures` in a separate step — useful when you want to gate registry reads on workflow identity checks. -If you set `SkipSignatureVerification: true` in `ParseReportWithConfig`, parse the header first, then verify: +If you set `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig), parse the header first, then verify: ```go report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext, cre.ReportParseConfig{ @@ -396,7 +402,7 @@ if err := report.VerifySignatures(runtime); err != nil { ## Best practices -1. **Verify before side effects**: Call `cre.ParseReport()` before writing to databases, chains, or external systems. +1. **Verify before side effects**: Call [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) before writing to databases, chains, or external systems. 2. **Permission on metadata**: After verification, check `WorkflowID()`, `WorkflowOwner()`, or `DONID()` match your expectations. 3. **Deduplicate by execution ID**: Use `ExecutionID()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#understanding-cachesettings-for-reports)). 4. **Do not skip signature verification in production** unless you have another trust path. @@ -405,7 +411,7 @@ if err := report.VerifySignatures(runtime); err != nil { **`ErrUnknownSigner` / `invalid signature` in sim with fresh webhook JSON** -- **Expected** when using default `ParseReport` on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. +- **Expected** when using default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. - For local wiring tests, use `SkipSignatureVerification: true`. For real crypto verify, use a **deployed sender** or production-signed reports. **`ErrUnknownSigner` (deployed)** diff --git a/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx index a42faaa3f30..ed6a799d911 100644 --- a/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx +++ b/src/content/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts.mdx @@ -16,11 +16,11 @@ This guide is for the **receiver** side: you already received a CRE report packa When a workflow delivers results via HTTP (or another offchain channel), nothing onchain automatically validates the report. **You must verify signatures before trusting the data.** -The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. +The CRE SDK provides [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. {/* prettier-ignore */} {/* prettier-ignore */} @@ -28,20 +28,26 @@ The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification When you submit reports onchain through the `KeystoneForwarder`, the forwarder contract verifies signatures before calling your consumer's `onReport`. This guide covers **offchain** verification for HTTP and custom ingest paths. See [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain). +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package another workflow (or system) created with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). You receive its bytes over HTTP (or another channel) as `rawReport`, `reportContext`, and `signatures`. Before you use the encoded payload, you must confirm the signatures match authorized DON signers on the Capability Registry. + +This guide is the **receiver** path: decode the POST body, call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification), then read trusted metadata and `body()`. See [Key Terms: Report](/cre/key-terms#report-cre-report) for how reports are created and delivered. + ## Where this guide fits -| Question | Answer | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Same CRE report the **sender** created with `runtime.report()`. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#where-this-guide-fits). | -| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `runtime.report()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | -| What does this guide cover? | Step 3 below: `Report.parse()` before you use `body()` or take side effects. | -| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | +| Question | Answer | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| What is the report? | Same [CRE report](/cre/key-terms#report-cre-report) the **sender** created with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#what-is-a-cre-report). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 3 below: [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) before you use `body()` or take side effects. | +| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | **Receiver flow:** 1. HTTP trigger (or your API) receives the POST payload. 2. Decode hex fields into bytes. -3. `Report.parse()`: verify signatures and read metadata. +3. [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification): verify signatures and read metadata. 4. Use trusted `body()` in your logic. Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts) on the sender side. This guide covers local simulation first, then the deploy example with `authorizedKeys`. @@ -49,7 +55,7 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## What you'll learn - When to verify reports offchain vs relying on onchain forwarders -- How `Report.parse()` validates signatures and reads metadata +- How [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) validates signatures and reads metadata - How to build a receiver workflow that accepts reports over HTTP - How to restrict verification to specific CRE environments or zones @@ -61,12 +67,12 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## Onchain vs offchain verification -| Aspect | Offchain (`Report.parse`) | Onchain (`KeystoneForwarder`) | -| -------------------- | ------------------------------------------------------------ | --------------------------------- | -| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | -| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | -| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | -| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | +| Aspect | Offchain ([`Report.parse()`](/cre/reference/sdk/core-ts#report-verification)) | Onchain (`KeystoneForwarder`) | +| -------------------- | ----------------------------------------------------------------------------- | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. @@ -82,7 +88,7 @@ Default (`productionEnvironment()`): 3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. 4. **Return a `Report` object** with accessors for workflow ID, owner, execution ID, body, and more. -If verification fails, `Report.parse()` throws (for example, unknown signer, insufficient signatures, or registry read failure). +If verification fails, [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) throws (for example, unknown signer, insufficient signatures, or registry read failure). ## Testing locally with simulation @@ -94,14 +100,14 @@ After you run the [submit guide complete example](/cre/guides/workflow/using-htt ### Sim wiring vs full verify -| Mode | Config | What it validates | -| ---------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Wiring / decode** | `skipSignatureVerification: true` in staging config | JSON + hex decode, `workflowId()`, `executionId()`, `donId()`, `body()` | -| **Full crypto verify** | Default `Report.parse()` (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification: simulation uses local DON keys; `Report.parse()` checks the mainnet Capability Registry. | +| Mode | Config | What it validates | +| ---------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Wiring / decode** | `skipSignatureVerification: true` in staging config | JSON + hex decode, `workflowId()`, `executionId()`, `donId()`, `body()` | +| **Full crypto verify** | Default [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification: simulation uses local DON keys; [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) checks the mainnet Capability Registry. | ### Minimal receiver for simulation -Use an **empty HTTP trigger config** for sim (add `authorizedKeys` before deploy). Call `Report.parse()` from your handler with the `runtime` parameter. The CLI delivers `--http-payload` file contents as `payload.input` bytes. +Use an **empty HTTP trigger config** for sim (add `authorizedKeys` before deploy). Call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) from your handler with the `runtime` parameter. The CLI delivers `--http-payload` file contents as `payload.input` bytes. `config.staging.json`: @@ -262,7 +268,7 @@ export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) **What's happening:** 1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. -2. `Report.parse()` verifies signatures against the production CRE registry. +2. [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) verifies signatures against the production CRE registry. 3. On success, you read metadata and `body()` safely. {/* prettier-ignore */} @@ -272,7 +278,7 @@ export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) ## Report payload format -Receivers need three JSON fields (plus optional metadata your API may add). The JSON key is `context` even though the SDK field is `reportContext`: +When a sender POSTs a [CRE report](/cre/key-terms#report-cre-report) as JSON for offchain verification, receivers need three fields (plus optional metadata your API may add). The JSON key is `context` even though the SDK field is `reportContext`: | JSON field | SDK field | Description | | ------------ | --------------- | --------------------------------------------------------------- | @@ -331,17 +337,17 @@ const config: ReportParseConfig = { } ``` -| Option | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `acceptedEnvironments` | Registry environments to check (defaults to production) | -| `acceptedZones` | Restrict to specific DON IDs within an environment | -| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript; call `Report.parse()` without this flag for production verification. | +| Option | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `acceptedEnvironments` | Registry environments to check (defaults to production) | +| `acceptedZones` | Restrict to specific DON IDs within an environment | +| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript; call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) without this flag for production verification. | Most workflows should use the default config (production environment only). ## Best practices -1. **Verify before side effects**: Call `Report.parse()` before writing to databases, chains, or external systems. +1. **Verify before side effects**: Call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) before writing to databases, chains, or external systems. 2. **Permission on metadata**: After verification, check `workflowId()`, `workflowOwner()`, or `donId()` match your expectations. 3. **Deduplicate by execution ID**: Use `executionId()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#understanding-cachesettings-for-reports)). 4. **Do not skip signature verification in production** unless you have another trust path. @@ -350,12 +356,12 @@ Most workflows should use the default config (production environment only). **Empty error after verify sim** -- `Report.parse()` may throw an **`AggregateError`** of multiple `invalid signature` errors. **`AggregateError.message` is often empty**, so the CLI prints `Execution resulted in an error being returned:` with nothing after the colon. +- [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) may throw an **`AggregateError`** of multiple `invalid signature` errors. **`AggregateError.message` is often empty**, so the CLI prints `Execution resulted in an error being returned:` with nothing after the colon. - Format errors in your handler before rethrowing (see the simulation example above). **`invalid signature` / `unknown signer` in sim with fresh webhook JSON** -- **Expected** when using default `Report.parse()` on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. +- **Expected** when using default [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. - For local wiring tests, set `skipSignatureVerification: true`. For real crypto verify, use a **deployed sender** or production-signed reports. **`invalid signature` / `unknown signer` (deployed)** diff --git a/src/content/cre/index.mdx b/src/content/cre/index.mdx index e0d87181230..7f7432d5c44 100644 --- a/src/content/cre/index.mdx +++ b/src/content/cre/index.mdx @@ -110,17 +110,18 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) ## Glossary: Building blocks -| Concept | One-liner | -| ------------------ | ----------------------------------------------------------------- | -| **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | -| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | -| **Callback** | Function that runs when its trigger fires; contains your logic. | -| **Runtime** | Object passed to a callback; used to invoke capabilities. | -| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | -| **Workflow DON** | Watches triggers and coordinates the workflow. | -| **Capability DON** | Executes a specific capability. | -| **Consensus** | BFT protocol that merges node results into one verifiable report. | +| Concept | One-liner | +| ------------------ | ---------------------------------------------------------------- | +| **Workflow** | Compiled WebAssembly (WASM) binary. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | +| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | +| **Callback** | Function that runs when its trigger fires; contains your logic. | +| **Runtime** | Object passed to a callback; used to invoke capabilities. | +| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | +| **Workflow DON** | Watches triggers and coordinates the workflow. | +| **Capability DON** | Executes a specific capability. | +| **Consensus** | BFT protocol that merges node results into one trusted outcome. | +| **Report** | DON-signed package from `runtime.report()` / `GenerateReport()`. | Full definitions live on **[Key Terms and Concepts](/cre/key-terms)**. diff --git a/src/content/cre/key-terms.mdx b/src/content/cre/key-terms.mdx index 722c51ddc98..98a95fb4b12 100644 --- a/src/content/cre/key-terms.mdx +++ b/src/content/cre/key-terms.mdx @@ -5,7 +5,7 @@ date: Last Modified metadata: description: "Learn essential CRE concepts: workflows, handlers, triggers, callbacks, Runtime, capabilities, DONs, and consensus." datePublished: "2025-11-04" - lastModified: "2025-11-04" + lastModified: "2026-05-20" --- import { Aside } from "@components" @@ -75,6 +75,12 @@ Short-lived objects passed to your callback function during a specific execution Learn more about [Consensus and Aggregation](/cre/reference/sdk/consensus). +### Report (CRE report) + +A cryptographically signed package your workflow [DON](/cre/key-terms#decentralized-oracle-network-don) produces after your callback encodes its result: payload bytes, report context, and DON signatures. Create it with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (TypeScript) or [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) (Go). + +Deliver onchain with [`writeReport()`](/cre/reference/sdk/evm-client-ts#writereport) / [`WriteReport()`](/cre/reference/sdk/evm-client-go#writereport), or offchain with [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) / [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport). Receivers verify with [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) or [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) and [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain). + ### SDK Clients: `EVMClient` & `HTTPClient` The primary SDK clients you use inside a callback to interact with capabilities. For example, you use an EVM client to read from a smart contract and an HTTP client to make offchain API requests. diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt index 175df69db76..fde695841ea 100644 --- a/src/content/cre/llms-full-go.txt +++ b/src/content/cre/llms-full-go.txt @@ -99,17 +99,18 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) ## Glossary: Building blocks -| Concept | One-liner | -| ------------------ | ----------------------------------------------------------------- | -| **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | -| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | -| **Callback** | Function that runs when its trigger fires; contains your logic. | -| **Runtime** | Object passed to a callback; used to invoke capabilities. | -| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | -| **Workflow DON** | Watches triggers and coordinates the workflow. | -| **Capability DON** | Executes a specific capability. | -| **Consensus** | BFT protocol that merges node results into one verifiable report. | +| Concept | One-liner | +| ------------------ | ---------------------------------------------------------------- | +| **Workflow** | Compiled WebAssembly (WASM) binary. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | +| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | +| **Callback** | Function that runs when its trigger fires; contains your logic. | +| **Runtime** | Object passed to a callback; used to invoke capabilities. | +| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | +| **Workflow DON** | Watches triggers and coordinates the workflow. | +| **Capability DON** | Executes a specific capability. | +| **Consensus** | BFT protocol that merges node results into one trusted outcome. | +| **Report** | DON-signed package from `runtime.report()` / `GenerateReport()`. | Full definitions live on **[Key Terms and Concepts](/cre/key-terms)**. @@ -149,7 +150,7 @@ Jump to what you need: # Key Terms and Concepts Source: https://docs.chain.link/cre/key-terms -Last Updated: 2025-11-04 +Last Updated: 2026-05-20 This page defines the fundamental terms and concepts for the Chainlink Runtime Environment (CRE). @@ -216,6 +217,12 @@ Short-lived objects passed to your callback function during a specific execution Learn more about [Consensus and Aggregation](/cre/reference/sdk/consensus). +### Report (CRE report) + +A cryptographically signed package your workflow [DON](/cre/key-terms#decentralized-oracle-network-don) produces after your callback encodes its result: payload bytes, report context, and DON signatures. Create it with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (TypeScript) or [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) (Go). + +Deliver onchain with [`writeReport()`](/cre/reference/sdk/evm-client-ts#writereport) / [`WriteReport()`](/cre/reference/sdk/evm-client-go#writereport), or offchain with [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) / [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport). Receivers verify with [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) or [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) and [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain). + ### SDK Clients: `EVMClient` & `HTTPClient` The primary SDK clients you use inside a callback to interact with capabilities. For example, you use an EVM client to read from a smart contract and an HTTP client to make offchain API requests. @@ -3770,9 +3777,9 @@ writePromise := reserveManager.WriteReportFromUpdateReserves(runtime, updateData Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values Last Updated: 2025-11-04 -This guide shows how to manually generate a **CRE report** containing a single value (like `uint256`, `address`, or `bool`). A CRE report is a DON-signed package from `runtime.GenerateReport()` / `runtime.report()`: your encoded data plus workflow metadata and signatures. +This guide shows how to manually generate a **[CRE report](/cre/key-terms#report-cre-report)** containing a single value (like `uint256`, `address`, or `bool`). See [Key Terms: Report](/cre/key-terms#report-cre-report) for the full definition; in short, it is a DON-signed package from [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) / [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) with your encoded data, workflow metadata, and signatures. -This guide covers **creating** the signed report (`GenerateReport()` / `runtime.report()`). **Delivering** it is a separate step: see the table below. +This guide covers **creating** the signed report ([`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) / [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime)). **Delivering** it is a separate step: see the table below. **Use this approach when:** @@ -3790,12 +3797,12 @@ This guide covers **creating** the signed report (`GenerateReport()` / `runtime. Manually generating a report for a single value involves two main steps: 1. **ABI-encode the value** into bytes using the `go-ethereum/accounts/abi` package -2. **Generate a cryptographically signed report** using `runtime.GenerateReport()` +2. **Generate a cryptographically signed report** using [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) -| After `GenerateReport()` / `report()` | Guide | Who verifies? | -| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | -| `evm.Client.WriteReport()` / `writeReport()` | [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | `KeystoneForwarder` onchain | -| `http.Client` `SendReport()` | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) | Receiver: [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) or your API | +| After [`GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) / [`report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) | Guide | Who verifies? | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | +| [`WriteReport()`](/cre/reference/sdk/evm-client-go#writereport) / [`writeReport()`](/cre/reference/sdk/evm-client-ts#writereport) | [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) | `KeystoneForwarder` onchain | +| [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport) / [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) | [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) | Receiver: [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain) or your API | See [API Interactions: CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http) for the sender → receiver mental model. @@ -4036,7 +4043,7 @@ func main() { Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-structs Last Updated: 2025-11-04 -This guide shows how to generate a **CRE report** containing a struct with multiple fields. A CRE report is a DON-signed package from `runtime.GenerateReport()`. After generation, deliver it [onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) or via [HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http); HTTP receivers should [verify offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain). See [API Interactions: CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). +This guide shows how to generate a **[CRE report](/cre/key-terms#report-cre-report)** containing a struct with multiple fields. See [Key Terms: Report](/cre/key-terms#report-cre-report) for the full definition. After generation, deliver it [onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) or via [HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http); HTTP receivers should [verify offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain). See [API Interactions: CRE reports over HTTP](/cre/guides/workflow/using-http-client#cre-reports-over-http). There are two encoding approaches depending on whether you have generated bindings for your contract. @@ -4744,7 +4751,7 @@ The CRE SDK provides an HTTP client that allows your workflows to interact with ## CRE reports over HTTP -A **CRE report** is a DON-signed package your workflow creates with `runtime.report()` (TypeScript) or `runtime.GenerateReport()` (Go). It contains your encoded payload, workflow metadata, and cryptographic signatures. +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package your workflow creates with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (TypeScript) or [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) (Go). It bundles your encoded payload, workflow metadata, report context, and cryptographic signatures from the DON. See [Key Terms: Report](/cre/key-terms#report-cre-report) for the full definition, including how onchain delivery differs from HTTP. A typical secure integration uses two parties: @@ -15299,7 +15306,7 @@ This guide is for the **sender** side: a CRE workflow that **creates** a signed **What you'll learn:** -- How to use `SendReport` to submit reports via HTTP +- How to use [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport) to submit reports via HTTP - How to write transformation functions for different API formats - Best practices for report submission and deduplication @@ -15308,27 +15315,33 @@ This guide is for the **sender** side: a CRE workflow that **creates** a signed This guide covers HTTP submission. For submitting reports to smart contracts, see [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain). +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is the signed output your workflow DON produces when you call [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values). It packages your encoded data (the payload you computed in the callback), fixed workflow metadata, a report context (config digest and sequence number), and ECDSA signatures from DON nodes. + +This guide covers the **sender** path: create the report in your workflow, then POST it to an HTTP endpoint. The receiver must verify those signatures before trusting the data. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go) on the receiver side. + ## Where this guide fits -| Question | Answer | -| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Output of `runtime.GenerateReport()` after your workflow DON reaches consensus: encoded payload + metadata + signatures. | -| Where does it come from? | **Inside this workflow:** after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | -| What does this guide cover? | Steps 3–4 below: `GenerateReport()`, then `SendReport()` to your API. Steps 1–2 (trigger and your callback logic) are prerequisites, not the focus here. | -| Who verifies it? | The **receiver:** your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go). | +| Question | Answer | +| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | A [CRE report](/cre/key-terms#report-cre-report): output of [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) after DON consensus (encoded payload + metadata + signatures). | +| Where does it come from? | **Inside this workflow:** after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | +| What does this guide cover? | Steps 3–4 below: [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values), then [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport) to your API. Steps 1–2 (trigger and your callback logic) are prerequisites, not the focus here. | +| Who verifies it? | The **receiver:** your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-go). | **Sender flow in one workflow execution:** 1. Trigger fires (cron, HTTP, …). 2. Your callback runs (API calls, encoding, etc.). -3. `runtime.GenerateReport()`: DON produces a signed `sdk.ReportResponse`. -4. `SendReport()`: format and POST to your URL. +3. [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values): DON produces a signed `sdk.ReportResponse`. +4. [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport): format and POST to your URL. ## Prerequisites - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) - Understanding of [generating reports](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) -- A generated report from `runtime.GenerateReport()` +- A generated report from [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package another workflow (or system) created with [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values). You receive its bytes over HTTP (or another channel) as `rawReport`, `reportContext`, and `signatures`. Before you use the encoded payload, you must confirm the signatures match authorized DON signers on the Capability Registry. + +This guide is the **receiver** path: decode the POST body, call [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport), then read trusted metadata and `Body()`. See [Key Terms: Report](/cre/key-terms#report-cre-report) for how reports are created and delivered. + ## Where this guide fits -| Question | Answer | -| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Same CRE report the **sender** created with `runtime.GenerateReport()`. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#where-this-guide-fits). | -| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `GenerateReport()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | -| What does this guide cover? | Step 3 below: `cre.ParseReport()` before you use `Body()` or take side effects. | -| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | +| Question | Answer | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| What is the report? | Same [CRE report](/cre/key-terms#report-cre-report) the **sender** created with [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#what-is-a-cre-report). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 3 below: [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) before you use `Body()` or take side effects. | +| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | **Receiver flow:** 1. HTTP trigger (or your API) receives the POST payload. 2. Decode hex fields into bytes. -3. `cre.ParseReport()`: verify signatures and read metadata. +3. [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport): verify signatures and read metadata. 4. Use trusted `Body()` in your logic. Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go) on the sender side. This guide covers local simulation first, then the deploy example with `AuthorizedKeys`. @@ -16001,7 +16020,7 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## What you'll learn - When to verify reports offchain vs relying on onchain forwarders -- How `cre.ParseReport()` validates signatures and reads metadata +- How [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) validates signatures and reads metadata - How to build a receiver workflow that accepts reports over HTTP - How to restrict verification to specific CRE environments or zones @@ -16013,12 +16032,12 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## Onchain vs offchain verification -| Aspect | Offchain (`cre.ParseReport`) | Onchain (`KeystoneForwarder`) | -| -------------------- | ------------------------------------------------------------ | --------------------------------- | -| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | -| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | -| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | -| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | +| Aspect | Offchain ([`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport)) | Onchain (`KeystoneForwarder`) | +| -------------------- | --------------------------------------------------------------------------- | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. @@ -16034,7 +16053,7 @@ Default (`cre.ProductionEnvironment()`): 3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. 4. **Return a `*cre.Report`** with accessors for workflow ID, owner, execution ID, body, and more. -If verification fails, `cre.ParseReport()` returns an error (for example, `ErrUnknownSigner`, `ErrWrongSignatureCount`, or registry read failure). +If verification fails, [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) returns an error (for example, `ErrUnknownSigner`, `ErrWrongSignatureCount`, or registry read failure). ## Testing locally with simulation @@ -16046,7 +16065,7 @@ After you run the [submit guide complete example](/cre/guides/workflow/using-htt ### Minimal receiver for simulation -Use an empty HTTP trigger for sim. Set `SkipSignatureVerification: true` in staging config (or pass it to `ParseReportWithConfig`). The CLI delivers `--http-payload` file contents as `payload.Input` bytes. +Use an empty HTTP trigger for sim. Set `SkipSignatureVerification: true` in staging config (or pass it to [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig)). The CLI delivers `--http-payload` file contents as `payload.Input` bytes. `config.staging.json`: @@ -16135,10 +16154,10 @@ func main() { ### Sim wiring vs full verify -| Mode | Config | What it validates | -| ---------------------- | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | -| **Wiring / decode** | `SkipSignatureVerification: true` in `ParseReportWithConfig` | JSON + hex decode, metadata accessors, `Body()` | -| **Full crypto verify** | Default `cre.ParseReport()` (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification. | +| Mode | Config | What it validates | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| **Wiring / decode** | `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig) | JSON + hex decode, metadata accessors, `Body()` | +| **Full crypto verify** | Default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification. | ```bash cre workflow simulate verify-report-receiver \ @@ -16150,8 +16169,8 @@ cre workflow simulate verify-report-receiver \ **Pass criteria** -- **Sim wiring:** `SkipSignatureVerification: true` in `ParseReportWithConfig`: logs show metadata and a successful handler return. -- **Full crypto verify:** default `ParseReport` with a **production-signed** report (not typical for sender-sim → receiver-sim alone). +- **Sim wiring:** `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig): logs show metadata and a successful handler return. +- **Full crypto verify:** default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) with a **production-signed** report (not typical for sender-sim → receiver-sim alone). `project.yaml` needs **`ethereum-mainnet` RPC** for default verify (registry reads). @@ -16255,7 +16274,7 @@ func main() { **What's happening:** 1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. -2. `cre.ParseReport()` verifies signatures against the production CRE registry. +2. [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) verifies signatures against the production CRE registry. 3. On success, you read metadata and `Body()` safely. @@ -16265,7 +16284,7 @@ func main() { ## Report payload format -Receivers need three JSON fields. The JSON key is `context` even though the SDK field is `ReportContext`: +When a sender POSTs a [CRE report](/cre/key-terms#report-cre-report) as JSON for offchain verification, receivers need three fields. The JSON key is `context` even though the SDK field is `ReportContext`: | JSON field | SDK field | Description | | ------------ | --------------- | --------------------------------------------------------------- | @@ -16288,7 +16307,7 @@ See [SDK Reference: Core: Report verification](/cre/reference/sdk/core-go#report func ParseReport(runtime Runtime, rawReport []byte, signatures [][]byte, reportContext []byte) (*Report, error) ``` -Parses and verifies a report against the production CRE environment. Use `ParseReportWithConfig` for custom environments or zones. +Parses and verifies a report against the production CRE environment. Use [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig) for custom environments or zones. ### `*cre.Report` accessors @@ -16329,7 +16348,7 @@ report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext This is a **different pattern** from the simulation testing use of `SkipSignatureVerification`. In testing, you skip verification permanently. Here, you parse the header first to inspect metadata (such as `WorkflowID()` or `DONID()` for filtering), then call `VerifySignatures` in a separate step — useful when you want to gate registry reads on workflow identity checks. -If you set `SkipSignatureVerification: true` in `ParseReportWithConfig`, parse the header first, then verify: +If you set `SkipSignatureVerification: true` in [`ParseReportWithConfig`](/cre/reference/sdk/core-go#creparsereportwithconfig), parse the header first, then verify: ```go report, err := cre.ParseReportWithConfig(runtime, rawReport, sigs, reportContext, cre.ReportParseConfig{ @@ -16348,7 +16367,7 @@ if err := report.VerifySignatures(runtime); err != nil { ## Best practices -1. **Verify before side effects**: Call `cre.ParseReport()` before writing to databases, chains, or external systems. +1. **Verify before side effects**: Call [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) before writing to databases, chains, or external systems. 2. **Permission on metadata**: After verification, check `WorkflowID()`, `WorkflowOwner()`, or `DONID()` match your expectations. 3. **Deduplicate by execution ID**: Use `ExecutionID()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-go#understanding-cachesettings-for-reports)). 4. **Do not skip signature verification in production** unless you have another trust path. @@ -16357,7 +16376,7 @@ if err := report.VerifySignatures(runtime); err != nil { **`ErrUnknownSigner` / `invalid signature` in sim with fresh webhook JSON** -- **Expected** when using default `ParseReport` on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. +- **Expected** when using default [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport) on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. - For local wiring tests, use `SkipSignatureVerification: true`. For real crypto verify, use a **deployed sender** or production-signed reports. **`ErrUnknownSigner` (deployed)** diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index ee27231a3a5..3e58f8ca273 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -99,17 +99,18 @@ Learn more about [Consensus Computing in CRE](/cre/concepts/consensus-computing) ## Glossary: Building blocks -| Concept | One-liner | -| ------------------ | ----------------------------------------------------------------- | -| **Workflow** | Compiled WebAssembly (WASM) binary. | -| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | -| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | -| **Callback** | Function that runs when its trigger fires; contains your logic. | -| **Runtime** | Object passed to a callback; used to invoke capabilities. | -| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | -| **Workflow DON** | Watches triggers and coordinates the workflow. | -| **Capability DON** | Executes a specific capability. | -| **Consensus** | BFT protocol that merges node results into one verifiable report. | +| Concept | One-liner | +| ------------------ | ---------------------------------------------------------------- | +| **Workflow** | Compiled WebAssembly (WASM) binary. | +| **Handler** | `handler(trigger, callback)` pair; the atom of execution. | +| **Trigger** | Event that starts an execution (cron, HTTP, EVM log, …). | +| **Callback** | Function that runs when its trigger fires; contains your logic. | +| **Runtime** | Object passed to a callback; used to invoke capabilities. | +| **Capability** | Decentralized microservice (chain read/write, HTTP Fetch, ...). | +| **Workflow DON** | Watches triggers and coordinates the workflow. | +| **Capability DON** | Executes a specific capability. | +| **Consensus** | BFT protocol that merges node results into one trusted outcome. | +| **Report** | DON-signed package from `runtime.report()` / `GenerateReport()`. | Full definitions live on **[Key Terms and Concepts](/cre/key-terms)**. @@ -149,7 +150,7 @@ Jump to what you need: # Key Terms and Concepts Source: https://docs.chain.link/cre/key-terms -Last Updated: 2025-11-04 +Last Updated: 2026-05-20 This page defines the fundamental terms and concepts for the Chainlink Runtime Environment (CRE). @@ -216,6 +217,12 @@ Short-lived objects passed to your callback function during a specific execution Learn more about [Consensus and Aggregation](/cre/reference/sdk/consensus). +### Report (CRE report) + +A cryptographically signed package your workflow [DON](/cre/key-terms#decentralized-oracle-network-don) produces after your callback encodes its result: payload bytes, report context, and DON signatures. Create it with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (TypeScript) or [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) (Go). + +Deliver onchain with [`writeReport()`](/cre/reference/sdk/evm-client-ts#writereport) / [`WriteReport()`](/cre/reference/sdk/evm-client-go#writereport), or offchain with [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) / [`SendReport()`](/cre/reference/sdk/http-client-go#sendrequestersendreport). Receivers verify with [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) or [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparsereport). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http) and [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain). + ### SDK Clients: `EVMClient` & `HTTPClient` The primary SDK clients you use inside a callback to interact with capabilities. For example, you use an EVM client to read from a smart contract and an HTTP client to make offchain API requests. @@ -4053,7 +4060,7 @@ The CRE SDK provides an HTTP client that allows your workflows to interact with ## CRE reports over HTTP -A **CRE report** is a DON-signed package your workflow creates with `runtime.report()` (TypeScript) or `runtime.GenerateReport()` (Go). It contains your encoded payload, workflow metadata, and cryptographic signatures. +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package your workflow creates with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (TypeScript) or [`runtime.GenerateReport()`](/cre/guides/workflow/using-evm-client/onchain-write/generating-reports-single-values) (Go). It bundles your encoded payload, workflow metadata, report context, and cryptographic signatures from the DON. See [Key Terms: Report](/cre/key-terms#report-cre-report) for the full definition, including how onchain delivery differs from HTTP. A typical secure integration uses two parties: @@ -15004,7 +15011,7 @@ This guide is for the **sender** side: a CRE workflow that **creates** a signed **What you'll learn:** -- How to use `sendReport()` to submit reports via HTTP +- How to use [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) to submit reports via HTTP - How to write transformation functions for different API formats - Best practices for report submission and deduplication @@ -15013,26 +15020,32 @@ This guide is for the **sender** side: a CRE workflow that **creates** a signed This guide covers HTTP submission. For submitting reports to smart contracts, see [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/overview-ts). +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is the signed output your workflow DON produces when you call [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). It packages your encoded data (the payload you computed in the callback), fixed workflow metadata, a report context (config digest and sequence number), and ECDSA signatures from DON nodes. + +This guide covers the **sender** path: create the report in your workflow, then POST it to an HTTP endpoint. The receiver must verify those signatures before trusting the data. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts) on the receiver side. + ## Where this guide fits -| Question | Answer | -| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Output of `runtime.report()` after your workflow DON reaches consensus: encoded payload + metadata + signatures. | -| Where does it come from? | **Inside this workflow:** after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | -| What does this guide cover? | Steps 3–4 below: `runtime.report()`, then `sendReport()` to your API. Steps 1–2 (trigger and your callback logic) are prerequisites, not the focus here. | -| Who verifies it? | The **receiver:** your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). | +| Question | Answer | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| What is the report? | A [CRE report](/cre/key-terms#report-cre-report): output of [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) after DON consensus (encoded payload + metadata + signatures). | +| Where does it come from? | **Inside this workflow:** after your logic runs (fetch data, compute, encode). There is no separate "get report" step. | +| What does this guide cover? | Steps 3–4 below: [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime), then [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) to your API. Steps 1–2 (trigger and your callback logic) are prerequisites, not the focus here. | +| Who verifies it? | The **receiver:** your HTTP service or a separate CRE workflow. See [Verifying CRE Reports Offchain](/cre/guides/workflow/using-http-client/verifying-reports-offchain-ts). | **Sender flow in one workflow execution:** 1. Trigger fires (cron, HTTP, …). 2. Your callback runs (API calls, encoding, etc.). -3. `runtime.report()`: DON produces a signed `ReportResponse`. -4. `sendReport()`: format and POST to your URL. +3. [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime): DON produces a signed `ReportResponse`. +4. [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport): format and POST to your URL. ## Prerequisites - Familiarity with [making POST requests](/cre/guides/workflow/using-http-client/post-request) -- Familiarity with `runtime.report()` (covered [below](#generating-reports-for-http-submission)) +- Familiarity with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) (covered [below](#generating-reports-for-http-submission)) - **`viem`** as a direct dependency in the workflow `package.json` (for ABI encoding in examples) - Protobuf HTTP/report types from **`@chainlink/cre-sdk/pb`** (`SDK_PB.ReportResponse`, `HTTP_CLIENT_PB.RequestJson`), not the main `@chainlink/cre-sdk` entry @@ -15095,7 +15108,7 @@ const submitReport = (sendRequester: HTTPSendRequester, report: Report): { succe **What's happening here:** 1. `formatReportSimple` transforms the report into an HTTP request that your API understands -2. `sendRequester.sendReport()` calls your transformation function and sends the request +2. [`sendRequester.sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) calls your transformation function and sends the request 3. The SDK handles consensus and returns the result The rest of this guide explains how this works and shows different formatting patterns for various API requirements. @@ -15104,7 +15117,7 @@ The rest of this guide explains how this works and shows different formatting pa ### The report structure -When you call `runtime.report()`, the SDK creates a `ReportResponse` containing: +After [consensus](/cre/key-terms#consensus), [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) returns a `ReportResponse`: the wire-format view of a [CRE report](/cre/key-terms#report-cre-report). It contains: ```typescript interface ReportResponse { @@ -15133,7 +15146,7 @@ Your transformation function tells the SDK how to format the report for your API **The SDK calls this function internally:** -1. You pass your transformation function to `sendReport()` +1. You pass your transformation function to [`sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport) 2. The SDK calls it with the generated `ReportResponse` 3. Your function returns a `RequestJson` formatted for your API 4. The SDK sends the request and handles consensus @@ -15383,7 +15396,7 @@ This approach is reliable because the `rawReport` is identical across all nodes ## Generating reports for HTTP submission -Before you can submit a report via HTTP, you need to generate it using `runtime.report()`. This creates a cryptographically signed report from your encoded data. +Before you can submit a report via HTTP, you need to generate it using [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). This creates a cryptographically signed report from your encoded data. **Basic pattern:** @@ -15407,11 +15420,11 @@ const report = runtime // Step 3: Submit via HTTP (covered in next section) ``` -The `runtime.report()` method works the same way whether you're encoding a single value or a struct—just use Viem's `encodeAbiParameters()` with the appropriate ABI types. For detailed examples on encoding single values, structs, and complex types, see the [Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain) guide. +The [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) method works the same way whether you're encoding a single value or a struct—just use Viem's `encodeAbiParameters()` with the appropriate ABI types. For detailed examples on encoding single values, structs, and complex types, see the [Writing Data Onchain](/cre/guides/workflow/using-evm-client/onchain-write/writing-data-onchain) guide. ## Using `sendReport()` (recommended approach) -Use the high-level `httpClient.sendRequest()` pattern with `sendRequester.sendReport()`: +Use the high-level `httpClient.sendRequest()` pattern with [`sendRequester.sendReport()`](/cre/reference/sdk/http-client-ts#using-sendreport): ```typescript import { @@ -15662,7 +15675,7 @@ const onCronTrigger = (runtime: Runtime): MyResult => { ## Troubleshooting @@ -15703,11 +15716,11 @@ This guide is for the **receiver** side: you already received a CRE report packa When a workflow delivers results via HTTP (or another offchain channel), nothing onchain automatically validates the report. **You must verify signatures before trusting the data.** -The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. +The CRE SDK provides [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) to do this inside a workflow. Verification runs **offchain** in your callback: signatures are checked with local cryptography, while authorized signer addresses are loaded via **read-only calls to the onchain Capability Registry** (default: Ethereum Mainnet). Results are cached per DON. @@ -15715,20 +15728,26 @@ The CRE SDK provides `Report.parse()` to do this inside a workflow. Verification When you submit reports onchain through the `KeystoneForwarder`, the forwarder contract verifies signatures before calling your consumer's `onReport`. This guide covers **offchain** verification for HTTP and custom ingest paths. See [Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain). +## What is a CRE report? + +A **[CRE report](/cre/key-terms#report-cre-report)** is a DON-signed package another workflow (or system) created with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). You receive its bytes over HTTP (or another channel) as `rawReport`, `reportContext`, and `signatures`. Before you use the encoded payload, you must confirm the signatures match authorized DON signers on the Capability Registry. + +This guide is the **receiver** path: decode the POST body, call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification), then read trusted metadata and `body()`. See [Key Terms: Report](/cre/key-terms#report-cre-report) for how reports are created and delivered. + ## Where this guide fits -| Question | Answer | -| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| What is the report? | Same CRE report the **sender** created with `runtime.report()`. See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#where-this-guide-fits). | -| Where does it come from? | Another workflow (or system) already ran sender steps: logic → `runtime.report()` → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | -| What does this guide cover? | Step 3 below: `Report.parse()` before you use `body()` or take side effects. | -| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | +| Question | Answer | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| What is the report? | Same [CRE report](/cre/key-terms#report-cre-report) the **sender** created with [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime). See [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#what-is-a-cre-report). | +| Where does it come from? | Another workflow (or system) already ran sender steps: logic → [`runtime.report()`](/cre/reference/sdk/core-ts#runtime-and-noderuntime) → HTTP POST. You receive `rawReport`, `context`, and `signatures` in the request body. | +| What does this guide cover? | Step 3 below: [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) before you use `body()` or take side effects. | +| Same workflow as the sender? | Often **no:** common pattern is Workflow A (publish) and Workflow B (ingest with HTTP trigger). | **Receiver flow:** 1. HTTP trigger (or your API) receives the POST payload. 2. Decode hex fields into bytes. -3. `Report.parse()`: verify signatures and read metadata. +3. [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification): verify signatures and read metadata. 4. Use trusted `body()` in your logic. Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts) on the sender side. This guide covers local simulation first, then the deploy example with `authorizedKeys`. @@ -15736,7 +15755,7 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## What you'll learn - When to verify reports offchain vs relying on onchain forwarders -- How `Report.parse()` validates signatures and reads metadata +- How [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) validates signatures and reads metadata - How to build a receiver workflow that accepts reports over HTTP - How to restrict verification to specific CRE environments or zones @@ -15748,12 +15767,12 @@ Pair this guide with [Submitting Reports via HTTP](/cre/guides/workflow/using-ht ## Onchain vs offchain verification -| Aspect | Offchain (`Report.parse`) | Onchain (`KeystoneForwarder`) | -| -------------------- | ------------------------------------------------------------ | --------------------------------- | -| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | -| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | -| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | -| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | +| Aspect | Offchain ([`Report.parse()`](/cre/reference/sdk/core-ts#report-verification)) | Onchain (`KeystoneForwarder`) | +| -------------------- | ----------------------------------------------------------------------------- | --------------------------------- | +| **Where it runs** | Inside your CRE workflow callback | In a smart contract transaction | +| **Signature check** | Local `ecrecover` on report hash | Contract logic onchain | +| **Signer allowlist** | Read from Capability Registry (`getDON`, `getNodesByP2PIds`) | Forwarder + registry | +| **Typical use** | HTTP APIs, webhooks, ingest workflows | Consumer contracts via `onReport` | Offchain verification still uses **onchain data as a trust anchor**: the first time a DON is seen, the SDK reads the production Capability Registry on Ethereum Mainnet to learn `f` and authorized signer addresses. @@ -15769,7 +15788,7 @@ Default (`productionEnvironment()`): 3. **Verify signatures**: compute `keccak256(keccak256(rawReport) || reportContext)`, recover signers, require **f+1** valid signatures from authorized nodes. 4. **Return a `Report` object** with accessors for workflow ID, owner, execution ID, body, and more. -If verification fails, `Report.parse()` throws (for example, unknown signer, insufficient signatures, or registry read failure). +If verification fails, [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) throws (for example, unknown signer, insufficient signatures, or registry read failure). ## Testing locally with simulation @@ -15781,14 +15800,14 @@ After you run the [submit guide complete example](/cre/guides/workflow/using-htt ### Sim wiring vs full verify -| Mode | Config | What it validates | -| ---------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Wiring / decode** | `skipSignatureVerification: true` in staging config | JSON + hex decode, `workflowId()`, `executionId()`, `donId()`, `body()` | -| **Full crypto verify** | Default `Report.parse()` (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification: simulation uses local DON keys; `Report.parse()` checks the mainnet Capability Registry. | +| Mode | Config | What it validates | +| ---------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Wiring / decode** | `skipSignatureVerification: true` in staging config | JSON + hex decode, `workflowId()`, `executionId()`, `donId()`, `body()` | +| **Full crypto verify** | Default [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) (production registry) | Reports from a **deployed/production DON**. Sim-signed reports **fail** default verification: simulation uses local DON keys; [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) checks the mainnet Capability Registry. | ### Minimal receiver for simulation -Use an **empty HTTP trigger config** for sim (add `authorizedKeys` before deploy). Call `Report.parse()` from your handler with the `runtime` parameter. The CLI delivers `--http-payload` file contents as `payload.input` bytes. +Use an **empty HTTP trigger config** for sim (add `authorizedKeys` before deploy). Call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) from your handler with the `runtime` parameter. The CLI delivers `--http-payload` file contents as `payload.input` bytes. `config.staging.json`: @@ -15949,7 +15968,7 @@ export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) **What's happening:** 1. An external system POSTs hex-encoded `report`, `context`, and `signatures` to your HTTP trigger. -2. `Report.parse()` verifies signatures against the production CRE registry. +2. [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) verifies signatures against the production CRE registry. 3. On success, you read metadata and `body()` safely. @@ -15959,7 +15978,7 @@ export const initWorkflow = (config: Config, _secretsProvider: SecretsProvider) ## Report payload format -Receivers need three JSON fields (plus optional metadata your API may add). The JSON key is `context` even though the SDK field is `reportContext`: +When a sender POSTs a [CRE report](/cre/key-terms#report-cre-report) as JSON for offchain verification, receivers need three fields (plus optional metadata your API may add). The JSON key is `context` even though the SDK field is `reportContext`: | JSON field | SDK field | Description | | ------------ | --------------- | --------------------------------------------------------------- | @@ -16018,17 +16037,17 @@ const config: ReportParseConfig = { } ``` -| Option | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `acceptedEnvironments` | Registry environments to check (defaults to production) | -| `acceptedZones` | Restrict to specific DON IDs within an environment | -| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript; call `Report.parse()` without this flag for production verification. | +| Option | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `acceptedEnvironments` | Registry environments to check (defaults to production) | +| `acceptedZones` | Restrict to specific DON IDs within an environment | +| `skipSignatureVerification` | Parse metadata only, without registry reads or signature checks. Use only for testing or when another layer verifies signatures. There is no separate `verifySignatures()` on `Report` in TypeScript; call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) without this flag for production verification. | Most workflows should use the default config (production environment only). ## Best practices -1. **Verify before side effects**: Call `Report.parse()` before writing to databases, chains, or external systems. +1. **Verify before side effects**: Call [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) before writing to databases, chains, or external systems. 2. **Permission on metadata**: After verification, check `workflowId()`, `workflowOwner()`, or `donId()` match your expectations. 3. **Deduplicate by execution ID**: Use `executionId()` or `keccak256(rawReport)` to reject replays (see [Submitting Reports via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http-ts#understanding-cachesettings-for-reports)). 4. **Do not skip signature verification in production** unless you have another trust path. @@ -16037,12 +16056,12 @@ Most workflows should use the default config (production environment only). **Empty error after verify sim** -- `Report.parse()` may throw an **`AggregateError`** of multiple `invalid signature` errors. **`AggregateError.message` is often empty**, so the CLI prints `Execution resulted in an error being returned:` with nothing after the colon. +- [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) may throw an **`AggregateError`** of multiple `invalid signature` errors. **`AggregateError.message` is often empty**, so the CLI prints `Execution resulted in an error being returned:` with nothing after the colon. - Format errors in your handler before rethrowing (see the simulation example above). **`invalid signature` / `unknown signer` in sim with fresh webhook JSON** -- **Expected** when using default `Report.parse()` on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. +- **Expected** when using default [`Report.parse()`](/cre/reference/sdk/core-ts#report-verification) on a **sim-signed** report: simulator DON keys do not match mainnet registry signers. - For local wiring tests, set `skipSignatureVerification: true`. For real crypto verify, use a **deployed sender** or production-signed reports. **`invalid signature` / `unknown signer` (deployed)**