Skip to content

SIMD-0431: Loader V3: Permissioned Extend Program#431

Open
deanmlittle wants to merge 14 commits intosolana-foundation:mainfrom
blueshift-gg:permissioned-extend-program
Open

SIMD-0431: Loader V3: Permissioned Extend Program#431
deanmlittle wants to merge 14 commits intosolana-foundation:mainfrom
blueshift-gg:permissioned-extend-program

Conversation

@deanmlittle
Copy link
Contributor

No description provided.

@simd-bot
Copy link

simd-bot bot commented Dec 18, 2025

Hello deanmlittle! Welcome to the SIMD process. By opening this PR you are affirming that your SIMD has been thoroughly discussed and vetted in the SIMD discussion section. The SIMD PR section should only be used to submit a final technical specification for review. If your design / idea still needs discussion, please close this PR and create a new discussion here.

This PR requires the following approvals before it can be merged:

Once all requirements are met, you can merge this PR by commenting /merge.

@deanmlittle deanmlittle changed the title Permissioned program extend SIMD-0431: Permissioned Extend Program Dec 18, 2025
@buffalojoec
Copy link
Contributor

Lgtm

@deanmlittle
Copy link
Contributor Author

@0xRigel requesting your review as this pertains to multisig wallets like Squads. I know we discussed at breakpoint but worth double checking you don't foresee any issues. I think it is actually as simple as throwing a lighthouse instruction at the end to ensure the authority doesn't change.

@0xRigel
Copy link
Contributor

0xRigel commented Dec 21, 2025

Whats the current reason for ExtendProgram not supporting inner instructions? If we could get rid of that while simultaneously adding this permissioned check, that would be fab.

Aside from that, this looks good. We'll just have to make a few adjusments to the UI's under the hood logic for extend program.

@deanmlittle
Copy link
Contributor Author

Whats the current reason for ExtendProgram not supporting inner instructions? If we could get rid of that while simultaneously adding this permissioned check, that would be fab.

Aside from that, this looks good. We'll just have to make a few adjusments to the UI's under the hood logic for extend program.

ACK, thanks for reviewing! There are a many dumb restrictions on LoaderV3 due to security issues that can arise as a result of problematic account midstates created during the upgrade process. Hopefully we can ship a few more fixes that would allow us to relax these constraints in the future!

@deanmlittle deanmlittle changed the title SIMD-0431: Permissioned Extend Program SIMD-0431: Loader V3: Permissioned Extend Program Jan 2, 2026
Copy link
Contributor

@buffalojoec buffalojoec left a comment

Choose a reason for hiding this comment

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

I think this proposal could actually use a bit of fleshing out for context.

I've written a draft implementation here: anza-xyz/agave#9859


The first major issue I found is that we'd actually need to break the
ExtendProgram instruction's accounts list beyond just requiring a signature.
The authority is actually not a member of the required accounts for
ExtendProgram. We would need to add it.

https://github.com/anza-xyz/solana-sdk/blob/7b95685a9c3ddc4312d8522618cf4c1595accb0c/loader-v3-interface/src/instruction.rs#L150-L156

For this reason, I'm actually considering SIMD-0164 as a preferred solution. We
would introduce a new instruction with a new accounts list and deprecate the
old one.

Since callers will have to modify their code anyway in order to support the
ExtendProgram instruction after this feature, are we certain changing the
existing instruction is cleaner? It seems like maybe not.


Additionally, this proposal can probably add more details about some of the
deliberation that occurred in SIMD-0164. After all, it's going to be the exact
same design, just a different rollout strategy.

There was a bit of discussion about how this change affects multisigs. However,
in SIMD-0164 and also here in this proposal (via ack by @0xRigel) these
concerns were curtailed. We can probably at least mention how this affects
multisigs in one of the lower sections of the SIMD.

@Lichtso also added context to SIMD-0164 about already-deployed, possibly
frozen programs. This proposal will have the same issues.

We probably have to add that ExtendProgram will be accessible via CPI as a
result of this proposal's feature activation. If we don't, self-upgrading
programs won't be able to invoke ExtendProgram via CPI with their PDA
signers.

@deanmlittle
Copy link
Contributor Author

deanmlittle commented Jan 13, 2026

For this reason, I'm actually considering SIMD-0164 as a preferred solution. We
would introduce a new instruction with a new accounts list and deprecate the
old one.

I am of the opinion that simply modifying the existing instruction makes more sense for several reasons:

  • We don't want the current behavior to exist in the first place, so there is no need to preserve it
  • Maintaining two instructions in the enum just to display an error message in one of them is, in my opinion, less sensible than simply introducing an error message into the existing instruction in the case that the upgrade authority is not a signer
  • There are two main happy paths here, one being the feepayer already being the authority, and the other being Squads handling it all for you in their frontend. As such I think the chances of users actually hitting this error are already relatively low

Thus 164 is actually doing more work to achieve the same outcome. For that reason, I do not think 164 is a better solution.

@Lichtso
Copy link
Contributor

Lichtso commented Jan 13, 2026

We don't want the current behavior to exist in the first place, so there is no need to preserve it
Maintaining two instructions in the enum

I re-read SIMD-0164 any yes you are right, it does not mention the old one being disabled, but that would be my intention. Can update that SIMD.

introducing an error message into the existing instruction in the case that the upgrade authority is not a signer

It is not about displaying error messages but preventing unauthorized access from others. Currently ExtendProgram is completely lacking the [signer] authority parameter, that is the issue that got SIMD-0164 started.

https://github.com/anza-xyz/solana-sdk/blob/b0f5666fa6ccd99c47f656d6d19ac16bf8d2030f/loader-v3-interface/src/instruction.rs#L151-L156

@deanmlittle
Copy link
Contributor Author

I believe I have addressed all outstanding feedback. It is really just a matter of making the decision of whether we go with #164 or #431. As we would be throwing a missing signer error either way, I find no justification to pollute our Enum with an additional instruction when we can simply modify the existing one to achieve the same result.

@buffalojoec
Copy link
Contributor

I am of the opinion that simply modifying the existing instruction makes more sense for several reasons:

  • We don't want the current behavior to exist in the first place, so there is no need to preserve it
  • Maintaining two instructions in the enum just to display an error message in one of them is, in my opinion, less sensible than simply introducing an error message into the existing instruction in the case that the upgrade authority is not a signer
  • There are two main happy paths here, one being the feepayer already being the authority, and the other being Squads handling it all for you in their frontend. As such I think the chances of users actually hitting this error are already relatively low

Thus 164 is actually doing more work to achieve the same outcome. For that reason, I do not think 164 is a better solution.

OK, I can appreciate these points. I did some digging, and it seems like we've used both methods, but it depends on what we've historically done with the previous wire format.

For example, with System's CreateAccountPrefunded and Token's InitializeMint2, we introduced new versions since we planned to support their previous versions. Here we do not wish to do this.

With ALT, we relaxed signer requirements for CreateLookupTable, but did not modify the instruction accounts list. That's because the wire format was still backwards compatible. We know both options (SIMD-0164 or this one) for ExtendProgram will not be backwards compatible.

So, since we don't wish to support the old version (as @deanmlittle said above) and we will break the program's interface either way (as I said in the second block of this comment), this proposal does in fact appear to be cleaner to me.

deanmlittle and others added 4 commits January 20, 2026 17:59
constraints of ABI V1, in the case that a multisig upgrade authority wishes to
extend the program data account by greater than 10KiB, it will either need to
create multiple resize proposals, or atomically set its authority to a
top-level signer and reclaim it in the same transaction. The `ExtendProgram`

Choose a reason for hiding this comment

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

Suggested change
top-level signer and reclaim it in the same transaction. The `ExtendProgram`
top-level signer and extend it in the same transaction. The `ExtendProgram`

think this is what you meant here?

Copy link
Contributor

Choose a reason for hiding this comment

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

That line means reclaim the authority after extending at top-level with the temporary authority.

@Lichtso
Copy link
Contributor

Lichtso commented Jan 22, 2026

The only reason why Extend was ever separated from Upgrade was because it was explicitly designed to be permission-less as I understood it. Idea being one would first Extend on top-level and then Upgrade in CPI.

If we make it permissioned self upgrading programs would have to use the transient (but atomic) authority shuffle pattern to sign Extend and/or Upgrade on the top-level. Thus, if we go with an entirely permissioned workflow, there is no use-case for a stand-alone Extend anymore. Extend can implicitly be part of Upgrade.

In that sense neither SIMD-0431 nor SIMD-0164 are needed, we can just disable Extend altogether.

@deanmlittle
Copy link
Contributor Author

The only reason why Extend was ever separated from Upgrade was because it was explicitly designed to be permission-less as I understood it. Idea being one would first Extend on top-level and then Upgrade in CPI.

If we make it permissioned self upgrading programs would have to use the transient (but atomic) authority shuffle pattern to sign Extend and/or Upgrade on the top-level. Thus, if we go with an entirely permissioned workflow, there is no use-case for a stand-alone Extend anymore. Extend can implicitly be part of Upgrade.

In that sense neither SIMD-0431 nor SIMD-0164 are needed, we can just disable Extend altogether.

The authority shuffle is very clunky, and I agree with you that if we do have to shuffle, why not just combine this into upgrade directly? Upon reevaluating our options, I think I actually have an even better solution to this. I think we should instead:

  1. Remove cache invalidation on Extend.
  2. Add a check to inspect InvokeContext for an Upgrade instruction immediately proceeding the Extend instruction for the same program account.

By doing so, Extend can remain "permissionless" as it is today, so none of our workflows change, but it can piggyback on the safety of the Extend instruction for the same program, handling for permissions and cache invalidation without ever having to change the authority. I believe this is a much more elegant solution.

@Lichtso
Copy link
Contributor

Lichtso commented Feb 4, 2026

Add a check to inspect InvokeContext for an Upgrade instruction immediately proceeding the Extend instruction for the same program account.

Only top-level instructions are known ahead of time. For self upgrading programs the Upgrade is in CPI, thus unpredictable. We would need some other mechanism to make sure every Extend is followed by an Upgrade of the same program in the same transaction. Essentially a transient program state, which only exists during the transaction.

By then it becomes very similar to the retract-modify-redeploy-workflow in the early designs of loader-v4. With the difference being that loader-v4 explicitly persisted the retracted state in the program account, while this dirty flag here would be implicit and only exist during the transaction.

@deanmlittle
Copy link
Contributor Author

deanmlittle commented Feb 4, 2026

Only top-level instructions are known ahead of time. For self upgrading programs the Upgrade is in CPI, thus unpredictable. We would need some other mechanism to make sure every Extend is followed by an Upgrade of the same program in the same transaction. Essentially a transient program state, which only exists during the transaction.

Ahh yeah, you're right. Though I suppose we could go the other way and have the upgrade instruction introspect for the Extend? I'll give this some more thought. It would be great to avoid the authority shuffle if possible.

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.

5 participants