Skip to content

SIMD-0167: Loader-v4#167

Open
Lichtso wants to merge 22 commits intosolana-foundation:mainfrom
Lichtso:loader-v4
Open

SIMD-0167: Loader-v4#167
Lichtso wants to merge 22 commits intosolana-foundation:mainfrom
Lichtso:loader-v4

Conversation

@Lichtso
Copy link
Contributor

@Lichtso Lichtso commented Aug 20, 2024

No description provided.

Copy link

@nickfrosty nickfrosty left a comment

Choose a reason for hiding this comment

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

I also noticed there are several typos on the word "throw"

topointon-jump
topointon-jump previously approved these changes Nov 1, 2024
Copy link

@topointon-jump topointon-jump left a comment

Choose a reason for hiding this comment

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

Very nice to see this well-written, well-specified SIMD!

Would be great to get more detail on the migration path from v3 to v4.


- loader-v3 clears the program proxy account (setting its size to zero)
- loader-v3 transfers all funds from the programdata to the proxy account
- loader-v3 gifts the program proxy account to loader-v4

Choose a reason for hiding this comment

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

How would the gifting work? Do we need to add a new instruction to the v3 loader? Will this upgrade mechanism be specified in a future SIMD?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see three options here:

  1. A migrate instruction for loader-v3 which the dApp devs trigger themselves
  2. A migrate instruction for loader-v3 which we the protocol engineers trigger
  3. A feature gate which scans the accounts DB and migrates all loader-v3 programs

I would prefer the second option as that allows us to keep the gathering of the loader-v3 program list and then slowly working through it off-chain and still makes sure that all loader-v3 programs get migrated.

Copy link
Contributor Author

@Lichtso Lichtso Jan 16, 2025

Choose a reason for hiding this comment

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

Added a more detailed description of how this would work:
f2d4970

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.

Getting really close on my side. Based on our last discussion we wanted to add the following to SetAuthority:

  • If the program is Uninitialized will skip the existing authority check, set the new authority, and set the status to NeverBeenDeployed.
  • Programs that are Retracted can be finalized only if the program length is 0

buffalojoec
buffalojoec previously approved these changes Aug 22, 2025
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.

Let's do it!

Comment on lines +147 to +148
- the program account was not deployed within the current slot (delay
visibility)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we define "delay visibility" or "deployment cooldown" in terminology and use the term consistently in this SIMD?

- Change the status stored in the program account to `Retracted`
- Set the `is_executable` flag to `false`

#### SetAuthority
Copy link
Contributor

Choose a reason for hiding this comment

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

This instruction does three different actions: initialize, set-authority, or finalize. All of them set the authority field but they are all different enough that they warrant having specific instructions, in my opinion.

Splitting this instruction up would help clarify instruction account requirements:

  1. Initialize does not require an instruction account to specify the current authority
  2. SetAuthority would always require the new authority to be a signer, no need to specify it as optional
  3. Finalize does not require an instruction account to specify a new authority

Additionally, the way SetAuthority is specified to be treated as an "initialization" is an anti-pattern because it's typically assumed that when initializing accounts on solana that the caller allocates the account data before invoking the initialization instruction.


None.

## Detailed Design
Copy link
Contributor

@jstarry jstarry Aug 26, 2025

Choose a reason for hiding this comment

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


The feature gate must enable loader-v4 program management and execution.

### Owned Program Accounts
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I don't really understand what "owned" is supposed to indicate here. Can we call this section "Program Account Layout"?

otherwise throw `InvalidArgument`
- Check that there are enough funds in the program account for rent
exemption of the new length, otherwise throw `InsufficientFunds`
- Set the length of the program account to the requested new size plus
Copy link
Contributor

@jstarry jstarry Aug 26, 2025

Choose a reason for hiding this comment

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

@Lichtso Lichtso requested a review from jstarry September 29, 2025 20:15
Comment on lines +118 to +122
- Enum variant `0u64`: `Uninitalized`, account was zero-filled externally
- Enum variant `1u64`: `NeverBeenDeployed`, used as write buffer
- Enum variant `2u64`: `Retracted`, program is in maintenance
- Enum variant `3u64`: `Deployed`, program is ready to be executed
- Enum variant `4u64`: `Finalized`, same as `Deployed`, but can not be
Copy link
Contributor

Choose a reason for hiding this comment

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

some typo fixes (u64 -> u32 and Uninitalized -> Uninitialized) and a new naming suggestion for NeverBeenDeployed -> Buffered.

