@@ -98,41 +98,49 @@ explicitly before the actual upload starts.
9898
9999The _ current slot_ is as in the Clock sysvar.
100100
101+ Delay visibility: The changed version of a program only becomes available after
102+ the current slot ends. Thus, the first transaction in the next slot can invoke
103+ it.
104+
105+ Deployment cooldown: There can be at most one deployment per program in the
106+ same slot. Subsequent deployments have to wait for the next slot.
107+
101108## Detailed Design
102109
103110The feature gate must enable loader-v4 program management and execution.
104111
105- ### Owned Program Accounts
112+ ### Program Account Layout
106113
107114Accounts of programs owned by loader-v4 must have the following layout:
108115
109116- Header (which is 48 bytes long):
110117 - ` u64 ` status enum:
111- - Enum variant ` 0u64 ` : ` Invalid ` , account was zero-filled externally
118+ - Enum variant ` 0u64 ` : ` Uninitalized ` , account was zero-filled externally
112119 - Enum variant ` 1u64 ` : ` NeverBeenDeployed ` , used as write buffer
113120 - Enum variant ` 2u64 ` : ` Retracted ` , program is in maintenance
114121 - Enum variant ` 3u64 ` : ` Deployed ` , program is ready to be executed
115122 - Enum variant ` 4u64 ` : ` Finalized ` , same as ` Deployed ` , but can not be
116123 modified anymore
117- - ` u64 ` Slot in which the program was last deployed, retracted or
118- initialized.
124+ - ` u64 ` Slot in which the program was last deployed.
119125 - ` [u8; 32] ` Authority address which can send program management
120126 instructions.
121127- Body:
122128 - ` [u8] ` The programs executable file
123129
130+ ### Program Account Header Verification
131+
124132Verification the program account checks in the following order that:
125133
126134- the owner of the program account is loader-v4,
127135otherwise throw ` InvalidAccountOwner `
128- - the program account is at least as long enough for the header,
136+ - the program account is at least as long enough for the header (48 bytes) ,
129137otherwise throw ` AccountDataTooSmall `
130138- the program account is writable, otherwise throw ` InvalidArgument `
131139- the provided authority (instruction account at index 1) signed,
132140otherwise throw ` MissingRequiredSignature `
133141- the authority stored in the program account is the one provided,
134142otherwise throw ` IncorrectAuthority `
135- - the status stored in the program account is not ` Invalid ` ,
143+ - the status stored in the program account is not ` Uninitalized ` ,
136144otherwise throw ` InvalidArgument `
137145- the status stored in the program account is not ` Finalized ` ,
138146otherwise throw ` Immutable `
@@ -153,58 +161,78 @@ failing any of the above checks must throw `UnsupportedProgramId`.
153161
154162### Program Management Instructions
155163
164+ The loader-v4 intructions Deploy and Retract are not authorized in CPI.
165+
166+ #### Initialize
167+
168+ - Instruction accounts:
169+ - ` [writable] ` The account to initialize as program account.
170+ - ` [signer] ` The new authority of the program.
171+ - Instruction data:
172+ - Enum variant ` 0u32 `
173+ - Behavior:
174+ - Charge 32 CUs
175+ - Check there are at least two instruction accounts,
176+ otherwise throw ` NotEnoughAccountKeys `
177+ - Check that the owner of the program account is loader-v4,
178+ otherwise throw ` InvalidAccountOwner `
179+ - Check that the program account is writable,
180+ otherwise throw ` InvalidArgument `
181+ - Check that the new authority (instruction account at index 1) has signed,
182+ otherwise throw ` MissingRequiredSignature `
183+ - Change the slot in the program account to the current slot
184+ - Change the status stored in the program account to ` NeverBeenDeployed `
185+ - Copy the new authority address into the program account
186+
156187#### SetAuthority
157188
158189- Instruction accounts:
159190 - ` [writable] ` The program account to change the authority of.
160191 - ` [signer] ` The current authority of the program.
161- - ` [optional( signer) ] ` The new authority of the program.
192+ - ` [signer] ` The new authority of the program.
162193- Instruction data:
163- - Enum variant ` 7u32 `
194+ - Enum variant ` 1u32 `
164195- Behavior:
165196 - Charge 32 CUs
166197 - Check there are at least three instruction accounts,
167198 otherwise throw ` NotEnoughAccountKeys `
168- - If this is an initialization (program account length is too short to
169- contain the header):
170- - the owner of the program account is loader-v4,
171- otherwise throw ` InvalidAccountOwner `
172- - the program account is writable, otherwise throw ` InvalidArgument `
173- - Check that there are enough funds in the program account for rent
174- exemption of the header,
175- otherwise throw ` InsufficientFunds `
176- - otherwise, if this is not an initialization:
177- - Verify the program account
178- - Check that the new authority (instruction account at index 2)
179- is either the system program or has signed,
180- otherwise throw ` MissingRequiredSignature `
181- - If this is an initialization:
182- - Set the length of the program account to the header size
183- - Set the slot to zero, ** not** the current slot
184- - Set the status to ` NeverBeenDeployed `
185- - otherwise, if it is not an initialization:
186- - Check that the authority stored in the program account is different
187- from the one provided, otherwise throw ` InvalidArgument `
199+ - Verify the program account header
200+ - Check that the new authority (instruction account at index 2) has signed,
201+ otherwise throw ` MissingRequiredSignature `
202+ - Check that the current authority is different from the new authority,
203+ otherwise throw ` InvalidArgument `
188204 - Copy the new authority address into the program account
189- - If the the new authority is the system program:
190- - Check that the status stored in the program account is ` Deployed ` or
191- that the status is ` Retracted ` and the program length is 0 (header only),
192- otherwise throw ` InvalidArgument `
193- - Change the status stored in the program account to ` Finalized `
205+
206+ #### Finalize
207+
208+ - Instruction accounts:
209+ - ` [writable] ` The program account to finalize.
210+ - ` [signer] ` The current authority of the program.
211+ - Instruction data:
212+ - Enum variant ` 2u32 `
213+ - Behavior:
214+ - Charge 32 CUs
215+ - Check there are at least two instruction accounts,
216+ otherwise throw ` NotEnoughAccountKeys `
217+ - Verify the program account header
218+ - Check that the status stored in the program account is ` Deployed ` or
219+ that the status is ` Retracted ` and the program length is 0 (header only),
220+ otherwise throw ` InvalidArgument `
221+ - Change the status stored in the program account to ` Finalized `
194222
195223#### SetProgramLength
196224
197225- Instruction accounts:
198226 - ` [writable] ` The program account to change the size of.
199227 - ` [signer] ` The authority of the program.
200228- Instruction data:
201- - Enum variant ` 2u32 `
229+ - Enum variant ` 3u32 `
202230 - ` u32 ` The new size after the operation.
203231- Behavior:
204232 - Charge 32 + new_size_in_bytes / cpi_bytes_per_unit CUs
205233 - Check there are at least two instruction accounts,
206234 otherwise throw ` NotEnoughAccountKeys `
207- - Verify the program account
235+ - Verify the program account header
208236 - Check that the status stored in the program account is
209237 ` NeverBeenDeployed ` or ` Retracted ` ,
210238 otherwise throw ` InvalidArgument `
@@ -213,21 +241,23 @@ failing any of the above checks must throw `UnsupportedProgramId`.
213241 otherwise throw ` InsufficientFunds `
214242 - Set the length of the program account to the requested new size plus
215243 the header size
244+ - Note: In CPI the maximum growth is limited to 10 KiB in ABI v1 and
245+ 0 bytes in ABI v0.
216246
217247#### Write
218248
219249- Instruction accounts:
220250 - ` [writable] ` The program account to write to.
221251 - ` [signer] ` The authority of the program.
222252- Instruction data:
223- - Enum variant ` 0u32 `
253+ - Enum variant ` 4u32 `
224254 - ` u32 ` Byte offset at which to write the given bytes
225255 - ` [u8] ` Chunk of the programs executable file
226256- Behavior:
227257 - Charge 32 + chunk_length_in_bytes / cpi_bytes_per_unit CUs
228258 - Check there are at least two instruction accounts,
229259 otherwise throw ` NotEnoughAccountKeys `
230- - Verify the program account
260+ - Verify the program account header
231261 - Check the status stored in the program account is ` NeverBeenDeployed ` or
232262 ` Retracted ` ,
233263 otherwise throw ` InvalidArgument `
@@ -244,7 +274,7 @@ failing any of the above checks must throw `UnsupportedProgramId`.
244274 - ` [signer] ` The authority of the program.
245275 - ` [] ` The account to copy from.
246276- Instruction data:
247- - Enum variant ` 1u32 `
277+ - Enum variant ` 5u32 `
248278 - ` u32 ` Byte offset at which to write
249279 - ` u32 ` Byte offset at which to read
250280 - ` u32 ` Length of the chunk to copy in bytes
@@ -254,17 +284,16 @@ failing any of the above checks must throw `UnsupportedProgramId`.
254284 otherwise throw ` NotEnoughAccountKeys `
255285 - Check that program account and source account do not alias,
256286 otherwise throw ` AccountBorrowFailed `
257- - Verify the program account
287+ - Verify the program account header
258288 - Check the status stored in the program account is ` NeverBeenDeployed ` or
259289 ` Retracted ` ,
260290 otherwise throw ` InvalidArgument `
261- - Check that the source account is owned by loader v2, v3 or v4,
262- otherwise throw ` InvalidArgument `
263- - and look-up the source header size:
291+ - Check that the source accounts owner and look-up the source header size:
264292 - loader-v2: 0 bytes
265293 - loader-v3 buffer: 37 bytes
266294 - loader-v3 programdata: 45 bytes
267295 - loader-v4: 48 bytes
296+ - if none of the above matches throw ` InvalidArgument `
268297 - Check that the source end offset (sum of source offset and length) does
269298 not exceed the maximum (source account length minus the source header size),
270299 otherwise throw ` AccountDataTooSmall `
@@ -280,17 +309,18 @@ failing any of the above checks must throw `UnsupportedProgramId`.
280309 - ` [writable] ` The program account to deploy.
281310 - ` [signer] ` The authority of the program.
282311- Instruction data:
283- - Enum variant ` 5u32 `
312+ - Enum variant ` 6u32 `
284313- Behavior:
285314 - Charge 32 CUs
286315 - Check there are at least two instruction accounts,
287316 otherwise throw ` NotEnoughAccountKeys `
288- - Verify the program account
289- - Check that the slot stored in the program account is not the current
290- (deployment cooldown), otherwise throw ` InvalidArgument `
317+ - Verify the program account header
291318 - Check that the status stored in the program account is ` NeverBeenDeployed `
292319 or ` Retracted `
293320 otherwise throw ` InvalidArgument `
321+ - If the status is ` Retracted ` then also check that the slot stored in the
322+ program account is not the current (deployment cooldown),
323+ otherwise throw ` InvalidArgument `
294324 - Charge program_length_in_bytes / cpi_bytes_per_unit CUs
295325 - Check that the executable file stored in the program account passes
296326 executable verification
@@ -304,16 +334,16 @@ failing any of the above checks must throw `UnsupportedProgramId`.
304334 - ` [writable] ` The program account to retract.
305335 - ` [signer] ` The authority of the program.
306336- Instruction data:
307- - Enum variant ` 6u32 `
337+ - Enum variant ` 7u32 `
308338- Behavior:
309339 - Charge 32 CUs
310340 - Check there are at least two instruction accounts,
311341 otherwise throw ` NotEnoughAccountKeys `
312- - Verify the program account
313- - Check that the slot stored in the program account is not the current
314- (deployment cooldown), otherwise throw ` InvalidArgument `
342+ - Verify the program account header
315343 - Check that the status stored in the program account is ` Deployed ` ,
316344 otherwise throw ` InvalidArgument `
345+ - Check that the slot stored in the program account is not the current
346+ (deployment cooldown), otherwise throw ` InvalidArgument `
317347 - Note: The slot is ** not** set to the current slot to allow a
318348 retract-modify-redeploy-sequence within the same slot or even within the
319349 same transaction.
@@ -327,7 +357,7 @@ failing any of the above checks must throw `UnsupportedProgramId`.
327357 - ` [signer] ` The authority of the program.
328358 - ` [writable] ` The recipient account.
329359- Instruction data:
330- - Enum variant ` 3u32 `
360+ - Enum variant ` 8u32 `
331361- Behavior:
332362 - Charge 32 CUs
333363 - Check there are at least three instruction accounts,
@@ -336,7 +366,7 @@ failing any of the above checks must throw `UnsupportedProgramId`.
336366 otherwise throw ` AccountBorrowFailed `
337367 - Check that the recipient account is writable,
338368 otherwise throw ` InvalidArgument `
339- - Verify the program account
369+ - Verify the program account header, but skip the ` Finalized ` check
340370 - Transfer lamports which are not needed for rent exemption from the
341371 program account to the recipient account
342372
@@ -347,7 +377,7 @@ failing any of the above checks must throw `UnsupportedProgramId`.
347377 - ` [signer] ` The authority of the program.
348378 - ` [writable] ` The recipient account.
349379- Instruction data:
350- - Enum variant ` 4u32 `
380+ - Enum variant ` 9u32 `
351381- Behavior:
352382 - Charge 32 CUs
353383 - Check there are at least three instruction accounts,
@@ -356,7 +386,7 @@ failing any of the above checks must throw `UnsupportedProgramId`.
356386 otherwise throw ` AccountBorrowFailed `
357387 - Check that the recipient account is writable,
358388 otherwise throw ` InvalidArgument `
359- - Verify the program account
389+ - Verify the program account header
360390 - Check that the status stored in the program account is
361391 ` NeverBeenDeployed ` or ` Retracted ` ,
362392 otherwise throw ` InvalidArgument `
@@ -367,19 +397,19 @@ failing any of the above checks must throw `UnsupportedProgramId`.
367397
368398#### Inital deployment
369399
400+ - Allocate an account to header plus ELF size
370401- Assign account to loader-v4
371- - SetAuthority to the new authority
372- - SetProgramLength to ELF size
402+ - Initialize to the new authority
373403- [ Transaction boundary]
374404- Write chunks repeatedly
375405- [ Transaction boundary]
376406- Deploy
377407
378408#### Redeployment
379409
410+ - Allocate an account to header plus ELF size
380411- Assign buffer account to loader-v4
381- - SetAuthority of the buffer to the new authority
382- - SetProgramLength of buffer to ELF size
412+ - Initialize of the buffer to the new authority
383413- [ Transaction boundary]
384414- Write chunks repeatedly
385415- [ Transaction boundary]
@@ -404,16 +434,12 @@ failing any of the above checks must throw `UnsupportedProgramId`.
404434- Retract
405435- SetProgramLength to 0
406436- WithdrawLamports leaving enough for rent expemtion of the header
407- - SetAuthority to the system program
437+ - Finalize
408438
409439#### Transfer authority
410440
411441- SetAuthority to the new authority
412442
413- #### Finalize
414-
415- - SetAuthority to the system program
416-
417443## Impact
418444
419445- This proposal covers all the use cases loader-v3 had but in a cleaner way and
0 commit comments