@@ -22,9 +22,7 @@ This was a workaround to circumvent the finality of the `is_executable` flag,
22
22
which will be ignored by the program runtime from SIMD-0162 onwards.
23
23
Consequentially, this setup of the program account being a proxy account,
24
24
containing the address of the actual program data account, is no longer
25
- necessary and should be removed. Likewise the distinction of executable program
26
- accounts and non-executable buffer accounts is also no longer necessary and
27
- should be removed as well.
25
+ necessary and should be removed.
28
26
29
27
In loader-v3 every instruction which modified the program data had to re-verify
30
28
the ELF in the end. Instead we are now aiming for a more modular workflow which
@@ -36,6 +34,8 @@ transactions.
36
34
Another issue with loader-v3 is that the executable file stored in the
37
35
programdata account is misaligned relative to the beginning of the account.
38
36
This currently requires a copy in the ELF loader to re-align the program.
37
+ To avoid any other alignment issues all states of the accounts owned by a
38
+ loader should have the same layout and only be differentiated by a status enum.
39
39
40
40
Additionally, there currently is no complete specification of the loaders
41
41
program management instructions. This proposal would thus fill that gap once
@@ -71,7 +71,7 @@ a complete implementation, specification and documentation.
71
71
72
72
## New Terminology
73
73
74
- None .
74
+ The _ current slot _ is as in the Clock sysvar .
75
75
76
76
## Detailed Design
77
77
@@ -87,16 +87,17 @@ instruction `UpgradeableLoaderInstruction::Migrate` (see SIMD-0315).
87
87
Accounts of programs owned by loader-v4 must have the following layout:
88
88
89
89
- Header (which is 48 bytes long):
90
+ - ` u64 ` status enum:
91
+ - Enum variant ` 0u64 ` : ` Invalid ` , account was zero-filled externally
92
+ - Enum variant ` 1u64 ` : ` NeverBeenDeployed ` , used as write buffer
93
+ - Enum variant ` 2u64 ` : ` Retracted ` , program is in maintenance
94
+ - Enum variant ` 3u64 ` : ` Deployed ` , program is ready to be executed
95
+ - Enum variant ` 4u64 ` : ` Finalized ` , same as ` Deployed ` , but can not be
96
+ modified anymore
90
97
- ` u64 ` Slot in which the program was last deployed, retracted or
91
98
initialized.
92
99
- ` [u8; 32] ` Authority address which can send program management
93
- instructions. Or if the status is finalized, then the address of the next
94
- version of the program.
95
- - ` u64 ` status enum:
96
- - Enum variant ` 0u64 ` : Retracted, program is in maintenance
97
- - Enum variant ` 1u64 ` : Deployed, program is ready to be executed
98
- - Enum variant ` 2u64 ` : Finalized, same as ` Deployed ` , but can not be
99
- modified anymore
100
+ instructions.
100
101
- Body:
101
102
- ` [u8] ` The programs executable file
102
103
@@ -111,7 +112,9 @@ otherwise throw `AccountDataTooSmall`
111
112
otherwise throw ` MissingRequiredSignature `
112
113
- the authority stored in the program account is the one provided,
113
114
otherwise throw ` IncorrectAuthority `
114
- - the status stored in the program account is not finalized,
115
+ - the status stored in the program account is not ` Invalid ` ,
116
+ otherwise throw ` InvalidArgument `
117
+ - the status stored in the program account is not ` Finalized ` ,
115
118
otherwise throw ` Immutable `
116
119
117
120
### Execution / Invocation
@@ -120,7 +123,7 @@ Invoking programs owned by loader-v4 checks in the following order that:
120
123
121
124
- the owner of the program account is loader-v4
122
125
- the program account is at least as long enough for the header
123
- - the status stored in the program account is not retracted
126
+ - the status stored in the program account is ` Deployed ` or ` Finalized `
124
127
- the program account was not deployed within the current slot (delay
125
128
visibility)
126
129
- the executable file stored in the program account passes executable
@@ -130,8 +133,6 @@ failing any of the above checks must throw `UnsupportedProgramId`.
130
133
131
134
### Program Management Instructions
132
135
133
- All program management instructions must cost 2000 CUs.
134
-
135
136
#### Write
136
137
137
138
- Instruction accounts:
@@ -142,10 +143,12 @@ All program management instructions must cost 2000 CUs.
142
143
- ` u32 ` Byte offset at which to write the given bytes
143
144
- ` [u8] ` Chunk of the programs executable file
144
145
- Behavior:
146
+ - Charge 32 + chunk_length_in_bytes CUs
145
147
- Check there are at least two instruction accounts,
146
148
otherwise throw ` NotEnoughAccountKeys `
147
149
- Verify the program account
148
- - Check the status stored in the program account is retracted,
150
+ - Check the status stored in the program account is ` NeverBeenDeployed ` or
151
+ ` Retracted ` ,
149
152
otherwise throw ` InvalidArgument `
150
153
- Check that the end offset (sum of offset and length of the chunk) does
151
154
not exceed the maximum (program account length minus the header size),
@@ -158,26 +161,28 @@ All program management instructions must cost 2000 CUs.
158
161
- Instruction accounts:
159
162
- ` [writable] ` The program account to copy to.
160
163
- ` [signer] ` The authority of the program.
161
- - ` [] ` The program(data) account to copy from.
164
+ - ` [] ` The account to copy from.
162
165
- Instruction data:
163
166
- Enum variant ` 1u32 `
164
167
- ` u32 ` Byte offset at which to write
165
168
- ` u32 ` Byte offset at which to read
166
169
- ` u32 ` Length of the chunk to copy in bytes
167
170
- Behavior:
171
+ - Charge 32 + chunk_length_in_bytes CUs
168
172
- Check there are at least three instruction accounts,
169
173
otherwise throw ` NotEnoughAccountKeys `
170
174
- Check that program account and source account do not alias,
171
175
otherwise throw ` AccountBorrowFailed `
172
176
- Verify the program account
173
- - Check the status stored in the program account is retracted,
177
+ - Check the status stored in the program account is ` NeverBeenDeployed ` or
178
+ ` Retracted ` ,
174
179
otherwise throw ` InvalidArgument `
175
- - Check that the source account is owned by loader v1, v2, v3 or v4,
180
+ - Check that the source account is owned by loader v2, v3 or v4,
176
181
otherwise throw ` InvalidArgument `
177
182
- and look-up the source header size:
178
- - loader-v1: 0 bytes
179
183
- loader-v2: 0 bytes
180
- - loader-v3: 45 bytes
184
+ - loader-v3 buffer: 37 bytes
185
+ - loader-v3 programdata: 45 bytes
181
186
- loader-v4: 48 bytes
182
187
- Check that the source end offset (sum of source offset and length) does
183
188
not exceed the maximum (source account length minus the source header size),
@@ -193,11 +198,11 @@ All program management instructions must cost 2000 CUs.
193
198
- Instruction accounts:
194
199
- ` [writable] ` The program account to change the size of.
195
200
- ` [signer] ` The authority of the program.
196
- - ` [writable] ` Optional, the recipient account.
197
201
- Instruction data:
198
202
- Enum variant ` 2u32 `
199
203
- ` u32 ` The new size after the operation.
200
204
- Behavior:
205
+ - Charge 32 + new_size_in_bytes CUs
201
206
- Check there are at least two instruction accounts,
202
207
otherwise throw ` NotEnoughAccountKeys `
203
208
- If this is an initialization (program account length is too short to
@@ -209,145 +214,182 @@ All program management instructions must cost 2000 CUs.
209
214
otherwise throw ` MissingRequiredSignature `
210
215
- If this is not an initialization:
211
216
- Verify the program account
212
- - Check that the status stored in the program account is retracted,
217
+ - Check that the status stored in the program account is
218
+ ` NeverBeenDeployed ` or ` Retracted ` ,
213
219
otherwise throw ` InvalidArgument `
214
220
- Check that there are enough funds in the program account for rent
215
- exemption, otherwise throw ` InsufficientFunds `
216
- - If there are more than enough funds:
217
- - Check there are at least three instruction accounts,
221
+ exemption of the new length, otherwise throw ` InsufficientFunds `
222
+ - Set the length of the program account to the requested new size plus
223
+ the header size
224
+ - In case that this is an initialization, also initialize the header:
225
+ - Set the slot to zero, ** not** the current slot
226
+ - Set the authority address (from the instruction account at index 1)
227
+ - Set the status to ` NeverBeenDeployed `
228
+
229
+ #### WithdrawLamports
230
+
231
+ - Instruction accounts:
232
+ - ` [writable] ` The program account to withdraw from.
233
+ - ` [signer] ` The authority of the program.
234
+ - ` [writable] ` The recipient account.
235
+ - Instruction data:
236
+ - Enum variant ` 3u32 `
237
+ - ` u64 ` The amount in lamports.
238
+ - Behavior:
239
+ - Charge 32 CUs
240
+ - Check there are at least two instruction accounts,
218
241
otherwise throw ` NotEnoughAccountKeys `
219
- - Check that the recipient account (instruction account at index 2) is
220
- writable, otherwise throw ` InvalidArgument `
221
- - If a recipient account was provided that is not the program account:
222
- - Transfer the surplus from the program account to the recipient account
223
- - otherwise, if the requested new size is zero throw ` InvalidArgument `
224
- - If the requested new size is zero:
242
+ - Check that program account and recipient account do not alias,
243
+ otherwise throw ` AccountBorrowFailed `
244
+ - Verify the program account
245
+ - Check that there would be enough funds in the program account remaining for
246
+ rent exemption after the withdrawl, otherwise throw ` InsufficientFunds `
247
+ - If all lamports are being withdrawn:
248
+ - Check that the status stored in the program account is
249
+ ` NeverBeenDeployed ` or ` Retracted ` ,
250
+ otherwise throw ` InvalidArgument `
225
251
- Set the length of the program account to 0 (removing the header too)
226
- - If the requested new size is greater than zero:
227
- - Set the length of the program account to the requested new size plus
228
- the header size
229
- - In case that this is an initialization, also initialize the header:
230
- - Set the ` is_executable ` flag to ` true `
231
- - Set the slot to zero, ** not** the current slot
232
- - Set the authority address (from the instruction account at index 1)
233
- - Set the status to retracted
252
+ - Transfer the amount from the program account to the recipient account
234
253
235
254
#### Deploy
236
255
237
256
- Instruction accounts:
238
257
- ` [writable] ` The program account to deploy.
239
258
- ` [signer] ` The authority of the program.
240
259
- Instruction data:
241
- - Enum variant ` 3u32 `
260
+ - Enum variant ` 4u32 `
242
261
- Behavior:
262
+ - Charge 32 CUs
243
263
- Check there are at least two instruction accounts,
244
264
otherwise throw ` NotEnoughAccountKeys `
245
265
- Verify the program account
246
266
- Check that the slot stored in the program account is not the current
247
267
(deployment cooldown), otherwise throw ` InvalidArgument `
248
268
- Note: The cooldown enforces that each pair of an address and a slot can
249
269
uniquely identify a deployment of a program, which simplifies caching logic.
250
- - Check that the status stored in the program account is retracted
270
+ - Check that the status stored in the program account is ` NeverBeenDeployed `
271
+ or ` Retracted `
251
272
otherwise throw ` InvalidArgument `
273
+ - Charge program_length_in_bytes CUs
252
274
- Check that the executable file stored in the program account passes
253
275
executable verification
254
276
- Change the slot in the program account to the current slot
255
- - Change the status stored in the program account to deployed
277
+ - Change the status stored in the program account to ` Deployed `
278
+ - Set the ` is_executable ` flag to ` true `
256
279
257
280
#### Retract
258
281
259
282
- Instruction accounts:
260
283
- ` [writable] ` The program account to retract.
261
284
- ` [signer] ` The authority of the program.
262
285
- Instruction data:
263
- - Enum variant ` 4u32 `
286
+ - Enum variant ` 5u32 `
264
287
- Behavior:
288
+ - Charge 32 CUs
265
289
- Check there are at least two instruction accounts,
266
290
otherwise throw ` NotEnoughAccountKeys `
267
291
- Verify the program account
268
292
- Check that the slot stored in the program account is not the current
269
293
(deployment cooldown), otherwise throw ` InvalidArgument `
270
- - Check that the status stored in the program account is deployed ,
294
+ - Check that the status stored in the program account is ` Deployed ` ,
271
295
otherwise throw ` InvalidArgument `
272
296
- Note: The slot is ** not** set to the current slot to allow a
273
297
retract-modify-redeploy-sequence within the same slot or even within the
274
298
same transaction.
275
- - Change the status stored in the program account to retracted
299
+ - Change the status stored in the program account to ` Retracted `
300
+ - Set the ` is_executable ` flag to ` false `
276
301
277
- #### TransferAuthority
302
+ #### SetAuthority
278
303
279
304
- Instruction accounts:
280
305
- ` [writable] ` The program account to change the authority of.
281
306
- ` [signer] ` The current authority of the program.
282
- - ` [signer] ` The new authority of the program.
307
+ - ` [optional( signer) ] ` The new authority of the program.
283
308
- Instruction data:
284
- - Enum variant ` 5u32 `
309
+ - Enum variant ` 6u32 `
285
310
- Behavior:
311
+ - Charge 32 CUs
286
312
- Check there are at least three instruction accounts,
287
313
otherwise throw ` NotEnoughAccountKeys `
288
314
- Verify the program account
289
315
- Check that the new authority (instruction account at index 2)
290
- signed as well, otherwise throw ` MissingRequiredSignature `
316
+ is either the system program or has signed,
317
+ otherwise throw ` MissingRequiredSignature `
291
318
- Check that the authority stored in the program account is different
292
319
from the one provided, otherwise throw ` InvalidArgument `
293
320
- Copy the new authority address into the program account
321
+ - If the the new authority is the system program:
322
+ - Check that the status stored in the program account is ` Deployed ` ,
323
+ otherwise throw ` InvalidArgument `
324
+ - Change the status stored in the program account to ` Finalized `
325
+
326
+ ### Workflows
327
+
328
+ #### Inital deployment
329
+
330
+ - Assign account to loader-v4
331
+ - SetProgramLength to ELF size
332
+ - [ Transaction boundary]
333
+ - Write chunks repeatedly
334
+ - [ Transaction boundary]
335
+ - Deploy
336
+
337
+ #### Redeployment
338
+
339
+ - Assign buffer account to loader-v4
340
+ - SetProgramLength of buffer to ELF size
341
+ - [ Transaction boundary]
342
+ - Write chunks repeatedly
343
+ - [ Transaction boundary]
344
+ - Retract program
345
+ - SetProgramLength of program to ELF size
346
+ - Copy from buffer to program
347
+ - Deploy program
348
+ - SetProgramLength of buffer to 0
349
+ - WithdrawLamports of buffer to program
350
+
351
+ #### Close: Temporary
352
+
353
+ - Retract
354
+
355
+ #### Close: Recycle
356
+
357
+ - Retract
358
+ - SetProgramLength to 0
359
+ - WithdrawLamports all
360
+
361
+ #### Close: Permanent
362
+
363
+ - Retract
364
+ - SetProgramLength to 0
365
+ - WithdrawLamports leaving enough for rent expemtion of the header
366
+ - SetAuthority to the system program
367
+
368
+ #### Transfer authority
369
+
370
+ - SetAuthority
294
371
295
372
#### Finalize
296
373
297
- - Instruction accounts:
298
- - ` [writable] ` The program account to change the authority of.
299
- - ` [signer] ` The current authority of the program.
300
- - ` [] ` Optional, the reserved address for the next version of the program.
301
- - Instruction data:
302
- - Enum variant ` 6u32 `
303
- - Behavior:
304
- - Check there are at least three instruction accounts,
305
- otherwise throw ` NotEnoughAccountKeys `
306
- - Verify the program account
307
- - Check that the status stored in the program account is deployed,
308
- otherwise throw ` InvalidArgument `
309
- - for the program account of the next version
310
- (instruction account at index 2) check that:
311
- - the owner of the program account is loader-v4,
312
- otherwise throw ` InvalidAccountOwner `
313
- - the program account is at least as long enough for the header,
314
- otherwise throw ` AccountDataTooSmall `
315
- - the authority stored in the program account is the one provided,
316
- otherwise throw ` IncorrectAuthority `
317
- - the status stored in the program account is not finalized,
318
- otherwise throw ` Immutable `
319
- - Copy the address of the next version into the next version field stored in
320
- the previous versions program account
321
- - Change the status stored in the program account to finalized
374
+ - SetAuthority to the system program
322
375
323
376
## Impact
324
377
325
378
- This proposal covers all the use cases loader-v3 had but in a cleaner way and
326
379
comes with a specification.
327
- - loader-v3 had a separate account type for buffers and extra commands for
328
- these buffer accounts, in loader-v4 program accounts can act as buffers, there
329
- is no more distinction.
330
- - loader-v3 deployments always needed a buffer, in loader-v4 it is optional,
331
- one can upload a redeployment into the program account directly.
380
+ - loader-v3 had a separate account layout for buffers and extra commands for
381
+ these buffer accounts, in loader-v4 they are only differentiated by status.
332
382
- loader-v3 had two accounts per program, loader-v4 goes back to having only
333
383
one, thus needs less funds to reach rent exemption.
334
- - loader-v3 closing of programs did finalize them, in loader-v4 all the funds
335
- can be retrieved and the program address repurposed.
384
+ - loader-v3 closing of programs did always finalize them, in loader-v4 there
385
+ is an option to retrieve all the funds the program address can be repurposed.
336
386
- loader-v3 programs could only grow, loader-v4 can shrink programs and also
337
387
retrieve the surplus of funds no longer required for rent exception.
338
388
- loader-v3 programs were always "live" after the first deployment, with
339
389
loader-v4 one can temporarily put a program into maintenance mode without a
340
390
redeployment.
341
- - loader-v3 always required the entire program to be uploaded for a
342
- redeployment, loader-v4 supports partial uploads for patching chunks of the
343
- program.
344
391
- loader-v3 ELFs were misaligned, loader-v4 properly aligns the executable
345
392
file relative to the beginning of the account.
346
- - loader-v4 allows finalized programs to mark which other program supersedes
347
- them which can then be offered as an option in frontends. This provides a
348
- more secure alternative to redeployment / upgrading of programs at the same
349
- address. The keypair for the next version linked during finalization should be
350
- generated beforehand.
351
393
- An option to migrate programs from loader-v3 to loader-v4 without changing
352
394
their program address will be available via a new loader-v3 instruction. (see
353
395
SIMD-0315)
0 commit comments