Suggested change
- Enum variant `0u64`: `Uninitalized`, account was zero-filled externally
- Enum variant `1u64`: `NeverBeenDeployed`, used as write buffer
- Enum variant `2u64`: `Retracted`, program is in maintenance
- Enum variant `3u64`: `Deployed`, program is ready to be executed
- Enum variant `4u64`: `Finalized`, same as `Deployed`, but can not be
- Enum variant `0u32`: `Uninitialized`, account was zero-filled externally
- Enum variant `1u32`: `Buffered`, used as write buffer
- Enum variant `2u32`: `Retracted`, program is in maintenance
- Enum variant `3u32`: `Deployed`, program is ready to be executed
- Enum variant `4u32`: `Finalized`, same as `Deployed`, but can not be


### Program Account Header Verification

Verification the program account checks in the following order that:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Verification the program account checks in the following order that:
Verification of the program account checks the following in order:


- the owner of the program account is loader-v4,
otherwise throw `InvalidAccountOwner`
- the program account is at least as long enough for the header (48 bytes),
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- the program account is at least as long enough for the header (48 bytes),
- the program account is at least long enough for the header (48 bytes),

Invoking programs owned by loader-v4 checks in the following order that:

- the owner of the program account is loader-v4
- the program account is at least as long enough for the header
Copy link
Contributor

Choose a reason for hiding this comment

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

In light of the conversation here should we change this to check that the program account is strictly greater than the length of the header? A finalized program with executable length of zero definitely wouldn't be executable. But this is technically a sub-case of the later "executable verification" check anyways.


### Program Management Instructions

The loader-v4 intructions Deploy and Retract are not authorized in CPI.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The loader-v4 intructions Deploy and Retract are not authorized in CPI.
The loader-v4 instructions Deploy and Retract are not authorized in CPI. If
these instructions are invoked from another program, throw
`ProgramFailedToComplete`.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was thinking about the CPI restriction some more: Isn't it a problem for multisig and governance? E.g. #167 (comment) would not work, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah yeah, you're right. Didn't think about that. Let's try to remove this restriction then. If I remember correctly it's because we don't yet allow changing the executable flag from CPI.

- Enum variant `3u32`
- `u32` The new size after the operation.
- Behavior:
- Charge 32 + new_size_in_bytes / cpi_bytes_per_unit CUs
Copy link
Contributor

Choose a reason for hiding this comment

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

We should only charge CU's for the increased size (if any)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we discussed this before. The reason why we charge for the entire length is because the program runtime has to copy over the existing data into the new allocation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah yeah, you're right never mind.

- Instruction data:
- Enum variant `4u32`
- `u32` Byte offset at which to write the given bytes
- `[u8]` Chunk of the programs executable file
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks different from loader-v3 which serializes the length of the chunk as a u64 before the chunk data. Are you implying that the length isn't serialized here and that chunk_length_in_bytes is inferred from ix.data.len - 4 bytes (enum variant) - 4 bytes (offset)? I think we should match loader-v3 behavior and serialize the chunk length as well. But consider serializing the length as u16 or u32 instead of u64 to save some bytes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is the advantage of doing so? It would introduce additional failure cases of the explicit field and implicit calculation disagreeing.


failing any of the above checks must throw `UnsupportedProgramId`.

### Program Management Instructions
Copy link
Contributor

Choose a reason for hiding this comment

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

Should also add a note saying that instruction data length is limited to 1232 bytes to match loader-v3 behavior

otherwise throw `InvalidArgument`
- Check that the executable length is not longer than the program account,
otherwise throw `InvalidArgument`
- Charge program_length_in_bytes / cpi_bytes_per_unit CUs
Copy link
Contributor

Choose a reason for hiding this comment

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

We should only charge for the executable length rather than the full account data length

Suggested change
- Charge program_length_in_bytes / cpi_bytes_per_unit CUs
- Charge executable length / cpi_bytes_per_unit CUs

- Charge program_length_in_bytes / cpi_bytes_per_unit CUs
- Check that the executable file stored in the program account passes
executable verification
- Change the executable length in the program account header
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- Change the executable length in the program account header
- Change the executable length in the program account header to the specified
value.

@Lichtso
Copy link
Contributor Author

Lichtso commented Nov 11, 2025

If we explicitly encode the ELF length anyway, we might as well move the header down to become a footer:

From Header | ELF | Empty Space to e.g. ELF | Footer | Empty Space | ELF Length. This has the advantage that the meta-data becomes extensible, which makes it more future proof, as the footer could grow without changing any layout.

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.