Skip to content

[2.x] Cross account links with an explicit data segment - #1231

Merged
lorisleiva merged 1 commit into
mainfrom
10-14-cross_account_links_with_an_explicit_data_segment
Oct 14, 2026
Merged

lorisleiva merged 1 commit into
mainfrom
10-14-cross_account_links_with_an_explicit_data_segment

Conversation

@lorisleiva

@lorisleiva lorisleiva commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

This PR makes paths cross account links with an explicit .data segment, following the matching spec change (codama-idl/spec#202). A linked public key now behaves like an account: .data enters its decoded data, and other segments are reserved for future attributes of the account, such as its lamports.

before                                 after
mint.decimals                          mint.data.decimals
${data.mint.decimals}                  ${data.mint.data.decimals}
${accounts.source.data.mint.symbol}    ${accounts.source.data.mint.data.symbol}
—                                      mint.data   (the whole data, even when it is not a struct)
  • visitors-core: resolveTypePath({ followAccountLinks }) crosses a linked public key on a .data segment, resolving to the account's data type. Each hop now consumes a segment, so the self-link guard is no longer needed.
  • dynamic-codecs: getDecodedNodeAtPath calls resolveAccountLink on a .data segment, and mint.data returns the account's decoded data.
  • dynamic-address-resolution: data paths fetch the linked account on a .data segment, including from data that is itself a linked address, e.g. pointer.data.data.mintAuthority.
  • visitors: renames follow account links on .data segments only.
  • validators: field discriminators report must not cross an account link for .data segments, and other segments applied to a linked public key as unresolvable paths.
  • The display follows through getDecodedNodeAtPath, and docs and tests use the new grammar.

@lorisleiva lorisleiva changed the title Cross account links with an explicit data segment [2.x] Cross account links with an explicit data segment Oct 14, 2026

lorisleiva commented Oct 14, 2026 •

Copy link
Copy Markdown
Member Author

@changeset-bot

changeset-bot Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 0c5bdd2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@lorisleiva

Copy link
Copy Markdown
Member Author

@trevor-cortex

Base automatically changed from 10-14-read_account_data_in_the_instruction_display to main October 14, 2026 14:06
@lorisleiva
lorisleiva force-pushed the 10-14-cross_account_links_with_an_explicit_data_segment branch from 34d4479 to a16f8dc Compare October 14, 2026 14:07

@trevor-cortex trevor-cortex left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

Moves account-link crossing in path expressions behind an explicit .data segment, matching spec#202. A linked public key now behaves like an account node: .data enters its decoded data (whole data, struct or not), and any other segment is reserved and throws. The five path walkers are updated in lockstep:

  • resolveTypePath (visitors-core): .data on a linked public key resolves to [...accountPath, account.data]; since every hop now consumes a segment, the followedAccounts self-link guard is gone and the self-link test flips from "throws" to "follows one hop per .data".
  • getDecodedNodeAtPath (dynamic-codecs): same shape; the crossing moved out of resolveContainer into the main loop, so mint.data returns the account's decoded data node.
  • getValueAtPath (dynamic-address-resolution): crossing now continues after consuming the .data segment and re-seeds typePath with the account data, which is what makes pointer.data.data.mintAuthority work.
  • createPathResolver (visitors): the public-key hop is pulled out of the defined-type while into its own block gated on .data; followedAccounts dropped for the same reason.
  • validators: the friendlier "must not cross an account link" message is now only emitted when the failing segment is data; mint.decimals falls through to the generic unresolvable-path message.

I traced the loop-termination argument in all four walkers and it holds: the only way to re-enter an account is via a .data segment, and paths are finite. The non-struct account data case (counter.data → u64) and the pointer-to-pointer case are both covered by tests.

Things to watch

  • Changeset. I don't see a .changeset/*.md in the file list, and this is a user-facing grammar change across @codama/visitors-core, @codama/visitors, @codama/validators, @codama/dynamic-codecs and @codama/dynamic-address-resolution. CONTRIBUTING asks for one per concern — is it coming in this PR, or is the stack carrying a single one elsewhere?
  • Spec pin. The PR references spec#202. If that change is doc-only in the spec, nothing to do; if it moved the @codama/spec version, does the pin in packages/spec-generators/package.json need to follow (even with no generated diff) so the pin stays aligned with the grammar this branch implements?
  • Reserved segments on the display side. getDataMemberPath in dynamic-instructions/src/display/fields.ts calls getDecodedNodeAtPath with resolveAccountLink: () => undefined and stops at the first undefined. With this PR, a reserved segment like mint.lamports now throws there instead of returning undefined (previously any field segment crossed the link). That's fine today since validators reject those paths, but when lamports & co. land that function will need to learn the reserved set. Just flagging so it isn't a surprise later.

Notes for other reviewers

  • The diff GitHub serves for dynamic-instructions/src/display/{accounts,dictionary,fields}.ts and test/display/account-data.test.ts includes the parent PR in the stack; only the .data-grammar lines (comments, test paths) belong to this PR.
  • DecodedAccountNode.data is required in decoded.ts, so the new current = account.data in path.ts is safe without the !current.data guard that resolveContainer applies to instructions/events/variants.
  • Small asymmetry worth knowing about, not a problem: accountDataValueNode('mint') (no path) yields the DecodedAccountNode, whereas mint.data yields its data type node. getValueNode in injected-values.ts unwraps both, so consumers see the same thing.

Comment thread packages/visitors-core/src/resolveTypePath.ts
@lorisleiva
lorisleiva force-pushed the 10-14-cross_account_links_with_an_explicit_data_segment branch from a16f8dc to 0c5bdd2 Compare October 14, 2026 14:11
@lorisleiva
lorisleiva merged commit 0e5dab0 into main Oct 14, 2026
3 of 5 checks passed
@lorisleiva
lorisleiva deleted the 10-14-cross_account_links_with_an_explicit_data_segment branch October 14, 2026 14:27
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.

2 participants