Skip to content

Commit 2a383cd

Browse files
committed
First draft
1 parent 4b1eaaf commit 2a383cd

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

proposals/0167-loader-v4.md

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

0 commit comments

Comments
 (0)