Skip to content

Commit

Permalink
First draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Sep 5, 2024
1 parent 4b1eaaf commit 2a383cd
Showing 1 changed file with 296 additions and 0 deletions.
296 changes: 296 additions & 0 deletions proposals/0167-loader-v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
---
simd: '0167'
title: Loader-v4
authors:
- Alexander Meißner
category: Standard
type: Core
status: Draft
created: 2024-08-15
feature: TBD
---

## Summary

A new upgradeable loader which only requires a single account per program.

## Motivation

Loader-v3, which is currently the only deployable loader, requires two accounts
per program. This was a workaround to circumvent the finality of the
`is_executable` flag, which is removed in SIMD-0162. Consequentially, this
setup of the program account being a proxy account, containing the address of
the actual programdata account, is no longer necessary and should be removed.

Another issue with loader-v3 is that the executable file stored in the
programdata account is misaligned relative to the beginning of the account.

Additionally, there currently is no complete specification of the loaders
program management instructions. This proposal would thus fill that gap once
loader-v4 goes into production.

See impact for further motivation.

## Alternatives Considered

A delay-visibility-free redeployment could be achieved by keeping the swap
program around until the end of the slot. This would however mean that two
accounts per program must be loaded until the dapp developer reclaims the
second one. That would defy the purpose of this proposal which is to get rid
of the proxy account.

## New Terminology

None.

## Detailed Design

`LoaderV411111111111111111111111111111111111` program management and execution
must be enabled with the associated feature gate, which simultaneously disables
new deployments on loader-v3 (`BPFLoaderUpgradeab1e11111111111111111111111`),
throwing `InvalidIstructionData` if `DeployWithMaxDataLen` is called.

### Owned Program Accounts

Accounts of programs owned by loader-v4 must have the following layout:

- Header (which is 48 bytes long):
- `u64` Slot in which the program was last deployed, retracted or
initialized.
- `[u8; 32]` Authority address which can send program management
instructions.
- `u64` status enum:
- Enum variant `0u64`: Retracted, program is in maintenance
- Enum variant `1u64`: Deployed, program is ready to be executed
- Enum variant `2u64`: Finalized, same as `Deployed`, but can not be
modified anymore
- Body:
- `[u8]` The programs executable file

Verification the program account checks in the following order that:

- the owner of the program account is loader-v4,
otherwise throw `InvalidAccountOwner`
- the program account is at least as long enough for the header,
otherwise throw `AccountDataTooSmall`
- the program account is writable, otherwise throw `InvalidArgument`
- the provided authority (instruction account at index 1) signed,
otherwise throw `MissingRequiredSignature`
- the authority stored in the program account is the one provided,
otherwise throw `IncorrectAuthority`
- the status stored in the program account is not finalized,
otherwise throw `Immutable`

### Execution / Invocation

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

- the owner of the program account is loader-v4,
otherwise throw `UnsupportedProgramId`
- the program account is at least as long enough for the header,
otherwise throw `AccountDataTooSmall`
- the status stored in the program account is not retracted,
otherwise throw `UnsupportedProgramId`
- the program account was not deployed recently (delay-visibility),
otherwise throw `UnsupportedProgramId`
- the executable file stored in the program account passes executable
verification, otherwise throw `UnsupportedProgramId`

Otherwise the execution semantics stay the same as in loader-v2 and v3.
Delay-visibility also stays the same as in loader-v3:

- Re/deployed programs act as closed until the end of the slot,
only then becoming available for execution
- The feature set that the executable file is verified against is not
necessarily the current one, but the one of the epoch of the next slot

### Program Management Instructions

#### Write

- Instruction accounts:
- `[writable]` The program account to write to.
- `[signer]` The authority of the program.
- Instruction data:
- Enum variant `0u32`
- `u32` Offset at which to write the given bytes
- `[u8]` Chunk of the programs executable file
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- Verify the program account
- Check the status stored in the program account is retracted,
otherwise throw `InvalidArgument`
- Check that the end offset (sum of offset and length of the chunk) does
not exceed the maximum (program account length minus the header size),
otherwise throw `AccountDataTooSmall`
- Copy the chunk into the program account at the offset shifted by the
header size

#### Truncate

