Skip to content

fix(cre): wire ChainWrite.TargetsLimit to non-EVM WriteReport capabilities - #23257

Open
cawthorne wants to merge 1 commit into
developfrom
feature/add-non-evm-WriteReport-limits
Open

fix(cre): wire ChainWrite.TargetsLimit to non-EVM WriteReport capabilities#23257
cawthorne wants to merge 1 commit into
developfrom
feature/add-non-evm-WriteReport-limits

Conversation

@cawthorne

@cawthorne cawthorne commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

ChainWrite.TargetsLimit in CRE settings was silently unthrottled for non-EVM chains. The callLimiters map in capability_executor.go only wired ChainWriteTargets to {"evm", "WriteReport"} — Aptos, Solana, and Stellar WriteReport calls bypassed the limiter entirely.

The gap

The lookup at capability_executor.go:101:

limiter, ok := c.callLimiters[capCall{name: capName, method: request.Method}]
if ok { /* apply limit */ }
// if !ok → limiter silently skipped

For an Aptos write, ParseID("aptos:ChainSelector:4457093679053095497@1.0.0") returns name="aptos". The map only had {"evm", "WriteReport"} — so ok=false and the call proceeded unchecked.

family WriteReport exists? In callLimiters (before) In callLimiters (after)
evm
aptos
solana
stellar

The fix

Add new map entries — the limiter object (limiters.ChainWriteTargets) and settings schema (cresettings.chainWrite.TargetsLimit) already exist and are chain-family-agnostic:

		{"aptos", "View"}: limiters.ChainReadCalls,

		{"solana", "GetAccountInfoWithOpts"}:      limiters.ChainReadCalls,
		{"solana", "GetBalance"}:                  limiters.ChainReadCalls,
		{"solana", "GetBlock"}:                    limiters.ChainReadCalls,
		{"solana", "GetFeeForMessage"}:            limiters.ChainReadCalls,
		{"solana", "GetMultipleAccountsWithOpts"}: limiters.ChainReadCalls,
		{"solana", "GetSignatureStatuses"}:        limiters.ChainReadCalls,
		{"solana", "GetSlotHeight"}:               limiters.ChainReadCalls,
		{"solana", "GetTransaction"}:              limiters.ChainReadCalls,

		{"stellar", "GetLatestLedger"}: limiters.ChainReadCalls,
		{"stellar", "ReadContract"}:    limiters.ChainReadCalls,

		{"evm", "WriteReport"}:     limiters.ChainWriteTargets,
		{"aptos", "WriteReport"}:   limiters.ChainWriteTargets,
		{"solana", "WriteReport"}:  limiters.ChainWriteTargets,
		{"stellar", "WriteReport"}: limiters.ChainWriteTargets,

Production impact

Any production workflow writing to Aptos/Solana/Stellar has unlimited write targets today, regardless of ChainWrite.TargetsLimit in the org-level CRE settings. With this fix, TargetsLimit=0 correctly blocks all chain writes, not just EVM.

How discovered

While debugging fire-drill transmit_fault scenarios in chainlink-data-feeds. We investigated whether ChainWrite.TargetsLimit=0 could replace the bad-contract-address fault (hot-reloadable, no re-register), but found Aptos writes bypassed the limiter — leading to this fix.

Test plan

  • go test ./core/services/workflows/v2/... passes (verified locally)
  • Existing EVM write-limit tests still pass (no behavioral change for EVM)
  • Manual: set ChainWrite.TargetsLimit = 0 on an Aptos-targeted workflow, verify writes are now blocked (previously: writes succeeded)

@cawthorne
cawthorne requested a review from a team as a code owner July 28, 2026 15:04
@github-actions

Copy link
Copy Markdown
Contributor

👋 cawthorne, thanks for creating this pull request!

To help reviewers, please consider creating future PRs as drafts first. This allows you to self-review and make any final changes before notifying the team.

Once you're ready, you can mark it as "Ready for review" to request feedback. Thanks!

@github-actions

Copy link
Copy Markdown
Contributor

✅ No conflicts with other open PRs targeting develop

@github-actions

Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@trunk-io

trunk-io Bot commented Jul 28, 2026

Copy link
Copy Markdown

Static BadgeStatic BadgeStatic Badge

Failed Test Failure Summary Logs
TestTransfersController_TransferBalanceToLowError The test failed due to a low balance error during transfer. Logs ↗︎

View Full Report ↗︎Docs

@cawthorne
cawthorne force-pushed the feature/add-non-evm-WriteReport-limits branch from 050ba19 to 4d694a8 Compare July 28, 2026 15:34
@cawthorne

Copy link
Copy Markdown
Contributor Author

This breaks the Stellar ReadContract test:
stellar.ReadContract: PerWorkflow.ChainRead.CallLimit limited for workflow[00c2f1c36d518944c52c54e87b8bc51ecf8792fb905244ecbb7f98ec8dbc6b88]: cannot use 16, limit is 15\""
Either a latent default limit or a test would need to be adjusted.

c.c. @yashnevatia @ilija42

jmank88
jmank88 previously approved these changes Jul 28, 2026
@cawthorne

Copy link
Copy Markdown
Contributor Author

This breaks the Stellar ReadContract test: stellar.ReadContract: PerWorkflow.ChainRead.CallLimit limited for workflow[00c2f1c36d518944c52c54e87b8bc51ecf8792fb905244ecbb7f98ec8dbc6b88]: cannot use 16, limit is 15\"" Either a latent default limit or a test would need to be adjusted.

c.c. @yashnevatia @ilija42

Added a new TOML for this test which bumps the CallLimit. May not be the leanest approach, open to feedback @yashnevatia @ilija42

@ilija42 ilija42 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just set the limit in the existing toml config?

@cawthorne

Copy link
Copy Markdown
Contributor Author

Why not just set the limit in the existing toml config?

Happy to. I was just unsure if the existing one should be left alone. Will do that now.

@cawthorne

Copy link
Copy Markdown
Contributor Author

Why not just set the limit in the existing toml config?

Done.

The callLimiters map in capability_executor.go only wired EVM
capability methods to the ChainReadCalls and ChainWriteTargets limiters.
Aptos, Solana, and Stellar read/write calls were silently unthrottled —
the limiter lookup returned ok=false and the call proceeded unchecked,
regardless of the ChainRead.CallLimit or ChainWrite.TargetsLimit settings.

The settings schema (chainlink-common cresettings) already defines
these limits as chain-family-agnostic per-workflow limits. The wiring
just never connected them to non-EVM capability methods.

Read methods added:
  aptos:   View
  solana:  GetAccountInfoWithOpts, GetBalance, GetBlock, GetFeeForMessage,
           GetMultipleAccountsWithOpts, GetSignatureStatuses, GetSlotHeight,
           GetTransaction
  stellar: GetLatestLedger, ReadContract

Write methods added:
  aptos:   WriteReport
  solana:  WriteReport
  stellar: WriteReport

All map to the same limiter objects already used for EVM
(limiters.ChainReadCalls / limiters.ChainWriteTargets).

Discovered while debugging fire-drill transmit_fault scenarios in
chainlink-data-feeds: we investigated whether ChainWrite.TargetsLimit=0
could replace the bad-contract-address fault (hot-reloadable, no
re-register), but found Aptos writes bypassed the limiter entirely.
@cawthorne
cawthorne force-pushed the feature/add-non-evm-WriteReport-limits branch from eebf489 to 04e939a Compare July 30, 2026 10:48
@cl-sonarqube-production

Copy link
Copy Markdown

@cawthorne
cawthorne added this pull request to the merge queue Jul 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants