Skip to content

Gate initialize by upgrade authority - #187

Closed
kaze-cow wants to merge 1 commit into
mainfrom
kaze/sc-438-gate-initialize-with-the-program-upgrade-authority
Closed

kaze-cow wants to merge 1 commit into
mainfrom
kaze/sc-438-gate-initialize-with-the-program-upgrade-authority

Conversation

@kaze-cow

@kaze-cow kaze-cow commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Description

Make it so that only the BPF Upgradable Loader's upgrade authority (same as the original deployer of the program) can call Initialize

Motivation

Its technically possible that after program deployment, someone could come in and call Initialize, setting their own data and permissions, prior to us being able to do so. This, and could cause us to lose the ability to use a deployment address that we want to use. To prevent this from happening, we need some access control. And conveniently, the address of the program deployer is stored in the BPF upgradable loader!

Other considerations

In the absolute simplest case, we could have gated the initialize function to specified constant address. This would allow for no breaking change to the Initialize interface and absolute simplest change. But its not too hard to have it use the BPF upgradable address and we want to make sure the initialization process is as robust and straightforward as possible.

The Program Data account structure is well known and simple, so we could have hardcoded the data to decode it right in our project without depending upon the new solana-loader-v3-interface dependency. But as we are approaching launch and having this be overly complicated is unnecessary, I like this approach.

@kaze-cow
kaze-cow requested a review from a team as a code owner October 8, 2026 08:20
@kaze-cow kaze-cow self-assigned this Oct 8, 2026
@linear-code

linear-code Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

SC-438

Comment on lines +121 to +146
"name": "program_data",
"pda": {
"seeds": [
{
"kind": "const",
"value": [
5,
84,
138,
128,
134,
3,
65,
189,
80,
66,
142,
50,
244,
98,
61,
68,
117,
240,
124,
240,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this value needs to be manually updated. My suggestion is to just let AI handle it at this point 😓

Comment on lines +20 to +21
/// `payer` funds the new accounts' rent and signs. It must be the program's
/// upgrade authority, as recorded in `program_data`, which must be the

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.

Uhm, no?

Comment on lines 23 to +44
@@ -39,13 +41,14 @@ use crate::SettlementInstruction;
/// Wire format: `[discriminator=3, manager (32 bytes), solver_authority (32
/// bytes), reclaim_authority (32 bytes), settlement_owned_order_authority (32
/// bytes)]`, 129 bytes. Required accounts: `[payer (W,S), state_pda (W),
/// native_sol_buffer (W), system_program (R)]`. The system program must be available for the
/// native_sol_buffer (W), program_data (R), system_program (R)]`. The system program must be available for the

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.

Nit, the line lenght is off.

Comment on lines +22 to +25
/// program's `ProgramData` account under the upgradeable loader. It is meant
/// to be the transaction's fee payer: the state is created once at deployment and never deallocated,
/// so there's no need for a dedicated funding account separate from whoever
/// pays for the deployment transaction.

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.

Nit, not part of this PR. I think this is clear and we can drop it.

Suggested change
/// program's `ProgramData` account under the upgradeable loader. It is meant
/// to be the transaction's fee payer: the state is created once at deployment and never deallocated,
/// so there's no need for a dedicated funding account separate from whoever
/// pays for the deployment transaction.
/// program's `ProgramData` account under the upgradeable loader.

});
// Only the upgrade authority recorded in the resolved programData account
// may initialize.
const programData = initialize.accounts[3].address;

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.

Let's not use magic numbers like 3, we should rederive the account we need.
Also, the next function's signature would look a lot more natural to me if it were setUpgradeAuthority(svm, program*Id*, payer.address), why should someone care about the program data at this point?

Comment on lines +37 to +40
/// Record `authority` as the upgrade authority in the `programData` account,
/// which LiteSVM deploys without one. The authority sits after the
/// `ProgramData` header's variant tag (4 bytes), slot (8 bytes) and
/// `Option` tag (1 byte).

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.

Can't we do better than a lot of magic constants?

if !payer.is_signer() || program_data.address() != &get_program_data_address(program_id) {
return Err(SettlementError::UnauthorizedInitialize.into());
}
// The program bytes trail the loader state, which `deserialize` ignores.

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.

Will need to read up on how this serializes.

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.

Suggested test: rejects_reinitializing_after_renouncing_upgrade_authority.

@kaze-cow

kaze-cow commented Oct 8, 2026

Copy link
Copy Markdown
Contributor Author

asked to simplify this PR to use the constant owner approach to prevent needing to understand BPF loader. will close this in favor of #191

@kaze-cow kaze-cow closed this Oct 8, 2026
kaze-cow added a commit that referenced this pull request Oct 9, 2026
# Description

Make it so that only a hardcoded address defined in the program can call
`Initialize`.

## Motivation

Its technically possible that after program deployment, someone could
come in and call `Initialize`, setting their own data and permissions,
prior to us being able to do so. This, and could cause us to lose the
ability to use a deployment address that we want to use. To prevent this
from happening, we need some access control.

## Other considerations

It was also previously considered in #187 to use the BPF Upgradalbe
loader's upgrade authority. In honesty this is probably the best way to
go as the deployer would always be matched up with whoever actually
pushed up the program, but we are in a hurry and this option is much
simpler and works almost as well.

In the case that the program is accidentally deployed with the wrong
`DEPLOYER` set, it is possible for the upgrade authority to redeploy the
program with the correct `DEPLOYER` and try again, so the consequences
of a mistaken deployment are low.

---------

Co-authored-by: Federico Giacon <58218759+fedgiac@users.noreply.github.com>
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