Skip to content

Commit c5d5576

Browse files
committed
verifying tx status guides
1 parent 4d3022b commit c5d5576

File tree

3 files changed

+500
-30
lines changed

3 files changed

+500
-30
lines changed

reports/llms-report.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
{
2-
"startedAt": "2025-12-08T14:07:09.016Z",
2+
"startedAt": "2025-12-08T23:32:35.641Z",
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": 651667,
10-
"prevBytes": 651944,
11-
"deltaBytes": -277
9+
"bytes": 662832,
10+
"prevBytes": 651667,
11+
"deltaBytes": 11165
1212
},
1313
{
1414
"section": "cre-ts",
15-
"pagesProcessed": 78,
15+
"pagesProcessed": 79,
1616
"outputPath": "src/content/cre/llms-full-ts.txt",
17-
"bytes": 607170,
18-
"prevBytes": 607447,
19-
"deltaBytes": -277
17+
"bytes": 617294,
18+
"prevBytes": 607170,
19+
"deltaBytes": 10124
2020
},
2121
{
2222
"section": "vrf",
@@ -31,8 +31,8 @@
3131
"pagesProcessed": 260,
3232
"outputPath": "src/content/ccip/llms-full.txt",
3333
"bytes": 2849877,
34-
"prevBytes": 2849781,
35-
"deltaBytes": 96
34+
"prevBytes": 2849877,
35+
"deltaBytes": 0
3636
},
3737
{
3838
"section": "data-feeds",
@@ -123,5 +123,5 @@
123123
"deltaBytes": 0
124124
}
125125
],
126-
"finishedAt": "2025-12-08T14:07:12.967Z"
126+
"finishedAt": "2025-12-08T23:32:40.058Z"
127127
}

src/content/cre/llms-full-go.txt

Lines changed: 246 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10381,6 +10381,232 @@ Solidity types like `bytes` and `bytes32` map to `[]byte` in Go.
1038110381

1038210382
---
1038310383

