Skip to content

Add STATE_VERSION to all settlement PDA seeds - #89

Merged
kaze-cow merged 17 commits into
mainfrom
kaze/sc-287-add-state-version-as-a-seed-to-all-storage
Aug 11, 2026
Merged

Add STATE_VERSION to all settlement PDA seeds#89
kaze-cow merged 17 commits into
mainfrom
kaze/sc-287-add-state-version-as-a-seed-to-all-storage

Conversation

@kaze-cow

@kaze-cow kaze-cow commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

Updates the settlement root PDA seed to correspond to the Major and minor cargo package versions. This causes all PDAs to be relocated on every minor or major package version bump.

Contents

Generally speaking the root state PDA is now:

macro_rules! state_version {
    () => { concat!(env!("CARGO_PKG_VERSION_MAJOR"), ".", env!("CARGO_PKG_VERSION_MINOR")) };
}

pub const SETTLEMENT_SEED: &[u8] = concat!("settlement v", state_version!()).as_bytes();

The whole seed is printable ASCII, so it shows up readably in explorers, logs and solana account.

No CU cost. Everything resolves in rustcstrings on the built .so shows settlement .. v0.1 baked into rodata — so nothing happens on-chain.

Other considerations

  • User delegations stop working. Users delegate their token accounts to the state PDA, and a bump moves that address, so every user has to delegate again.
  • Whatever the buffers still hold is stranded. A buffer's funds are only spendable by the state PDA that is its SPL authority. After a bump the program can no longer sign for the old state PDA, so those funds can never be moved again. Buffers must be drained under the old program version first.

How to test

Check new strategy

🤖 Generated with Claude Code

Every account the settlement program stores lived at a PDA whose first
seed was the bare string `settlement`. A program upgrade that changed the
layout or meaning of stored state would therefore land on exactly the
same addresses as the previous version, so old order and state accounts
would be silently reinterpreted under the new layout.

Fold a `STATE_VERSION` constant into the prefix seed that all three PDA
families share, so bumping it relocates the program's whole address space
at once and accounts written by an older version become unreachable
rather than misread.

The version is formatted as decimal ASCII and concatenated onto the
prefix, giving `settlement1`, so the seed stays legible wherever seeds
surface. It remains a single seed rather than an extra seed slot, which
leaves the seed arity of all three schemes untouched and the compute cost
of every derivation unchanged.

The seed is built in a `const` item rather than a `const fn` because the
workspace denies `clippy::arithmetic_side_effects` and that lint skips
`const` item bodies but not `const fn` bodies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@kaze-cow
kaze-cow requested a review from a team as a code owner August 4, 2026 08:16
@linear-code

linear-code Bot commented Aug 4, 2026

Copy link
Copy Markdown

SC-287

@fedgiac fedgiac 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.

Something missing from the description that I think deserves a mention: this affects all PDAs, not just the state PDA. This is intended behavior, but a distracted reviewer would miss that.

Also, there are some references to fixed lengths, but I don't see it in the code:

At 15 bytes it has ample headroom under the 32-byte MAX_SEED_LEN

15? Maybe under the assumption that the minor/major are 1 byte each?

The four extra seed bytes are free too: sol_create_program_address and sol_try_find_program_address

4? With the same assumption from before, maybe 5 including the extra space?

But anyway, the assumption is wrong, this isn't a fixed bytes and this in principle is a security concern (see comment).

Also, we should clearly write in the readme that we must increase the minor version on each new deployment, this would be very easy to miss.
The fix for that is that the deployment script tries to see if the state PDA exists and, if it already exists, it aborts the deployment suggesting to bump the version.

Comment thread interface/src/pda/mod.rs
@kaze-cow

kaze-cow commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Also, we should clearly write in the readme that we must increase the minor version on each new deployment, this would be very easy to miss.

Do we want to enforce that its bumped on every version? or its OK to do a deployment without bumping (or only bumping patch) if the storage format hasn't changed?

The fix for that is that the deployment script tries to see if the state PDA exists and, if it already exists, it aborts the deployment suggesting to bump the version.

We don't currently do anything in the deployment script to call Initialize actually, as there was no initialization when the deploy script was first created. It seems we might want to add something to the test-cli before we do the next big release.

will probably need to do something more sophisticated later
… of github.com:cowprotocol/solana-programs into kaze/sc-287-add-state-version-as-a-seed-to-all-storage
@kaze-cow
kaze-cow requested a review from fedgiac August 6, 2026 08:14

@fedgiac fedgiac 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.

Do we want to enforce that its bumped on every version? or its OK to do a deployment without bumping (or only bumping patch) if the storage format hasn't changed?

I'd say the default should be enforcing the version bump but that it can be somehow overwritten. I don't have a concrete idea for how though.

We don't currently do anything in the deployment script to call Initialize actually, as there was no initialization when the deploy script was first created. It seems we might want to add something to the test-cli before we do the next big release.

Yep!

[making it permanent]

Mmh, I'm reconsidering the size, maybe 5 bytes (two minor, two major or one major, three minor) are more than enough for now. Maybe even (1, 2).
But yeah, why not making it permanent? I'll review the DESIGN file with this in mind.

Comment thread interface/src/pda/state.rs Outdated
Comment thread interface/src/pda/mod.rs Outdated
Comment thread interface/src/pda/mod.rs Outdated
Comment thread interface/src/pda/order.rs
Comment thread interface/src/pda/mod.rs Outdated
Comment thread interface/src/pda/mod.rs Outdated
Comment thread interface/src/pda/mod.rs
kaze-cow and others added 4 commits August 10, 2026 16:39
Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com>
Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com>
Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com>
@kaze-cow

kaze-cow commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

I'd say the default should be enforcing the version bump but that it can be somehow overwritten. I don't have a concrete idea for how though.

Ok for now my thought is, when we get the Initialize call added to the deploy script, it will run a check to see if the PDA already exists or not. if it is not creatable, then you have to pass another flag to confirm what you are doing. But since the Initialize step doesn't exist yet, lets focus on getting what we have here merged. Sg?

@fedgiac fedgiac 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.

Nice!

@kaze-cow
kaze-cow merged commit 5b2d9d5 into main Aug 11, 2026
14 checks passed
@kaze-cow
kaze-cow deleted the kaze/sc-287-add-state-version-as-a-seed-to-all-storage branch August 11, 2026 07:24
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