Skip to content

Commit ce5daeb

Browse files
committed
First draft
1 parent 4b1eaaf commit ce5daeb

File tree

1 file changed

+285
-0
lines changed

1 file changed

+285
-0
lines changed

proposals/0167-loader-v4.md

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
---
2+
simd: '0167'
3+
title: Loader-v4
4+
authors:
5+
- Alexander Meißner
6+
category: Standard
7+
type: Core
8+
status: Draft
9+
created: 2024-08-15
10+
feature: TBD
11+
---
12+
13+
## Summary
14+
15+
A new upgradeable loader which only requires a single account per program.
16+
17+
## Motivation
18+
19+
Loader-v3, which is currently the only deployable loader, requires two accounts
20+
per program. This was a workaround to circumvent the finality of the
21+
`is_executable` flag, which is removed in SIMD-0162. Consequentially, this
22+
setup of the program account being a proxy account, containing the address of
23+
the actual programdata account, is no longer necessary and should be removed.
24+
25+
Additionally, there currently is no complete specification of the loaders
26+
program management instructions. This proposal would thus fill that gap once
27+
loader-v4 goes into production.
28+
29+
See impact for further motivation.
30+
31+
## Alternatives Considered
32+
33+
A delay-visibility-free redeployment could be achieved by keeping the swap
34+
program around until the end of the slot. This would however mean that two
35+
accounts per program must be loaded until the dapp developer reclaims the
36+
second one. That would defy the purpose of this proposal which is to get rid
37+
of the proxy account.
38+
39+
## New Terminology
40+
41+
None.
42+
43+
## Detailed Design
44+
45+
`LoaderV411111111111111111111111111111111111` program management and execution
46+
must be enabled with the associated feature gate, which simultaneously disables
47+
new deployments on loader-v3 (`BPFLoaderUpgradeab1e11111111111111111111111`).
48+
49+
### Owned Program Accounts
50+
51+
Accounts of programs owned by loader-v4 must have the following layout:
52+
53+
- Header (which is 48 bytes long):
54+
- `u64` Slot in which the program was last deployed, retracted or
55+
initialized.
56+
- `[u8; 32]` Authority address which can send program management
57+
instructions.
58+
- `u64` status enum:
59+
- Enum variant `0u64`: Retracted, program is in maintenance
60+
- Enum variant `1u64`: Deployed, program is ready to be executed
61+
- Enum variant `2u64`: Finalized, same as `Deployed`, but can not be
62+
modified anymore
63+
- Body:
64+
- `[u8]` The programs executable file
65+
66+
Verification the program account checks in the following order that:
67+
68+
- the owner of the program account is loader-v4,
69+
otherwise throw `InvalidAccountOwner`
70+
- the program account is at least as long enough for the header,
71+
otherwise throw `AccountDataTooSmall`
72+
- the program account is writable, otherwise throw `InvalidArgument`
73+
- the provided authority (instruction account at index 1) signed,
74+
otherwise throw `MissingRequiredSignature`
75+
- the authority stored in the program account is the one provided,
76+
otherwise throw `IncorrectAuthority`
77+
- the status stored in the program account is not finalized,
78+
otherwise thorw `Immutable`
79+
80+
### Execution / Invocation
81+
82+
Invoking programs owned by loader-v4 checks in the following order that:
83+
84+
- the owner of the program account is loader-v4,
85+
otherwise throw `UnsupportedProgramId`
86+
- the program account is at least as long enough for the header,
87+
otherwise throw `AccountDataTooSmall`
88+
- the status stored in the program account is not retracted,
89+
otherwise thorw `UnsupportedProgramId`
90+
- the program account was not deployed recently (delay-visibility),
91+
otherwise thorw `UnsupportedProgramId`
92+
- the executable file stored in the program account passes executable
93+
verification, otherwise thorw `UnsupportedProgramId`
94+
95+
Otherwise the execution semantics stay the same as in loader-v2 and v3.
96+
Delay-visibility also stays the same as in loader-v3:
97+
98+
- Re/deployed programs act as closed until the end of the slot,
99+
only then becoming available for execution
100+
- The feature set that the executable file is verified against is not
101+
necessarily the current one, but the one of the epoch of the next slot
102+
103+
### Program Management Instructions
104+
105+
#### Write
106+
107+
- Instruction accounts:
108+
- `[writable]` The program account to write to.
109+
- `[signer]` The authority of the program.
110+
- Instruction data:
111+
- Enum variant `0u32`
112+
- `u32` Offset at which to write the given bytes
113+
- `[u8]` Chunk of the programs executable file
114+
- Behavior:
115+
- Check there are at least two instruction accounts,
116+
otherwise throw `MissingAccount`
117+
- Verify the program account
118+
- Check the status stored in the program account is retracted,
119+
otherwise thorw `InvalidArgument`
120+
- Check that the end offset (sum of offset and length of the chunk) does
121+
not exceed the maximum (program account length minus the header size),
122+
otherwise throw `AccountDataTooSmall`
123+
- Copy the chunk into the program account at the offset shifted by the
124+
header size
125+
126+
#### Truncate
127+
128+
- Instruction accounts:
129+
- `[(signer), writable]` The program account to change the size of.
130+
- `[signer]` The authority of the program.
131+
- `[writable]` Optional, the recipient account.
132+
- Instruction data:
133+
- Enum variant `1u32`
134+
- `u32` The new size after the operation.
135+
- Behavior:
136+
- Check there are at least two instruction accounts,
137+
otherwise throw `MissingAccount`
138+
- If this is an initialization (program account length is too short to
139+
contain the header and the requested new size is greater 0):
140+
- the owner of the program account is loader-v4,
141+
otherwise throw `InvalidAccountOwner`
142+
- the program account is writable, otherwise throw `InvalidArgument`
143+
- the program account (instruction account at index 0) signed,
144+
otherwise throw `MissingRequiredSignature`
145+
- the provided authority (instruction account at index 1) signed,
146+
otherwise throw `MissingRequiredSignature`
147+
- If this is not an initialization:
148+
- Verify the program account
149+
- Check that the status stored in the program account is retracted,
150+
otherwise throw `InvalidArgument`
151+
- Check that there are enough funds in the program account for rent
152+
exemption, otherwise thorw `InsufficientFunds`
153+
- If there are more than enough funds:
154+
- Check there are at least three instruction accounts,
155+
otherwise throw `MissingAccount`
156+
- Check that the recipient account (instruction account at index 2) is
157+
writable, otherwise throw `InvalidArgument`
158+
- Transfer the surplus from the program account to the recipient account
159+
- If the requested new size is zero:
160+
- Delete the entire program account, including the header
161+
- If the requested new size is greater than zero:
162+
- Set the length of the program account to the requested new size plus
163+
the header size
164+
- In case that this is an initialization, also initialize the header:
165+
- Set the slot to zero, **not** the current slot
166+
- Set the authority address (from the instruction account at index 1)
167+
- Set the status to retracted
168+
169+
#### Deploy
170+
171+
- Instruction accounts:
172+
- `[writable]` The program account to deploy.
173+
- `[signer]` The authority of the program.
174+
- `[writable]` Optional, an undeployed source program account to take data
175+
and lamports from.
176+
- Instruction data:
177+
- Enum variant `2u32`
178+
- Behavior:
179+
- Check there are at least two instruction accounts,
180+
otherwise throw `MissingAccount`
181+
- Verify the program account
182+
- Check that the deployment cooldown expired,
183+
otherwise throw `InvalidArgument`
184+
- Check that the status stored in the program account is retracted
185+
otherwise throw `InvalidArgument`
186+
- In case a source program was provided (instruction account at index 2):
187+
- Verify the source program account
188+
- Check that the status stored in the source program account is retracted,
189+
otherwise throw `InvalidArgument`
190+
- Check that the executable file stored in the source program account
191+
passes executable verification
192+
- Copy the entire source program account into the program account
193+
- Set the length of the source program account to zero
194+
- Transfer all funds of the source program account to the program
195+
account
196+
- In case no source program was provided:
197+
- Check that the executable file stored in the program account passes
198+
executable verification
199+
- Change the slot in the program account to the current slot
200+
- Change the status stored in the program account to deployed
201+
202+
#### Retract
203+
204+
- Instruction accounts:
205+
- `[writable]` The program account to retract.
206+
- `[signer]` The authority of the program.
207+
- Instruction data:
208+
- Enum variant `3u32`
209+
- Behavior:
210+
- Check there are at least two instruction accounts,
211+
otherwise throw `MissingAccount`
212+
- Verify the program account
213+
- Check that the deployment cooldown expired,
214+
otherwise throw `InvalidArgument`
215+
- Check that the status stored in the program account is deployed,
216+
otherwise throw `InvalidArgument`
217+
- Note: The slot is **not** set to the current slot to allow a
218+
retract-modify-redeploy-sequence within the same slot
219+
- Change the status stored in the program account to retracted
220+
221+
#### TransferAuthority
222+
223+
- Instruction accounts:
224+
- `[writable]` The program account to change the authority of.
225+
- `[signer]` The current authority of the program.
226+
- `[signer]` Optional, the new authority of the program.
227+
- Instruction data:
228+
- Enum variant `4u32`
229+
- Behavior:
230+
- Check there are at least two instruction accounts,
231+
otherwise throw `MissingAccount`
232+
- Verify the program account
233+
- In case a new authority was provided (instruction account at index 2):
234+
- Check that it signed as well,
235+
otherwise throw `MissingRequiredSignature`
236+
- Check that the authority stored in the program account is different
237+
from the one provided, otherwise throw `InvalidArgument`
238+
- Copy the new authority address into the program account
239+
- In case no new authority was provided:
240+
- Check that the status stored in the program account is deployed,
241+
otherwise throw `InvalidArgument`
242+
- Change the status stored in the program account to finalized
243+
244+
## Impact
245+
246+
This proposal:
247+
248+
- covers all the use cases loader-v3 had but in a cleaner way and comes with
249+
a specification.
250+
- makes deployment slightly cheaper for dapp developers as they would no longer
251+
have to burn funds for the rent exception of the proxy account.
252+
- provides an alternative redeployment path which does not require a big
253+
deposit of funds for rent exception during the upload.
254+
- enables dapp developers to withdrawl the surplus of funds required for rent
255+
exception when shortening the length of program accounts or closing them.
256+
- shortens the workflow of temporarily closing a program to a single
257+
instruction, instead of having to build and redeploy an empty program.
258+
- allows transaction account loading to be simplifed once all loader-v3
259+
programs are migrated. That is because every program would load exactly one
260+
account and these accounts would no longer need to be inspected for redirection
261+
links.
262+
263+
## Security Considerations
264+
265+
None.
266+
267+
## Backwards Compatibility
268+
269+
This proposal does not break any existing programs. However, dapp developers
270+
might want to profit from the new program mangement instructions without
271+
influencing their users work flows. To do so they would need a way to turn the
272+
program accounts of loader-v3 to program accounts of loader-v4, changing the
273+
account owner but keeping the program address. Such a loader migration would
274+
be possible because programdata accounts of both loaders are 48 bytes long.
275+
Either a new instruction in loader-v3 or an automatic mechanism in the program
276+
runtime (triggered by feature activation) could then perform the following
277+
steps per program:
278+
279+
- loader-v3 clears the program proxy account (setting its size to zero)
280+
- loader-v3 transfers all funds from the programdata to the proxy account
281+
- loader-v3 gifts the program proxy account to loader-v4
282+
- loader-v4 initializes it via `Truncate`
283+
- loader-v4 copies the data from the programdata account via `Write`
284+
- loader-v4 deploys it via `Deploy`
285+
- loader-v3 closes the programdata account (setting its size to zero)

0 commit comments

Comments
 (0)