docs: view Chainlink CRE usage examples and documentation#168
Conversation
📝 WalkthroughWalkthroughThis PR adds Chainlink Runtime Environment (CRE) integration: a CRE transport with nonce management and retry/broadcast logic, new CRE-focused documentation, and a three-workflow CRE example (write, read, cleanup) with configs, scripts, and wasm-build artifacts ignored. Changes
Sequence Diagram(s)sequenceDiagram
participant SDK as SDK Client
participant CRE as CRETransport
participant RPC as JSON-RPC Endpoint
participant SIG as Signer
rect rgb(240,248,255)
Note over SDK,CRE: Prepare & Sign
SDK->>CRE: Execute(tx)
CRE->>CRE: ensure chainID cached
CRE->>SIG: request signing (uses chainID, nonce)
SIG-->>CRE: signed tx (bytes)
end
rect rgb(255,250,205)
Note over CRE,RPC: Broadcast (first tx → nonce fetch)
alt currentNonce unknown
CRE->>RPC: user.account RPC -> get nonce
RPC-->>CRE: account nonce
CRE->>CRE: store nonce
end
CRE->>RPC: user.broadcast (pre-serialized JSON-RPC)
RPC-->>CRE: success / error (-201 with data)
end
rect rgb(255,240,245)
Note over CRE,RPC: Retry on nonce error
alt nonce-related error
CRE->>CRE: reset nonce state
CRE->>RPC: user.account RPC (refetch)
CRE->>CRE: retry executeOnce (up to 3 attempts)
end
CRE-->>SDK: final result or error
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Time Submission Status
|
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
examples/truf-cre-demo/truf-cleanup-workflow/main.go (1)
124-162: SamecreateSignerduplication as other workflows.This is identical to the implementation in the read and write workflows. See the suggestion in the read workflow review for extracting to a shared package.
🧹 Nitpick comments (9)
examples/truf-cre-demo/secrets.yaml (1)
1-1: Add example secret entries or clarify the setup with comments.The
secretsNameskey is empty, which may confuse users following this example. Since this PR aims to provide CRE usage examples, consider either:
- Including at least one example entry to guide users on the expected format, or
- Adding a comment explaining how to populate this file
This will help users understand the required structure for CRE secrets configuration.
🔎 Suggested additions
Option 1: Add an example secret name
secretsNames: + - mySecret + - anotherSecretOption 2: Add clarifying comments
+# List of secret names required by the CRE workflows +# Users should populate this with the names of secrets available in their CRE environment secretsNames:Option 3: Combine both for maximum clarity
+# List of secret names required by the CRE workflows +# Example entries shown below; replace with actual secrets for your environment secretsNames: + - PRIVATE_KEY + - API_ENDPOINTexamples/truf-cre-demo/project.yaml (1)
1-20: LGTM! Consider documenting public RPC limitations.The CRE project configuration is well-structured with helpful comments. The use of a public RPC endpoint for Sepolia testnet is appropriate for example code.
Optional enhancement: Consider adding a comment about public RPC limitations:
workflow-settings: rpcs: - chain-name: ethereum-testnet-sepolia + # Note: Public RPC endpoints may have rate limits. For production use, configure your own RPC provider. url: https://ethereum-sepolia-rpc.publicnode.comexamples/truf-cre-demo/README.md (1)
149-172: Add language specifier to fenced code blocks.The output examples should have a language specifier (e.g.,
textorconsole) for consistency and to satisfy the linter.🔎 Suggested fix
### Write Workflow -``` +```text === TRUF CRE Write Workflow: Deploy & Insert Demo ===Apply the same pattern to the Read Workflow output (line 159), Cleanup Workflow output (line 168), and Project Structure (line 219) blocks.
core/tnclient/transport_cre.go (2)
288-294: Consider removing or converting debug printf statements to structured logging.Multiple
fmt.Printf("[DEBUG]...")statements throughout the file will write to stdout unconditionally. For a library, consider:
- Removing debug statements before release
- Using a proper logger if debug output is needed (the transport doesn't currently have logger access)
🔎 Example locations with debug prints
- Line 288: Execute attempt logging
- Line 291, 294: Error and retry logging
- Line 311: executeOnce entry
- Line 377, 381, 388: Nonce management logging
497-511: Duplicated broadcast error handling.The broadcast error decoding logic (code -201) is duplicated between
doJSONRPC(lines 199-211) andexecuteOnce(lines 497-511). Consider extracting to a helper function for maintainability.🔎 Suggested helper
func formatJSONRPCError(rpcErr *jsonrpc.Error) error { if rpcErr.Code == -201 && len(rpcErr.Data) > 0 { var broadcastErr struct { Code uint32 `json:"code"` Hash string `json:"hash"` Message string `json:"message"` } if err := json.Unmarshal(rpcErr.Data, &broadcastErr); err == nil { return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]", rpcErr.Message, rpcErr.Code, broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message) } } return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcErr.Message, rpcErr.Code) }examples/truf-cre-demo/truf-read-workflow/main.go (2)
190-228:createSignerfunction is duplicated across all workflow examples.This function is identical in
truf-read-workflow,truf-write-workflow, andtruf-cleanup-workflow. Consider extracting to a shared package underexamples/truf-cre-demo/shared/to reduce duplication and ensure consistency.🔎 Suggested structure
examples/truf-cre-demo/ ├── shared/ │ └── signer.go # createSigner function ├── truf-read-workflow/ ├── truf-write-workflow/ └── truf-cleanup-workflow/
152-160: Consider usingsort.Slicefor cleaner sorting.The manual bubble sort works but
sort.Sliceis more idiomatic Go and clearer:🔎 Suggested refactor
+import "sort" // Sort records in descending order by eventTime (newest first) records := actionResult.Results -for i := 0; i < len(records)-1; i++ { - for j := i + 1; j < len(records); j++ { - if records[i].EventTime < records[j].EventTime { - records[i], records[j] = records[j], records[i] - } - } -} +sort.Slice(records, func(i, j int) bool { + return records[i].EventTime > records[j].EventTime +})examples/truf-cre-demo/run-full-demo.sh (1)
1-2: Consider addingset -euo pipefailfor robustness.While you have explicit
$?checks after each command, adding shell options at the start provides an additional safety net for any unhandled failures.🔎 Proposed fix
#!/bin/bash +set -euo pipefail # TRUF CRE Complete Workflow Demoexamples/truf-cre-demo/truf-write-workflow/main.go (1)
117-122: Inconsistent error handling pattern.This segment returns
(result, nil)after an error, while earlier error paths (lines 84, 92, 108) return(result, err). This inconsistency could mask errors in the workflow result since the caller won't see a non-nil error.Consider aligning the error handling—either always return the error, or document why partial results with
nilerror are preferred for certain failures.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
examples/truf-cre-demo/go.sumis excluded by!**/*.sum
📒 Files selected for processing (23)
.gitignoreREADME.mdcore/tnclient/transport_cre.godocs/CRE_INTEGRATION.mddocs/api-reference.mddocs/readme.mddocs/stream-lifecycle.mdexamples/README.mdexamples/truf-cre-demo/.gitignoreexamples/truf-cre-demo/README.mdexamples/truf-cre-demo/go.modexamples/truf-cre-demo/project.yamlexamples/truf-cre-demo/run-full-demo.shexamples/truf-cre-demo/secrets.yamlexamples/truf-cre-demo/truf-cleanup-workflow/config.jsonexamples/truf-cre-demo/truf-cleanup-workflow/main.goexamples/truf-cre-demo/truf-cleanup-workflow/workflow.yamlexamples/truf-cre-demo/truf-read-workflow/config.jsonexamples/truf-cre-demo/truf-read-workflow/main.goexamples/truf-cre-demo/truf-read-workflow/workflow.yamlexamples/truf-cre-demo/truf-write-workflow/config.jsonexamples/truf-cre-demo/truf-write-workflow/main.goexamples/truf-cre-demo/truf-write-workflow/workflow.yaml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-10T15:39:48.576Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 138
File: examples/cache_example.go:21-21
Timestamp: 2025-07-10T15:39:48.576Z
Learning: For example code in the trufnetwork/sdk-go repository, the maintainer MicBun prefers to keep examples simple and focused on demonstrating functionality rather than implementing production-ready security practices like environment variables for sensitive values.
Applied to files:
README.mdexamples/truf-cre-demo/go.modexamples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T07:10:07.366Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 166
File: core/tnclient/transport_cre.go:657-678
Timestamp: 2025-12-24T07:10:07.366Z
Learning: In the trufnetwork/sdk-go repository, the gateway authentication in `core/tnclient/transport_cre.go` uses a custom SIWE-like format (not standard SIWE). The custom format intentionally omits the account address line and uses "Issue At" instead of "Issued At" to match the kwil-db gateway's expectations.
Applied to files:
examples/truf-cre-demo/go.moddocs/api-reference.mdcore/tnclient/transport_cre.go
🧬 Code graph analysis (3)
examples/truf-cre-demo/truf-read-workflow/main.go (5)
examples/truf-cre-demo/truf-write-workflow/main.go (1)
RecordData(33-38)core/logging/logging.go (1)
Logger(7-7)core/tnclient/client.go (1)
NewClient(31-59)core/tnclient/options_cre.go (1)
WithCRETransportAndSigner(101-109)core/types/stream.go (1)
GetRecordInput(12-21)
examples/truf-cre-demo/truf-write-workflow/main.go (8)
core/logging/logging.go (1)
Logger(7-7)core/util/stream_id.go (2)
NewStreamId(33-43)StreamId(29-31)core/tnclient/client.go (1)
NewClient(31-59)core/tnclient/options_cre.go (1)
WithCRETransportAndSigner(101-109)core/contractsapi/primitive_stream.go (1)
LoadPrimitiveActions(28-34)core/contractsapi/deploy_stream.go (1)
DeployStream(19-24)core/types/contract_values.go (1)
StreamTypePrimitive(12-12)core/types/primitive_stream.go (1)
InsertRecordInput(10-15)
examples/truf-cre-demo/truf-cleanup-workflow/main.go (4)
core/util/stream_id.go (1)
NewStreamId(33-43)core/tnclient/client.go (1)
NewClient(31-59)core/tnclient/options_cre.go (1)
WithCRETransportAndSigner(101-109)core/contractsapi/destroy_stream.go (1)
DestroyStream(17-23)
🪛 markdownlint-cli2 (0.18.1)
examples/truf-cre-demo/README.md
150-150: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
159-159: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
168-168: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
219-219: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (29)
examples/truf-cre-demo/go.mod (4)
3-3: Verify Go 1.25.3 compatibility with team infrastructure.Go 1.25.3 was released 2025-10-13 and is a very recent version. Ensure all developers and CI/CD infrastructure have access to this version, as older toolchains may not recognize it.
Consider documenting the minimum Go version requirement in the project's README or contributing guide, especially for contributors who may still be using Go 1.24 or earlier.
8-8: Confirm beta dependency is intentional for example code.The cron scheduler dependency uses
v1.0.0-beta.0, which indicates active development. While appropriate for example/demo code, verify this aligns with the project's intent for this package. If stability is desired, consider whether a stable release is available.
1-44: Module structure and replace directive are well-configured.The use of a local replace directive to point to the parent SDK is appropriate for the monorepo structure, and the module name clearly indicates this is a demo. The indirect dependencies are reasonable for CRE integration and SDK usage.
9-10: Dependencies resolve cleanly with no conflicts; no action required.The
go mod graphconfirms thatsdk-go v0.5.2(December 2025) explicitly depends on and was tested withkwil-db/core v0.4.3(July 2025). The date gap reflects intentional version pinning to known-working versions, not outdated or untested transitive dependencies. Module resolution completed without errors.Likely an incorrect or invalid review comment.
examples/truf-cre-demo/.gitignore (1)
1-1: LGTM!Excluding environment files from version control is a security best practice.
.gitignore (1)
33-35: LGTM!Excluding WASM build artifacts from version control is appropriate. The section comment clearly documents the purpose.
examples/README.md (1)
54-66: LGTM! Clear and well-structured documentation.The new CRE integration section effectively documents the new feature, explains the architectural decisions (separate workflows for request limits), and provides appropriate links to detailed documentation.
docs/stream-lifecycle.md (1)
33-38: No changes needed — the field pathtxRes.Result.Codeis correct.The code already accesses the correct field from the transaction response. Throughout the codebase (tests, examples, and integration code), all usages consistently access
txRes.Result.CodeandtxRes.Result.Log. NoTxResultfield exists in the SDK's transaction response structure. The field path in this documentation matches the actual SDK implementation fromgithub.com/trufnetwork/kwil-db/core/types.Likely an incorrect or invalid review comment.
examples/truf-cre-demo/truf-read-workflow/workflow.yaml (1)
1-23: Configuration looks correct for a CRE workflow example.The workflow settings follow the expected CRE conventions. The empty
secrets-pathis appropriate for a demo that uses config-based credentials.examples/truf-cre-demo/truf-write-workflow/workflow.yaml (1)
1-23: LGTM!Workflow configuration is consistent with the read workflow pattern.
examples/truf-cre-demo/README.md (1)
94-102: Security notice is appropriate for example code.The warning about the test private key is good. Based on learnings, example code in this repository prioritizes simplicity over production-ready security practices, so this approach is acceptable for demonstration purposes.
docs/api-reference.md (1)
158-338: Comprehensive CRE API documentation.The documentation thoroughly covers:
- Transport options and their parameters
- Build requirements (
wasip1tag)- Usage examples for read-only and write operations
- Limitations and resources
This provides clear guidance for developers integrating CRE workflows.
docs/CRE_INTEGRATION.md (2)
167-168: Important option ordering constraint is well documented.Good callout about
WithSignerneeding to come beforeWithCRETransportwhen using separate options. This prevents a common integration mistake.
46-51: Incorrect Go version specified.Same issue as in README.md - Go 1.25.3 does not exist. Update to a valid Go version.
🔎 Suggested fix
1. **Go 1.25.3 or later** +1. **Go 1.22 or later** ```bash go version # Should show 1.25.3+ +go version # Should show 1.22+</details> > Likely an incorrect or invalid review comment. </blockquote></details> <details> <summary>core/tnclient/transport_cre.go (4)</summary><blockquote> `285-306`: **Retry logic for nonce errors is well-implemented.** The retry mechanism correctly: - Limits retries to 3 attempts - Resets `nonceFetched` on nonce errors to refetch from the gateway - Only retries on nonce-specific errors This handles the common case where nonces become stale due to concurrent transactions. --- `346-392`: **Nonce management logic is correct but has a subtle edge case.** The nonce is incremented before the transaction is broadcast (lines 387-389). If the broadcast fails for non-nonce reasons, the local nonce counter advances but the on-chain nonce doesn't. Subsequent transactions will use incorrect nonces until a nonce error triggers a refetch. For CRE workflows with the 5 HTTP request limit, this is unlikely to be a practical issue. The retry mechanism (lines 285-306) will recover by refetching the nonce on failure. --- `443-457`: **WASM pointer corruption workaround is well-documented.** The comment clearly explains the Go WASM issue (golang/go#59156, golang/go#66984) and why manual JSON construction is necessary. This is a valid workaround for the known pointer size mismatch between 64-bit Go and 32-bit WASM runtime. --- `418-424`: **Critical fix for fee serialization is well-documented.** The comment clearly explains why `Fee` must be `big.NewInt(0)` rather than `nil`. This prevents the serialization mismatch that causes signature verification failures. </blockquote></details> <details> <summary>examples/truf-cre-demo/truf-read-workflow/main.go (2)</summary><blockquote> `108-113`: **Inconsistent error handling pattern.** On line 112, when `getRecordsCount` fails, the code sets `result.Error` but returns `nil` for the error. Earlier error cases (lines 79-81, 93-95) return both the error and set `result.Error`. Consider being consistent - either always return the error or always return nil with error in result. Current pattern allows workflow to "succeed" with an error message, which may be intentional for CRE consensus but should be documented. --- `1-59`: **Workflow setup is well-structured.** The workflow initialization follows CRE patterns correctly: - Build tag `wasip1` is present - `InitWorkflow` returns proper CRE workflow - Cron trigger is configured from config - Handler is properly registered </blockquote></details> <details> <summary>examples/truf-cre-demo/truf-cleanup-workflow/main.go (2)</summary><blockquote> `106-111`: **Consistent error handling with other workflows.** The pattern of returning `nil` error while setting `result.Error` is consistent with the read workflow. This allows the CRE workflow to complete with an error message in the result rather than failing entirely. --- `40-49`: **Workflow entry point is properly structured.** `InitWorkflow` correctly initializes the CRE workflow with cron trigger and handler registration. </blockquote></details> <details> <summary>examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml (1)</summary><blockquote> `17-23`: **LGTM!** The workflow settings are properly structured with clear documentation. The configuration correctly references the local directory for the workflow path and config.json for configuration. </blockquote></details> <details> <summary>examples/truf-cre-demo/truf-write-workflow/main.go (4)</summary><blockquote> `26-51`: **LGTM!** The struct definitions are well-organized with proper JSON and consensus aggregation tags for CRE workflow execution. --- `53-62`: **LGTM!** The `InitWorkflow` function correctly wires the cron trigger to the handler. The unused `secretsProvider` parameter is required by the CRE interface signature. --- `192-230`: **LGTM!** The `createSigner` function properly validates the private key format, derives the Ethereum address using go-ethereum, and creates the signer using kwil-db crypto. The dual-library approach is necessary for compatibility. --- `232-234`: **LGTM!** Standard CRE WASM entry point correctly wiring the JSON parser and workflow initialization. </blockquote></details> <details> <summary>docs/readme.md (1)</summary><blockquote> `6-6`: **LGTM!** Good addition to the navigation with a clear description of the CRE integration guide. </blockquote></details> <details> <summary>README.md (1)</summary><blockquote> `63-74`: **LGTM!** The new CRE section is well-structured, provides clear context, and links appropriately to both external Chainlink documentation and internal guides. The feature list accurately summarizes CRE capabilities, and both the integration guide and demo example are present and functional. </blockquote></details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
examples/truf-cre-demo/README.md (1)
232-232: Incorrect Go version specified.Go 1.25.3 does not exist. Current stable Go versions are in the 1.22.x and 1.23.x range. This should be corrected to reflect the actual minimum Go version requirement.
🔎 Suggested fix
### Prerequisites -- Go 1.25.3 or later +- Go 1.22 or later - CRE CLI installed - Access to TRUF.NETWORK gateway
🧹 Nitpick comments (2)
examples/truf-cre-demo/README.md (2)
165-191: Consider adding language identifiers to code blocks.The expected output examples are clear and helpful. As a minor markdown style improvement, consider adding language identifiers to the fenced code blocks (e.g.,
```textor```console) for better syntax highlighting and linting compliance.🔎 Example of adding language identifiers
### Write Workflow -``` +```text === TRUF CRE Write Workflow: Deploy & Insert Demo ===Apply similar changes to code blocks at lines 177 and 186.
237-252: Consider adding language identifier for better rendering.The project structure diagram would benefit from a language identifier for proper markdown rendering. Consider using
```textor```tree.🔎 Suggested improvement
### Project Structure -``` +```text truf-cre-demo/
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
examples/truf-cre-demo/README.mdexamples/truf-cre-demo/config.jsonexamples/truf-cre-demo/truf-cleanup-workflow/workflow.yamlexamples/truf-cre-demo/truf-read-workflow/workflow.yamlexamples/truf-cre-demo/truf-write-workflow/workflow.yaml
✅ Files skipped from review due to trivial changes (1)
- examples/truf-cre-demo/config.json
🚧 Files skipped from review as they are similar to previous changes (2)
- examples/truf-cre-demo/truf-write-workflow/workflow.yaml
- examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's CRE examples, each workflow requires its own config.json file following the CRE CLI (`cre init`) format requirements, which necessitates config file duplication across workflows.
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's CRE examples, each workflow requires its own config.json file following the CRE CLI (`cre init`) format requirements, which necessitates config file duplication across workflows.
Applied to files:
examples/truf-cre-demo/truf-read-workflow/workflow.yamlexamples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).
Applied to files:
examples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's examples/truf-cre-demo directory, the private key "0000000000000000000000000000000000000000000000000000000000000001" is a dummy/placeholder key used for demonstration purposes in the CRE workflow examples.
Applied to files:
examples/truf-cre-demo/README.md
📚 Learning: 2025-07-10T15:39:48.576Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 138
File: examples/cache_example.go:21-21
Timestamp: 2025-07-10T15:39:48.576Z
Learning: For example code in the trufnetwork/sdk-go repository, the maintainer MicBun prefers to keep examples simple and focused on demonstrating functionality rather than implementing production-ready security practices like environment variables for sensitive values.
Applied to files:
examples/truf-cre-demo/README.md
🪛 markdownlint-cli2 (0.18.1)
examples/truf-cre-demo/README.md
168-168: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
177-177: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
186-186: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
237-237: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (10)
examples/truf-cre-demo/truf-read-workflow/workflow.yaml (1)
1-23: LGTM! Configuration is well-structured.The workflow settings file is correctly configured with:
- Clear documentation comments explaining the structure
- Proper workflow-name identifier for the read workflow
- Correct path references for shared config (as noted in learnings, all 3 workflows share the same config.json)
- Valid empty secrets-path
Based on learnings, the shared config approach via
../config.jsonis intentional and correct for this CRE demo.examples/truf-cre-demo/README.md (9)
1-14: LGTM! Clear overview of the demo structure.The documentation effectively explains the 3-workflow split strategy to work within CRE's 5 HTTP request limit per workflow. Based on learnings, this architectural decision is well-justified.
15-32: LGTM! Setup instructions are clear and secure.The configuration instructions properly guide users to:
- Replace the placeholder private key with their own
- Ensure proper permissions on the TRUF node
- Understand that all workflows share the same config.json
The security note about replacing the placeholder is appropriate for documentation.
33-56: LGTM! Clear and actionable quick start instructions.The commands are properly formatted for CRE CLI usage, with clear instructions for both complete demo execution and individual workflow testing.
57-107: LGTM! Comprehensive workflow documentation.The workflow descriptions effectively detail:
- HTTP request breakdown for each workflow
- Operations performed and their purposes
- Expected results
The request counts (5/5, 4/5, 5/5) demonstrate awareness of CRE's 5-request limit, consistent with learnings.
108-121: LGTM! Configuration example with appropriate security warning.The configuration section clearly shows the required fields and includes an important security warning. Based on learnings, the dummy private key shown is acceptable for demonstration purposes, and the warning at line 120 appropriately advises users about production security practices.
122-164: LGTM! Well-explained architecture and SDK features.The architecture section effectively explains:
- Why the 3-workflow split is necessary (5 HTTP request limit per workflow)
- Key SDK integration patterns with clear code examples
- Complete CRUD lifecycle demonstration
Based on learnings, the architectural rationale is correct and well-justified.
192-228: LGTM! Valuable implementation details and gotchas.This section provides critical insights:
- Graceful handling of duplicate streams
- Important fee initialization fix (nil vs big.NewInt(0) causing signature verification issues)
- Clear explanation of automatic nonce management
These details are essential for developers working with the SDK.
253-270: LGTM! Clear instructions with appropriate warning.The section provides practical guidance for extending the example while correctly warning about the 5 HTTP request limit constraint. The suggestion to create an additional workflow for bulk inserts demonstrates understanding of CRE's limitations.
271-301: LGTM! Comprehensive troubleshooting and guidance.The documentation concludes with:
- Practical troubleshooting for common CRE integration issues
- Relevant resource links
- Clear contributing guidelines emphasizing the 5 HTTP request limit
- Important security reminder for production deployments
This provides excellent support for developers using the example.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
core/tnclient/transport_cre.go (1)
435-514: Consider extracting duplicated broadcast error handling.Lines 489-504 duplicate the broadcast error handling logic from lines 199-211. This code appears in both
doJSONRPCandexecuteOnce.While the WASM pointer workaround necessitates manual JSON-RPC construction here (well-documented in lines 436-439), the error-handling logic could be extracted into a helper function to reduce duplication.
Additionally, the manual JSON string construction at lines 447-449 assumes the transaction JSON is valid and properly formatted. While this is likely safe given the prior
json.Marshalcall, be aware that this approach bypasses normal JSON encoding safeguards.🔎 Suggested refactoring to extract broadcast error handling
Add a helper function to handle broadcast errors:
// decodeBroadcastError decodes detailed broadcast error information from JSON-RPC error data func decodeBroadcastError(rpcErr *jsonrpc.Error) error { if rpcErr.Code == -201 && len(rpcErr.Data) > 0 { var broadcastErr struct { Code uint32 `json:"code"` Hash string `json:"hash"` Message string `json:"message"` } if err := json.Unmarshal(rpcErr.Data, &broadcastErr); err == nil { return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]", rpcErr.Message, rpcErr.Code, broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message) } } return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcErr.Message, rpcErr.Code) }Then use it at lines 199-211 and 489-504:
if rpcResp.Error != nil { - // For broadcast errors (-201), decode the BroadcastError details - if rpcResp.Error.Code == -201 && len(rpcResp.Error.Data) > 0 { - var broadcastErr struct { - Code uint32 `json:"code"` - Hash string `json:"hash"` - Message string `json:"message"` - } - if err := json.Unmarshal(rpcResp.Error.Data, &broadcastErr); err == nil { - return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]", - rpcResp.Error.Message, rpcResp.Error.Code, - broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message) - } - } - return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcResp.Error.Message, rpcResp.Error.Code) + return decodeBroadcastError(rpcResp.Error) }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
core/tnclient/transport_cre.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).
📚 Learning: 2025-12-24T07:10:07.366Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 166
File: core/tnclient/transport_cre.go:657-678
Timestamp: 2025-12-24T07:10:07.366Z
Learning: In the trufnetwork/sdk-go repository, the gateway authentication in `core/tnclient/transport_cre.go` uses a custom SIWE-like format (not standard SIWE). The custom format intentionally omits the account address line and uses "Issue At" instead of "Issued At" to match the kwil-db gateway's expectations.
Applied to files:
core/tnclient/transport_cre.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: test
🔇 Additional comments (5)
core/tnclient/transport_cre.go (5)
10-10: LGTM: Nonce tracking infrastructure.The new fields and import support the nonce auto-management feature. The mutex ensures thread-safe nonce increments.
Also applies to: 67-69
124-124: LGTM: Enhanced error diagnostics.The improved error messages will aid debugging, especially the detailed broadcast error decoding at lines 199-211.
Also applies to: 199-212
410-416: LGTM: Fee nil handling prevents signature mismatch.The comment clearly explains the serialization issue and the fix is appropriate.
427-427: LGTM: Explicit serialization type for EthPersonalSigner.Setting the serialization type explicitly ensures compatibility with EthPersonalSigner.
733-733: LGTM: Enhanced authentication error messages.Adding "kgw.authn" context to error messages improves debugging clarity.
Also applies to: 755-755
| // Retry loop for nonce errors | ||
| const maxRetries = 3 | ||
| for attempt := 0; attempt < maxRetries; attempt++ { | ||
| txHash, err := t.executeOnce(ctx, namespace, action, inputs, opts...) | ||
| if err != nil { | ||
| // Check if it's a nonce error | ||
| if strings.Contains(err.Error(), "invalid nonce") && attempt < maxRetries-1 { | ||
| // Reset nonce tracking to refetch on next attempt | ||
| t.nonceMu.Lock() | ||
| t.nonceFetched = false | ||
| t.nonceMu.Unlock() | ||
| continue // Retry | ||
| } | ||
| return types.Hash{}, err | ||
| } | ||
| return txHash, nil | ||
| } | ||
|
|
||
| return types.Hash{}, fmt.Errorf("max retries exceeded") |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's verify the file exists and check the code at the specified lines
cat -n core/tnclient/transport_cre.go | sed -n '280,305p'Repository: trufnetwork/sdk-go
Length of output: 1076
🏁 Script executed:
# Also check the isTransientTxError function mentioned at lines 586-591
cat -n core/tnclient/transport_cre.go | sed -n '580,600p'Repository: trufnetwork/sdk-go
Length of output: 857
🏁 Script executed:
# Search for nonce error handling patterns and structured error codes in the codebase
rg -n -C3 --type go 'nonce|transient.*error|error.*code' core/tnclient/ | head -100Repository: trufnetwork/sdk-go
Length of output: 6712
🏁 Script executed:
# Look for error type definitions or error handling patterns related to gateway API
fd --type go -x grep -l 'error\|Error' core/tnclient/ | head -20Repository: trufnetwork/sdk-go
Length of output: 231
🏁 Script executed:
# Find jsonrpc error code definitions
rg -n --type go 'ErrorCode|ErrorTx|ErrorTimeout|ErrorNonce|error.*nonce' --max-count 50 core/tnclient/Repository: trufnetwork/sdk-go
Length of output: 872
🏁 Script executed:
# Search for gateway API documentation or error type definitions
find . -name '*.go' -type f | xargs grep -l 'jsonrpc\|ErrorCode' | head -10Repository: trufnetwork/sdk-go
Length of output: 94
🏁 Script executed:
# Look for comments or error message patterns related to nonce
rg -n 'invalid nonce|nonce.*error|error.*nonce' --type goRepository: trufnetwork/sdk-go
Length of output: 411
Fragile error detection for nonce errors.
The retry logic uses substring matching strings.Contains(err.Error(), "invalid nonce") to detect nonce errors. This is fragile—if the gateway changes the error message format, retries will fail silently. Consider checking if the gateway API provides a structured error code for nonce errors (similar to the -202 and -32001 codes handled in isTransientTxError at lines 586–591). If available, use it instead of string matching.
🤖 Prompt for AI Agents
In core/tnclient/transport_cre.go around lines 285 to 303, the retry loop
currently detects nonce errors by substring-matching the error message ("invalid
nonce"); replace this fragile check with structured error-code detection:
inspect the returned error for the gateway/json-rpc error type (or unwrap to the
underlying error) and compare its numeric error code against the known
nonce-related codes used elsewhere (reuse the same checks as isTransientTxError
or add a helper like isNonceError that checks for the specific codes), and only
when that code is present perform the nonceMu reset and retry; otherwise return
the error. Ensure you handle nil unwraps and preserve existing behavior of
limiting retries to maxRetries.
| // Auto-manage nonce if not explicitly provided | ||
| if txOpts.Nonce == 0 { | ||
| t.nonceMu.Lock() | ||
|
|
||
| // Fetch nonce from gateway on first transaction only | ||
| if !t.nonceFetched { | ||
| // Create AccountID from signer | ||
| acctID := &types.AccountID{ | ||
| Identifier: t.signer.CompactID(), | ||
| KeyType: t.signer.PubKey().Type(), | ||
| } | ||
|
|
||
| // Fetch account info via user.account RPC call | ||
| params := map[string]any{ | ||
| "id": acctID, | ||
| } | ||
|
|
||
| var accountResp struct { | ||
| ID *types.AccountID `json:"id"` | ||
| Balance string `json:"balance"` | ||
| Nonce int64 `json:"nonce"` | ||
| } | ||
|
|
||
| err := t.callJSONRPC(ctx, "user.account", params, &accountResp) | ||
| if err != nil { | ||
| // If account doesn't exist yet, start with nonce 0 | ||
| if !strings.Contains(err.Error(), "not found") && !strings.Contains(err.Error(), "does not exist") { | ||
| t.nonceMu.Unlock() | ||
| return types.Hash{}, fmt.Errorf("failed to fetch account nonce: %w", err) | ||
| } | ||
| t.currentNonce = 0 | ||
| } else { | ||
| // Account nonce is the LAST used nonce, so NEXT nonce is nonce+1 | ||
| t.currentNonce = accountResp.Nonce + 1 | ||
| } | ||
| t.nonceFetched = true | ||
| } | ||
|
|
||
| // Use current nonce and increment | ||
| txOpts.Nonce = t.currentNonce | ||
| t.currentNonce++ | ||
|
|
||
| t.nonceMu.Unlock() | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for other error handling patterns with callJSONRPC
echo "=== Error handling patterns with callJSONRPC ==="
rg -n -B2 -A5 'callJSONRPC|err\.Error' core/tnclient/transport_cre.go | head -100
# Look for error type definitions
echo -e "\n=== Error type definitions ==="
rg -n 'type.*Error|error.*struct|ErrAccountNotFound|ErrNotFound' --type go core/tnclient/ | head -50
# Check for similar error string matching patterns
echo -e "\n=== String matching for errors in RPC context ==="
rg -n 'strings\.Contains.*Error|err.*not found|err.*does not exist' --type go core/tnclient/ | head -50
# Look at gateway client implementation
echo -e "\n=== Gateway interaction code ==="
find core/tnclient -name '*.go' -type f | xargs wc -l | sort -n | tail -20Repository: trufnetwork/sdk-go
Length of output: 6893
🏁 Script executed:
#!/bin/bash
# Get more context around the error handling in transport_cre.go
echo "=== Full context of user.account error handling ==="
sed -n '365,375p' core/tnclient/transport_cre.go
# Search for how errors are returned from gateway RPC
echo -e "\n=== Other RPC calls and their error handling ==="
rg -n -B3 -A8 'callJSONRPC\(ctx' core/tnclient/transport_cre.go | head -150
# Check if there's a gateway error response structure
echo -e "\n=== Response structures in transport ==="
ast-grep --pattern 'type $_ struct {
$$$
Error $_ `$_`
$$$
}'Repository: trufnetwork/sdk-go
Length of output: 6184
🏁 Script executed:
#!/bin/bash
# Search for account error handling in related test files or docs
echo "=== Test files for user.account handling ==="
find . -name '*test*.go' -type f | xargs grep -l 'user\.account' 2>/dev/null || echo "No test files found"
# Look for any gateway documentation or error constants
echo -e "\n=== Error constants or patterns ==="
rg -n 'account.*not.*found|does.*not.*exist' --type go --type md | head -30
# Check the overall structure of the transport client
echo -e "\n=== Transport client structure ==="
head -100 core/tnclient/transport_cre.goRepository: trufnetwork/sdk-go
Length of output: 3750
🏁 Script executed:
#!/bin/bash
# Search for error code constants or definitions
echo "=== Looking for error code definitions ==="
rg -n 'code.*int|ErrorCode|error.*code' --type go core/tnclient/ | head -40
# Check if there's a types file defining error codes
echo -e "\n=== Checking types package ==="
find . -name 'types.go' -o -name 'error*.go' | head -10
# Look for account error handling in gateway package or types
echo -e "\n=== Account-related types ==="
rg -n 'type.*Account|account.*error' --type go | head -30
# Search for JSON-RPC error code patterns in gateway responses
echo -e "\n=== JSON-RPC error response structures ==="
rg -n 'type.*Error|Error.*struct' --type go core/tnclient/transport_cre.go -A 5 | head -50Repository: trufnetwork/sdk-go
Length of output: 4508
🏁 Script executed:
#!/bin/bash
# Check the doJSONRPC function to see full error structure
echo "=== doJSONRPC error handling ==="
sed -n '460,520p' core/tnclient/transport_cre.go
# Look for JSON-RPC response structure definition
echo -e "\n=== JSON-RPC response structure ==="
ast-grep --pattern 'type $_ struct {
Error struct {
$$$
}
$$$
}'Repository: trufnetwork/sdk-go
Length of output: 2097
Use error codes instead of string matching for account lookup failures.
Line 367 uses fragile string matching ("not found", "does not exist") to detect non-existent accounts. JSON-RPC error responses include structured error codes, which are reliably extracted elsewhere in the codebase (line 583). The codebase comment at line 565 explicitly acknowledges this: "Consider adding structured error codes to the gateway API for better reliability."
The mutex locking correctly prevents race conditions during nonce fetching and incrementing.
resolves: https://github.com/truflation/website/issues/3055
Summary by CodeRabbit
New Features
Documentation
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.