- Instruction accounts:
- `[(signer), writable]` The program account to change the size of.
- `[signer]` The authority of the program.
- `[writable]` Optional, the recipient account.
- Instruction data:
- Enum variant `1u32`
- `u32` The new size after the operation.
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- If this is an initialization (program account length is too short to
contain the header and the requested new size is greater 0):
- the owner of the program account is loader-v4,
otherwise throw `InvalidAccountOwner`
- the program account is writable, otherwise throw `InvalidArgument`
- the program account (instruction account at index 0) signed,
otherwise throw `MissingRequiredSignature`
- the provided authority (instruction account at index 1) signed,
otherwise throw `MissingRequiredSignature`
- If this is not an initialization:
- Verify the program account
- Check that the status stored in the program account is retracted,
otherwise throw `InvalidArgument`
- Check that there are enough funds in the program account for rent
exemption, otherwise throw `InsufficientFunds`
- If there are more than enough funds:
- Check there are at least three instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- Check that the recipient account (instruction account at index 2) is
writable, otherwise throw `InvalidArgument`
- Transfer the surplus from the program account to the recipient account
- If the requested new size is zero:
- Delete the entire program account, including the header
- If the requested new size is greater than zero:
- Set the length of the program account to the requested new size plus
the header size
- In case that this is an initialization, also initialize the header:
- Set the `is_executable` flag to `true`
- Set the slot to zero, **not** the current slot
- Set the authority address (from the instruction account at index 1)
- Set the status to retracted

#### Deploy

- Instruction accounts:
- `[writable]` The program account to deploy.
- `[signer]` The authority of the program.
- `[writable]` Optional, an undeployed source program account to take data
and lamports from.
- Instruction data:
- Enum variant `2u32`
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- Verify the program account
- Check that the deployment cooldown expired,
otherwise throw `InvalidArgument`
- Check that the status stored in the program account is retracted
otherwise throw `InvalidArgument`
- In case a source program was provided (instruction account at index 2):
- Verify the source program account
- Check that the status stored in the source program account is retracted,
otherwise throw `InvalidArgument`
- Check that the executable file stored in the source program account
passes executable verification
- Copy the entire source program account into the program account
- Set the length of the source program account to zero
- Transfer all funds of the source program account to the program
account
- In case no source program was provided:
- Check that the executable file stored in the program account passes
executable verification
- Change the slot in the program account to the current slot
- Change the status stored in the program account to deployed

#### Retract

- Instruction accounts:
- `[writable]` The program account to retract.
- `[signer]` The authority of the program.
- Instruction data:
- Enum variant `3u32`
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- Verify the program account
- Check that the deployment cooldown expired,
otherwise throw `InvalidArgument`
- Check that the status stored in the program account is deployed,
otherwise throw `InvalidArgument`
- Note: The slot is **not** set to the current slot to allow a
retract-modify-redeploy-sequence within the same slot
- Change the status stored in the program account to retracted

#### TransferAuthority

- Instruction accounts:
- `[writable]` The program account to change the authority of.
- `[signer]` The current authority of the program.
- `[signer]` Optional, the new authority of the program.
- Instruction data:
- Enum variant `4u32`
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `NotEnoughAccountKeys`
- Verify the program account
- In case a new authority was provided (instruction account at index 2):
- Check that it signed as well,
otherwise throw `MissingRequiredSignature`
- Check that the authority stored in the program account is different
from the one provided, otherwise throw `InvalidArgument`
- Copy the new authority address into the program account
- In case no new authority was provided:
- Check that the status stored in the program account is deployed,
otherwise throw `InvalidArgument`
- Change the status stored in the program account to finalized

## Impact

This proposal:

- covers all the use cases loader-v3 had but in a cleaner way and comes with
a specification.
- makes deployment slightly cheaper for dapp developers as they would no longer
have to burn funds for the rent exception of the proxy account.
- provides an alternative redeployment path which does not require a big
deposit of funds for rent exception during the upload.
- enables dapp developers to withdrawl the surplus of funds required for rent
exception when shortening the length of program accounts or closing them.
- shortens the workflow of temporarily closing a program to a single
instruction, instead of having to build and redeploy an empty program.
- properly alignes the executable file relative to the beginning of the
account. In loader-v3 it is misaligned.
- once all loader-v3 programs are migrated:
- allows transaction account loading to be simplifed, because every program
would load exactly one account, no need to load the proxy account to get to
the actual program data (which is not listed in the transaction accounts).
- allows the removal of the write lock demotion exception if loader-v3 is
present in a transaction.
- corrects the miscounting of the proxy account size towards the total
transaction account loading limit.

## Security Considerations

None.

## Backwards Compatibility

This proposal does not break any existing programs. However, dapp developers
might want to profit from the new program mangement instructions without
influencing their users work flows. To do so they would need a way to turn the
program accounts of loader-v3 to program accounts of loader-v4, changing the
account owner but keeping the program address. A potential issue is that the
programdata header of loader-v3 is only 45 bytes long while loader-v4 takes 48
bytes. An automatic mechanism in the program runtime (triggered by feature
activation) could then perform the following steps per program:

- 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
- loader-v4 initializes it via `Truncate`
- loader-v4 copies the data from the programdata account via `Write`
- loader-v4 deploys it via `Deploy`
- Optinally, loader-v4 finalizes it without a next version forwarding
- loader-v3 closes the programdata account (setting its size to zero)

0 comments on commit 2a383cd

Please sign in to comment.