10384+
# Verifying Transaction Status
10385+
Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/onchain-write/verifying-transaction-status-go
10386+
Last Updated: 2025-12-08
10387+
10388+
When your workflow writes data to the blockchain, you can verify both that the transaction was mined and that your consumer contract successfully processed the data. This guide explains how to properly check both levels of execution.
10389+
10390+
<Aside type="note" title="Prerequisites">
10391+
This guide assumes you're already familiar with how CRE's onchain write process works. If you haven't read it yet,
10392+
start with [Onchain Write Overview](/cre/guides/workflow/using-evm-client/onchain-write/overview-go) to understand the
10393+
secure write flow.
10394+
</Aside>
10395+
10396+
## Why two levels of verification?
10397+
10398+
Your workflow's data goes through a two-tier transaction model:
10399+
10400+
1. **Outer Transaction**: Your workflow → `KeystoneForwarder` contract (on the blockchain)
10401+
2. **Inner Execution**: `KeystoneForwarder` → Your [consumer contract](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)'s `onReport()` function
10402+
10403+
A common mistake is only checking the outer transaction status. **The transaction can succeed while your consumer contract's `onReport()` function reverts.**
10404+
10405+
## Understanding the status fields
10406+
10407+
When you call `WriteReport()` on the EVM client and await the promise, you receive a `WriteReportReply` struct. This struct contains the complete results of your write operation, including two status indicators:
10408+
10409+
| Field | What it checks | Success means | Failure means |
10410+
| --------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
10411+
| `TxStatus` | Was the transaction mined on the blockchain? | Forwarder received and processed the report | Network issues, insufficient gas, or forwarder rejected the report |
10412+
| `ReceiverContractExecutionStatus` | Did YOUR consumer contract's `onReport()` complete without reverting? | All validation passed (if any), `_processReport()` executed successfully | Forwarder validation failed, workflow ID mismatch, or your business logic reverted |
10413+
10414+
<Aside type="caution" title="Simulation Limitation">
10415+
The `receiverContractExecutionStatus` field is currently not populated during workflow simulation. This verification
10416+
only works in production environments. During simulation, you can only verify that the transaction to the Forwarder
10417+
succeeded (`txStatus`), but cannot detect if your consumer contract's `onReport()` function reverted.
10418+
</Aside>
10419+
10420+
## The complete verification pattern
10421+
10422+
### Only checks outer transaction
10423+
10424+
```go
10425+
resp, err := writePromise.Await()
10426+
if err != nil {
10427+
return fmt.Errorf("write failed: %w", err)
10428+
}
10429+
10430+
// INCOMPLETE: Only verifies the transaction was mined
10431+
if resp.TxStatus == evm.TxStatus_TX_STATUS_SUCCESS {
10432+
logger.Info("Transaction succeeded")
10433+
return nil
10434+
}
10435+
```
10436+
10437+
**Problem**: Your consumer contract could have reverted, but you'd never know because you only checked if the transaction was mined.
10438+
10439+
### Checks both levels
10440+
10441+
```go
10442+
resp, err := writePromise.Await()
10443+
if err != nil {
10444+
return fmt.Errorf("write failed: %w", err)
10445+
}
10446+
10447+
// Step 1: Check outer transaction status
10448+
if resp.TxStatus != evm.TxStatus_TX_STATUS_SUCCESS {
10449+
return fmt.Errorf("transaction failed with status: %v", resp.TxStatus)
10450+
}
10451+
10452+
// Step 2: Check consumer contract execution status
10453+
if resp.ReceiverContractExecutionStatus != nil &&
10454+
*resp.ReceiverContractExecutionStatus == evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED {
10455+
logger.Error("Consumer contract reverted",
10456+
"error", resp.GetErrorMessage(),
10457+
"txHash", common.BytesToHash(resp.TxHash).Hex())
10458+
return fmt.Errorf("consumer contract execution failed: %s", resp.GetErrorMessage())
10459+
}
10460+
10461+
logger.Info("Both transaction AND consumer contract execution succeeded",
10462+
"txHash", common.BytesToHash(resp.TxHash).Hex())
10463+
```
10464+
10465+
**What this checks**:
10466+
10467+
1. Transaction was mined successfully
10468+
2. Your consumer contract's `onReport()` function executed without reverting
10469+
3. Your business logic completed successfully
10470+
10471+
## Common scenarios
10472+
10473+
### Scenario 1: Everything succeeded
10474+
10475+
```go
10476+
// Transaction mined + Consumer contract executed successfully
10477+
TxStatus: TX_STATUS_SUCCESS
10478+
ReceiverContractExecutionStatus: RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS
10479+
```
10480+
10481+
**What happened**: The report was delivered and your contract processed it successfully.
10482+
10483+
**Action**: None needed - everything worked as expected.
10484+
10485+
### Scenario 2: Transaction succeeded, but contract reverted
10486+
10487+
```go
10488+
// Transaction was mined, but your contract rejected the data
10489+
TxStatus: TX_STATUS_SUCCESS
10490+
ReceiverContractExecutionStatus: RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED
10491+
```
10492+
10493+
**What happened**: The forwarder successfully submitted the transaction, but your consumer contract's `onReport()` function reverted during execution.
10494+
10495+
**Common causes**:
10496+
10497+
- Forwarder address mismatch: You configured the wrong forwarder address in your consumer contract (simulation forwarders are different from production forwarders - see [Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks-go))
10498+
- Security check failed (if you configured expected values for workflow ID, owner, or name in your contract)
10499+
- Custom validation in `_processReport()` rejected the data
10500+
- ABI decoding failure (struct mismatch between workflow and contract)
10501+
- Custom business logic constraints not met
10502+
10503+
**Action**: Check the error message and review your consumer contract's validation logic. If moving from simulation to production, ensure you updated the forwarder address in your contract.
10504+
10505+
### Scenario 3: Transaction failed
10506+
10507+
```go
10508+
// Transaction failed to be mined
10509+
TxStatus: TX_STATUS_REVERTED or TX_STATUS_FATAL
10510+
ReceiverContractExecutionStatus: N/A
10511+
```
10512+
10513+
**What happened**: The transaction couldn't be mined on the blockchain.
10514+
10515+
**Common causes**:
10516+
10517+
- Insufficient gas
10518+
- Network connectivity issues
10519+
- Incorrect forwarder address
10520+
- RPC endpoint problems
10521+
10522+
**Action**: Check RPC endpoint, gas configuration, network status, and forwarder address.
10523+
10524+
## Best practices helper function
10525+
10526+
Create a reusable helper to verify both status levels:
10527+
10528+
```go
10529+
// verifyWriteSuccess checks both transaction and contract execution status
10530+
func verifyWriteSuccess(resp *evm.WriteReportReply, logger *slog.Logger) error {
10531+
// Check outer transaction
10532+
if resp.TxStatus != evm.TxStatus_TX_STATUS_SUCCESS {
10533+
return fmt.Errorf("transaction failed with status %v", resp.TxStatus)
10534+
}
10535+
10536+
// Check consumer contract execution
10537+
if resp.ReceiverContractExecutionStatus != nil &&
10538+
*resp.ReceiverContractExecutionStatus == evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED {
10539+
errorMsg := "unknown error"
10540+
if resp.ErrorMessage != nil {
10541+
errorMsg = *resp.ErrorMessage
10542+
}
10543+
return fmt.Errorf("consumer contract reverted: %s", errorMsg)
10544+
}
10545+
10546+
// Log success with transaction hash
10547+
txHash := common.BytesToHash(resp.TxHash).Hex()
10548+
logger.Info("Write verification succeeded",
10549+
"txHash", txHash,
10550+
"txStatus", resp.TxStatus,
10551+
"contractStatus", resp.ReceiverContractExecutionStatus)
10552+
10553+
return nil
10554+
}
10555+
10556+
// Usage in your workflow
10557+
func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) {
10558+
logger := runtime.Logger()
10559+
10560+
// ... prepare data and write report ...
10561+
10562+
writePromise := contract.WriteReportFromMyData(runtime, data, nil)
10563+
resp, err := writePromise.Await()
10564+
if err != nil {
10565+
return nil, fmt.Errorf("write report await failed: %w", err)
10566+
}
10567+
10568+
// Use the helper for complete verification
10569+
if err := verifyWriteSuccess(resp, logger); err != nil {
10570+
return nil, err
10571+
}
10572+
10573+
return &MyResult{TxHash: common.BytesToHash(resp.TxHash).Hex()}, nil
10574+
}
10575+
```
10576+
10577+
## Accessing error details
10578+
10579+
The `WriteReportReply` provides multiple ways to access error information:
10580+
10581+
```go
10582+
resp, err := writePromise.Await()
10583+
if err != nil {
10584+
return fmt.Errorf("await failed: %w", err)
10585+
}
10586+
10587+
// Option 1: Direct field access (pointer, can be nil)
10588+
if resp.ErrorMessage != nil {
10589+
logger.Error("Error message (direct)", "message", *resp.ErrorMessage)
10590+
}
10591+
10592+
// Option 2: Using the getter method (safer, returns empty string if nil)
10593+
logger.Info("Error message (getter)", "message", resp.GetErrorMessage())
10594+
10595+
// Option 3: Check status enum
10596+
logger.Info("Contract execution status", "status", resp.GetReceiverContractExecutionStatus())
10597+
```
10598+
10599+
**Best practice**: Use the getter methods (`GetErrorMessage()`, `GetReceiverContractExecutionStatus()`) as they handle nil values safely.
10600+
10601+
## Related resources
10602+
10603+
- **[EVM Client Reference](/cre/reference/sdk/evm-client-go#evmwritereportreply)** - Complete API documentation for `WriteReportReply`, including all field definitions and status constant values
10604+
- **[Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts)** - Learn about forwarder validation and the `IReceiver` interface
10605+
- **[Supported Networks](/cre/guides/workflow/using-evm-client/supported-networks)** - Forwarder addresses for simulation and production
10606+
- **[Submitting Reports Onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain)** - Complete guide to the write process
10607+
10608+
---
10609+
1038410610
# EVM Chain Interactions
1038510611
Source: https://docs.chain.link/cre/guides/workflow/using-evm-client/overview-go
1038610612
Last Updated: 2025-11-04
@@ -13543,13 +13769,26 @@ func (c *Client) WriteReport(runtime cre.Runtime, input *WriteCreReportRequest)
1354313769

1354413770
#### `evm.WriteReportReply`
1354513771

13546-
| Field | Type | Description |
13547-
| --------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------- |
13548-
| `TxStatus` | `TxStatus` | The final status of the transaction: `SUCCESS`, `REVERTED`, or `FATAL`. |
13549-
| `ReceiverContractExecutionStatus` | `*ReceiverContractExecutionStatus` | Optional. The status of the receiver contract's execution: `SUCCESS` or `REVERTED`. |
13550-
| `TxHash` | `[]byte` | Optional. The 32-byte transaction hash of the onchain submission. |
13551-
| `TransactionFee` | `*pb.BigInt` | Optional. The total fee paid for the transaction in Wei. |
13552-
| `ErrorMessage` | `*string` | Optional. An error message if the transaction failed. |
13772+
| Field | Type | Description |
13773+
| --------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13774+
| `TxStatus` | `TxStatus` | The final status of the transaction: `evm.TxStatus_TX_STATUS_SUCCESS`, `evm.TxStatus_TX_STATUS_REVERTED`, or `evm.TxStatus_TX_STATUS_FATAL`. |
13775+
| `ReceiverContractExecutionStatus` | `*ReceiverContractExecutionStatus` | Optional. The status of the receiver contract's execution: `evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS` or `evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED`. |
13776+
| `TxHash` | `[]byte` | Optional. The 32-byte transaction hash of the onchain submission. |
13777+
| `TransactionFee` | `*pb.BigInt` | Optional. The total fee paid for the transaction in Wei. |
13778+
| `ErrorMessage` | `*string` | Optional. An error message if the transaction failed. |
13779+
13780+
**Status constants:**
13781+
13782+
```go
13783+
// TxStatus values
13784+
evm.TxStatus_TX_STATUS_SUCCESS // = 2
13785+
evm.TxStatus_TX_STATUS_REVERTED // = 1
13786+
evm.TxStatus_TX_STATUS_FATAL // = 0
13787+
13788+
// ReceiverContractExecutionStatus values
13789+
evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_SUCCESS // = 0
13790+
evm.ReceiverContractExecutionStatus_RECEIVER_CONTRACT_EXECUTION_STATUS_REVERTED // = 1
13791+
```
1355313792

1355413793
## Chain Selectors
1355513794

0 commit comments

Comments
 (0)