Skip to content

Commit

Permalink
First draft
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso committed Aug 20, 2024
1 parent 4b1eaaf commit 8d0ec51
Showing 1 changed file with 273 additions and 0 deletions.
273 changes: 273 additions & 0 deletions proposals/0167-loader-v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
---
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.

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

The loader-v4 program management and execution must be enabled with the
associated feature gate, which simultaneously disables new deployments on
loader-v3.

Loader-v4 has the on-chain address
`LoaderV411111111111111111111111111111111111` and comes with following 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 `MissingAccount`
- Verify the program account
- Check the status stored in the program account is retracted,
otherwise thorw `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 `MissingAccount`
- 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 thorw `InsufficientFunds`
- If there are more than enough funds:
- Check there are at least three instruction accounts,
otherwise throw `MissingAccount`
- 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 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.

Check failure on line 117 in proposals/0167-loader-v4.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 97]

proposals/0167-loader-v4.md:117:81 MD013/line-length Line length [Expected: 80; Actual: 97]
- Instruction data:
- Enum variant `2u32`
- Behavior:
- Check there are at least two instruction accounts,
otherwise throw `MissingAccount`
- 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 `MissingAccount`
- 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 `MissingAccount`
- 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

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 thorw `Immutable`

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 thorw `UnsupportedProgramId`
- the program account was not deployed recently (delay-visibility),
otherwise thorw `UnsupportedProgramId`
- the executable file stored in the program account passes executable
verification, otherwise thorw `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

## 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.
- allows transaction account loading to be simplifed once all loader-v3
programs are migrated. That is because every program would load exactly one
account and these accounts would no longer need to be inspected for redirection
links.

## 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. Such a loader migration would
be possible because programdata accounts of both loaders are 48 bytes long.
Either a new instruction in loader-v3 or 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`
- loader-v3 closes the programdata account (setting its size to zero)

0 comments on commit 8d0ec51

Please sign in to comment.