Skip to content

Commit ac1d527

Browse files
authored
Finality, confidence levels, custom depth (#3247)
* add finality & confidence levels docs * add finality & confidence levels docs * add finality & confidence levels docs * finality clarifications + custom block depth support for chain reads * nit one liner code improvement * clarifications * add chain write finality + reorg * update custom depth w/ new helpers * nit update dates * nit clarification * llm gen
1 parent f1cb0b8 commit ac1d527

File tree

12 files changed

+744
-97
lines changed

12 files changed

+744
-97
lines changed

reports/llms-report.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
{
2-
"startedAt": "2025-12-10T23:13:13.756Z",
2+
"startedAt": "2025-12-11T12:22:09.628Z",
33
"siteBase": "https://docs.chain.link",
44
"sections": [
55
{
66
"section": "cre-go",
7-
"pagesProcessed": 83,
7+
"pagesProcessed": 84,
88
"outputPath": "src/content/cre/llms-full-go.txt",
9-
"bytes": 656030,
10-
"prevBytes": 656030,
9+
"bytes": 667067,
10+
"prevBytes": 667067,
1111
"deltaBytes": 0
1212
},
1313
{
1414
"section": "cre-ts",
15-
"pagesProcessed": 78,
15+
"pagesProcessed": 79,
1616
"outputPath": "src/content/cre/llms-full-ts.txt",
17-
"bytes": 612048,
18-
"prevBytes": 612048,
19-
"deltaBytes": 0
17+
"bytes": 623424,
18+
"prevBytes": 623539,
19+
"deltaBytes": -115
2020
},
2121
{
2222
"section": "vrf",
@@ -123,5 +123,5 @@
123123
"deltaBytes": 0
124124
}
125125
],
126-
"finishedAt": "2025-12-10T23:13:17.715Z"
126+
"finishedAt": "2025-12-11T12:22:14.025Z"
127127
}

src/config/sidebar.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,11 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = {
418418
title: "TypeScript Runtime Environment",
419419
url: "cre/concepts/typescript-wasm-runtime",
420420
},
421+
{
422+
title: "Finality & Confidence Levels",
423+
url: "cre/concepts/finality",
424+
highlightAsCurrent: ["cre/concepts/finality-go", "cre/concepts/finality-ts"],
425+
},
421426
],
422427
},
423428
{
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
section: cre
3+
title: "Finality and Confidence Levels"
4+
date: Last Modified
5+
sdkLang: "go"
6+
pageId: "concepts-finality"
7+
metadata:
8+
description: "Understand how CRE handles blockchain finality across different chains, including confidence levels, finality tags, and block depth configurations."
9+
datePublished: "2025-12-10"
10+
lastModified: "2025-12-10"
11+
---
12+
13+
import { Aside, CopyText } from "@components"
14+
15+
Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change.
16+
17+
Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation.
18+
19+
## Understanding CRE's finality model
20+
21+
CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains.
22+
23+
### The three confidence levels
24+
25+
| Confidence Level | Description | Use Case |
26+
| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
27+
| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. |
28+
| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. |
29+
| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. |
30+
31+
**Choosing the right level:**
32+
33+
- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues
34+
- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting)
35+
- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy
36+
37+
### How confidence levels map to chains
38+
39+
**SAFE and LATEST:**
40+
41+
CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains.
42+
43+
**FINALIZED:**
44+
45+
When you specify `FINALIZED` in your workflow, CRE automatically maps this to a native finality tag or a block depth threshold depending on the chain.
46+
47+
| Chain | Finality Method | Block Depth |
48+
| ------------------------------- | ---------------------------- | ----------- |
49+
| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag ||
50+
| Avalanche / Avalanche Fuji | Native `finalized` tag ||
51+
| Base / Base Sepolia | Native `finalized` tag ||
52+
| BNB Chain / BNB Testnet | Native `finalized` tag ||
53+
| Ethereum / Ethereum Sepolia | Native `finalized` tag ||
54+
| OP Mainnet / OP Sepolia | Native `finalized` tag ||
55+
| Polygon / Polygon Amoy | Block depth (500 blocks ago) | 500 |
56+
57+
## Finality for chain reads
58+
59+
Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-go#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-go#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-go#filterlogs), etc.) support confidence levels and custom block depths.
60+
61+
### Using confidence levels
62+
63+
For most read operations, use the standard confidence levels by passing `-2` (latest) or `-3` (finalized) as the `BlockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`.
64+
65+
**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported.
66+
67+
### Custom block depths
68+
69+
For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to:
70+
71+
- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks")
72+
- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds
73+
- Query historical state at specific past block heights for analysis or verification
74+
75+
**When to use custom block depths:**
76+
77+
- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors
78+
- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant
79+
- **Historical verification** — You need to verify state at a specific moment
80+
81+
**Implementation:**
82+
83+
You can pass any `*big.Int` directly as the `BlockNumber` parameter. The SDK accepts both special values (like `-2` for latest, `-3` for finalized) and positive integers for explicit block heights. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-go#custom-block-depths) for examples.
84+
85+
## Finality for chain writes
86+
87+
Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) when the transaction is included in a block, not when it reaches finality.
88+
89+
### What a successful response means
90+
91+
When [`WriteReportReply`](/cre/reference/sdk/evm-client-go#evmwritereportreply) returns with `TxStatus` equal to `SUCCESS`:
92+
93+
- Your transaction was **included in a block**
94+
- The transaction is **not necessarily finalized** yet
95+
96+
The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized.
97+
98+
### Reorg handling
99+
100+
If a block containing your transaction is reorganized:
101+
102+
- CRE's Transaction Manager (TXM) automatically resubmits your transaction
103+
- Gas bumping is applied as needed to ensure the transaction is included
104+
- **Important:** The transaction hash may change during resubmission
105+
- You are not automatically notified if the hash changes
106+
107+
<Aside type="caution" title="For mission-critical applications">
108+
If you need absolute certainty that your write transaction reached finality, implement post-write verification by
109+
reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for
110+
finality confirmation.
111+
</Aside>
112+
113+
## Finality for event triggers
114+
115+
EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers.
116+
117+
By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-go#evmfilterlogtriggerrequest).
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
---
2+
section: cre
3+
title: "Finality and Confidence Levels"
4+
date: Last Modified
5+
sdkLang: "ts"
6+
pageId: "concepts-finality"
7+
metadata:
8+
description: "Understand how CRE handles blockchain finality across different chains, including confidence levels, finality tags, and block depth configurations."
9+
datePublished: "2025-12-10"
10+
lastModified: "2025-12-10"
11+
---
12+
13+
import { Aside, CopyText } from "@components"
14+
15+
Finality determines when a blockchain transaction is considered irreversible. Until a block is finalized, it could be reorganized (replaced by a different block if the chain temporarily forks), which means any data you read from it might change.
16+
17+
Different blockchains achieve finality in different ways and at different speeds. CRE abstracts these differences through **confidence levels**, allowing you to specify your finality requirements without needing to know the underlying chain-specific implementation.
18+
19+
## Understanding CRE's finality model
20+
21+
CRE provides three confidence levels for reading blockchain data and monitoring events. These levels work consistently across all supported chains.
22+
23+
### The three confidence levels
24+
25+
| Confidence Level | Description | Use Case |
26+
| ---------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
27+
| **`LATEST`** | The most recent block. No finality guarantees—the block could still be reorganized. | Non-critical, time-sensitive operations where speed matters more than certainty. |
28+
| **`SAFE`** | A block that is unlikely to be reorganized, but not yet fully finalized. | A balance between speed and security for most operations. |
29+
| **`FINALIZED`** | A block that is considered irreversible. This is the safest option. | Critical operations where you need absolute certainty the data won't change. |
30+
31+
**Choosing the right level:**
32+
33+
- **`FINALIZED`** — Use for financial transactions, critical state updates, or when incorrect data could cause significant issues
34+
- **`SAFE`** — Use when you need reasonable confidence without waiting for full finality (good for most monitoring/alerting)
35+
- **`LATEST`** — Use for real-time dashboards or displays where speed matters more than guaranteed accuracy
36+
37+
### How confidence levels map to chains
38+
39+
**SAFE and LATEST:**
40+
41+
CRE uses the chain's native `safe` and `latest` block tags respectively for all supported chains.
42+
43+
**FINALIZED:**
44+
45+
When you specify `FINALIZED` in your workflow, CRE automatically maps this to its finality method—whether it uses the native finality tag or block depth (with the number of blocks specified for block depth).
46+
47+
| Chain | Finality Method |
48+
| ------------------------------- | ------------------------ |
49+
| Arbitrum One / Arbitrum Sepolia | Native `finalized` tag |
50+
| Avalanche / Avalanche Fuji | Native `finalized` tag |
51+
| Base / Base Sepolia | Native `finalized` tag |
52+
| BNB Chain / BNB Testnet | Native `finalized` tag |
53+
| Ethereum / Ethereum Sepolia | Native `finalized` tag |
54+
| OP Mainnet / OP Sepolia | Native `finalized` tag |
55+
| Polygon / Polygon Amoy | Block depth (500 blocks) |
56+
57+
## Finality for chain reads
58+
59+
Chain read operations ([`CallContract`](/cre/reference/sdk/evm-client-ts#callcontract), [`BalanceAt`](/cre/reference/sdk/evm-client-ts#balanceat), [`FilterLogs`](/cre/reference/sdk/evm-client-ts#filterlogs), etc.) support confidence levels and custom block depths.
60+
61+
### Using confidence levels
62+
63+
For most read operations, use the standard confidence levels by passing [`LATEST_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#latest_block_number) or [`LAST_FINALIZED_BLOCK_NUMBER`](/cre/reference/sdk/evm-client-ts#last_finalized_block_number) as the `blockNumber` parameter. If you don't specify a block number, CRE defaults to `LATEST`.
64+
65+
**Note:** The `SAFE` confidence level is not available for chain reads—only `LATEST` and `FINALIZED` are supported.
66+
67+
### Custom block depths
68+
69+
For use cases requiring fixed confirmation thresholds or historical state verification, you can specify **any explicit block number** instead of using the predefined confidence levels. This enables you to:
70+
71+
- Implement custom finality rules tailored to your risk profile (e.g., "always wait 1,000 blocks")
72+
- Meet regulatory requirements that mandate fixed, auditable confirmation thresholds
73+
- Query historical state at specific past block heights for analysis or verification
74+
75+
**When to use custom block depths:**
76+
77+
- **Regulatory compliance** — Your interactions require provable, fixed confirmation thresholds for auditors
78+
- **Changing chain parameters** — The chain's finality definition may change, but your security model must remain constant
79+
- **Historical verification** — You need to verify state at a specific moment
80+
81+
**Implementation:**
82+
83+
Block numbers must be provided as `BigIntJson` objects. See [Onchain Read](/cre/guides/workflow/using-evm-client/onchain-read-ts#custom-block-depths) for the conversion pattern and examples.
84+
85+
## Finality for chain writes
86+
87+
Chain write operations return a [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) when the transaction is included in a block, not when it reaches finality.
88+
89+
### What a successful response means
90+
91+
When [`WriteReportReply`](/cre/reference/sdk/evm-client-ts#writereportreply) returns with `txStatus` equal to `TX_STATUS_SUCCESS`:
92+
93+
- Your transaction was **included in a block**
94+
- The transaction is **not necessarily finalized** yet
95+
96+
The reply is returned as soon as the transaction appears in a block, not when the block reaches finality. This is important for time-sensitive workflows, but it means the transaction could still be reorganized.
97+
98+
### Reorg handling
99+
100+
If a block containing your transaction is reorganized:
101+
102+
- CRE's Transaction Manager (TXM) automatically resubmits your transaction
103+
- Gas bumping is applied as needed to ensure the transaction is included
104+
- **Important:** The transaction hash may change during resubmission
105+
- You are not automatically notified if the hash changes
106+
107+
<Aside type="caution" title="For mission-critical applications">
108+
If you need absolute certainty that your write transaction reached finality, implement post-write verification by
109+
reading the blockchain state after a custom number of confirmations. Do not rely solely on `WriteReportReply` for
110+
finality confirmation.
111+
</Aside>
112+
113+
## Finality for event triggers
114+
115+
EVM Log Triggers must use the three confidence levels (`LATEST`, `SAFE`, or `FINALIZED`). Custom block depths are not supported for triggers.
116+
117+
By default, triggers use `SAFE` if no confidence level is specified. For details on configuring trigger confidence levels, see [EVM Log Trigger](/cre/reference/sdk/triggers/evm-log-trigger-ts#configuration).

src/content/cre/guides/workflow/using-evm-client/onchain-read-go.mdx

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ date: Last Modified
77
metadata:
88
description: "Read data from smart contracts in Go: learn to call view functions and fetch verified blockchain state in your workflows."
99
datePublished: "2025-11-04"
10-
lastModified: "2025-11-04"
10+
lastModified: "2025-12-10"
1111
---
1212

1313
import { Aside } from "@components"
@@ -153,28 +153,73 @@ When calling contract read methods, you must specify a block number. There are t
153153

154154
### Using magic numbers
155155

156-
- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block
156+
- **Finalized block**: Use `big.NewInt(-3)` to read from the latest finalized block (recommended for production)
157157
- **Latest block**: Use `big.NewInt(-2)` to read from the latest block
158-
- **Specific block**: Use `big.NewInt(blockNumber)` to read from a specific block
159158

160-
### Using rpc constants (alternative)
159+
For explicit block numbers, see [Custom block depths](#custom-block-depths) below.
161160

162-
You can also use constants from the `go-ethereum/rpc` package for better readability:
161+
### Custom block depths
162+
163+
For use cases requiring fixed confirmation thresholds (e.g., regulatory compliance) or historical state verification, you can specify an exact block number.
164+
165+
**Example 1 - Read from a specific historical block**:
166+
167+
```go
168+
// Read from block 12345678
169+
specificBlock := big.NewInt(12345678)
170+
value, err := storageContract.Get(runtime, specificBlock).Await()
171+
if err != nil {
172+
return nil, fmt.Errorf("failed to read from specific block: %w", err)
173+
}
174+
```
175+
176+
**Example 2 - Read from 500 blocks ago from latest block**:
163177

164178
```go
165179
import (
166-
"math/big"
167-
"github.com/ethereum/go-ethereum/rpc"
180+
pb "github.com/smartcontractkit/chainlink-protos/cre/go/values/pb"
168181
)
169182

170-
// For latest block
171-
reqBlockNumber := big.NewInt(rpc.LatestBlockNumber.Int64())
183+
// Helper to convert protobuf BigInt to standard library big.Int
184+
func pbBigIntToBigInt(pb *pb.BigInt) *big.Int {
185+
if pb == nil {
186+
return nil
187+
}
188+
result := new(big.Int).SetBytes(pb.AbsVal)
189+
if pb.Sign < 0 {
190+
result.Neg(result)
191+
}
192+
return result
193+
}
194+
195+
// Get the latest block number
196+
latestHeader, err := evmClient.HeaderByNumber(runtime, &evm.HeaderByNumberRequest{}).Await()
197+
if err != nil {
198+
return nil, fmt.Errorf("failed to get latest block: %w", err)
199+
}
200+
201+
// Convert protobuf BigInt to standard library big.Int
202+
latestBlockNum := pbBigIntToBigInt(latestHeader.Header.BlockNumber)
203+
customDepth := big.NewInt(500)
204+
customBlock := new(big.Int).Sub(latestBlockNum, customDepth)
172205

173-
// For finalized block
174-
reqBlockNumber := big.NewInt(rpc.FinalizedBlockNumber.Int64())
206+
// Use the custom block number with the contract binding
207+
value, err := storageContract.Get(runtime, customBlock).Await()
208+
if err != nil {
209+
return nil, fmt.Errorf("failed to read from custom block: %w", err)
210+
}
175211
```
176212

177-
Both approaches are equivalent - use whichever you find more readable in your code.
213+
**Understanding the conversion:**
214+
215+
The `pbBigIntToBigInt` helper converts the SDK's protobuf `*pb.BigInt` type (which stores the value as `AbsVal []byte` and `Sign int64`) to Go's standard library `*big.Int`. This allows you to perform arithmetic operations like subtracting 500 blocks.
216+
217+
<Aside type="note" title="SDK enhancement planned">
218+
The SDK team is working on a built-in helper to simplify this conversion. Until then, use the `pbBigIntToBigInt`
219+
helper shown above.
220+
</Aside>
221+
222+
See [Finality and Confidence Levels](/cre/concepts/finality-go) for more details on when to use custom block depths.
178223

179224
## Complete example
180225

0 commit comments

Comments
 (0)