Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_program_fd_bpf_loader_program_h
2 : #define HEADER_fd_src_flamenco_runtime_program_fd_bpf_loader_program_h
3 :
4 : /* fd_bpf_loader_v3_program.h is the third version of the BPF loader
5 : program.
6 :
7 : Address: BPFLoaderUpgradeab1e11111111111111111111111 */
8 :
9 : #include "../../fd_flamenco_base.h"
10 : #include "../../accdb/fd_accdb.h"
11 : #include "../../progcache/fd_progcache_base.h"
12 : #include "../../../ballet/txn/fd_txn.h"
13 :
14 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/programs/bpf_loader/src/lib.rs#L67-L69 */
15 : #define DEFAULT_LOADER_COMPUTE_UNITS (570UL )
16 : #define DEPRECATED_LOADER_COMPUTE_UNITS (1140UL)
17 : #define UPGRADEABLE_LOADER_COMPUTE_UNITS (2370UL)
18 :
19 : /* https://github.com/anza-xyz/agave/blob/77daab497df191ef485a7ad36ed291c1874596e5/sdk/program/src/bpf_loader_upgradeable.rs#L29-L120 */
20 39 : #define SIZE_OF_PROGRAM (36UL ) /* UpgradeableLoaderState::size_of_program() */
21 60 : #define BUFFER_METADATA_SIZE (37UL ) /* UpgradeableLoaderState::size_of_buffer_metadata() */
22 396 : #define PROGRAMDATA_METADATA_SIZE (45UL ) /* UpgradeableLoaderState::size_of_programdata_metadata() */
23 18 : #define SIZE_OF_UNINITIALIZED (4UL ) /* UpgradeableLoaderState::size_of_uninitialized() */
24 :
25 : /* InstructionError conversions
26 : https://github.com/anza-xyz/agave/blob/ced98f1ebe73f7e9691308afa757323003ff744f/sdk/program/src/program_error.rs#L127-L160 */
27 51 : #define BUILTIN_BIT_SHIFT (32UL)
28 :
29 0 : #define CUSTOM_ZERO ((1UL) << BUILTIN_BIT_SHIFT)
30 0 : #define INVALID_ARGUMENT ((2UL) << BUILTIN_BIT_SHIFT)
31 0 : #define INVALID_INSTRUCTION_DATA ((3UL) << BUILTIN_BIT_SHIFT)
32 0 : #define INVALID_ACCOUNT_DATA ((4UL) << BUILTIN_BIT_SHIFT)
33 0 : #define ACCOUNT_DATA_TOO_SMALL ((5UL) << BUILTIN_BIT_SHIFT)
34 0 : #define INSUFFICIENT_FUNDS ((6UL) << BUILTIN_BIT_SHIFT)
35 0 : #define INCORRECT_PROGRAM_ID ((7UL) << BUILTIN_BIT_SHIFT)
36 0 : #define MISSING_REQUIRED_SIGNATURES ((8UL) << BUILTIN_BIT_SHIFT)
37 0 : #define ACCOUNT_ALREADY_INITIALIZED ((9UL) << BUILTIN_BIT_SHIFT)
38 0 : #define UNINITIALIZED_ACCOUNT ((10UL) << BUILTIN_BIT_SHIFT)
39 0 : #define NOT_ENOUGH_ACCOUNT_KEYS ((11UL) << BUILTIN_BIT_SHIFT)
40 0 : #define ACCOUNT_BORROW_FAILED ((12UL) << BUILTIN_BIT_SHIFT)
41 0 : #define MAX_SEED_LENGTH_EXCEEDED ((13UL) << BUILTIN_BIT_SHIFT)
42 0 : #define INVALID_SEEDS ((14UL) << BUILTIN_BIT_SHIFT)
43 0 : #define BORSH_IO_ERROR ((15UL) << BUILTIN_BIT_SHIFT)
44 0 : #define ACCOUNT_NOT_RENT_EXEMPT ((16UL) << BUILTIN_BIT_SHIFT)
45 0 : #define UNSUPPORTED_SYSVAR ((17UL) << BUILTIN_BIT_SHIFT)
46 0 : #define ILLEGAL_OWNER ((18UL) << BUILTIN_BIT_SHIFT)
47 0 : #define MAX_ACCOUNTS_DATA_ALLOCATIONS_EXCEEDED ((19UL) << BUILTIN_BIT_SHIFT)
48 0 : #define INVALID_ACCOUNT_DATA_REALLOC ((20UL) << BUILTIN_BIT_SHIFT)
49 0 : #define MAX_INSTRUCTION_TRACE_LENGTH_EXCEEDED ((21UL) << BUILTIN_BIT_SHIFT)
50 0 : #define BUILTIN_PROGRAMS_MUST_CONSUME_COMPUTE_UNITS ((22UL) << BUILTIN_BIT_SHIFT)
51 0 : #define INVALID_ACCOUNT_OWNER ((23UL) << BUILTIN_BIT_SHIFT)
52 0 : #define ARITHMETIC_OVERFLOW ((24UL) << BUILTIN_BIT_SHIFT)
53 0 : #define IMMUTABLE ((25UL) << BUILTIN_BIT_SHIFT)
54 0 : #define INCORRECT_AUTHORITY ((26UL) << BUILTIN_BIT_SHIFT)
55 :
56 : /* UpgradeableLoaderInstruction wire format (u32 discriminant).
57 :
58 : https://github.com/anza-xyz/agave/blob/v2.2.6/sdk/program/src/bpf_loader_upgradeable.rs */
59 :
60 0 : #define FD_BPF_INSTR_INITIALIZE_BUFFER (0U)
61 0 : #define FD_BPF_INSTR_WRITE (1U)
62 18 : #define FD_BPF_INSTR_DEPLOY_WITH_MAX_DATA_LEN (2U)
63 0 : #define FD_BPF_INSTR_UPGRADE (3U)
64 9 : #define FD_BPF_INSTR_SET_AUTHORITY (4U)
65 54 : #define FD_BPF_INSTR_CLOSE (5U)
66 9 : #define FD_BPF_INSTR_EXTEND_PROGRAM (6U)
67 24 : #define FD_BPF_INSTR_SET_AUTHORITY_CHECKED (7U)
68 24 : #define FD_BPF_INSTR_MIGRATE (8U)
69 0 : #define FD_BPF_INSTR_EXTEND_PROGRAM_CHECKED (9U)
70 :
71 : /* SIMD-0431: must extend by at least 10kb
72 : https://github.com/anza-xyz/solana-sdk/blob/loader-v3-interface%40v7.0.0/loader-v3-interface/src/instruction.rs#L18 */
73 0 : #define MINIMUM_EXTEND_PROGRAM_BYTES (10240UL)
74 :
75 : /* Per-variant payload structs.
76 :
77 : The `write` variant uses zero-copy for its `bytes` field: after a
78 : successful decode `bytes` points directly into the caller-owned
79 : instruction buffer, and the caller must keep that buffer alive for
80 : the lifetime of the decoded struct. */
81 :
82 : struct fd_bpf_instruction_write {
83 : uint offset;
84 : uchar const * bytes;
85 : ulong bytes_len;
86 : };
87 : typedef struct fd_bpf_instruction_write fd_bpf_instruction_write_t;
88 :
89 : struct fd_bpf_instruction_deploy_with_max_data_len {
90 : ulong max_data_len;
91 : };
92 : typedef struct fd_bpf_instruction_deploy_with_max_data_len fd_bpf_instruction_deploy_with_max_data_len_t;
93 :
94 : struct fd_bpf_instruction_extend_program {
95 : uint additional_bytes;
96 : };
97 : typedef struct fd_bpf_instruction_extend_program fd_bpf_instruction_extend_program_t;
98 :
99 : struct fd_bpf_instruction_extend_program_checked {
100 : uint additional_bytes;
101 : };
102 : typedef struct fd_bpf_instruction_extend_program_checked fd_bpf_instruction_extend_program_checked_t;
103 :
104 : union fd_bpf_instruction_inner {
105 : fd_bpf_instruction_write_t write;
106 : fd_bpf_instruction_deploy_with_max_data_len_t deploy_with_max_data_len;
107 : fd_bpf_instruction_extend_program_t extend_program;
108 : fd_bpf_instruction_extend_program_checked_t extend_program_checked;
109 : };
110 : typedef union fd_bpf_instruction_inner fd_bpf_instruction_inner_t;
111 :
112 : struct fd_bpf_instruction {
113 : uint discriminant;
114 : fd_bpf_instruction_inner_t inner;
115 : };
116 : typedef struct fd_bpf_instruction fd_bpf_instruction_t;
117 :
118 : /* UpgradeableLoaderState wire format (u32 discriminant).
119 :
120 : https://github.com/anza-xyz/agave/blob/v2.2.6/sdk/program/src/bpf_loader_upgradeable.rs */
121 :
122 81 : #define FD_BPF_STATE_UNINITIALIZED (0U)
123 96 : #define FD_BPF_STATE_BUFFER (1U)
124 606 : #define FD_BPF_STATE_PROGRAM (2U)
125 447 : #define FD_BPF_STATE_PROGRAM_DATA (3U)
126 :
127 : /* State struct field layout MUST be preserved: callers initialize and
128 : read these fields by name (e.g. `state.inner.buffer.has_authority_address`,
129 : `state.inner.program.programdata_address`, etc). */
130 :
131 : struct fd_bpf_state_buffer {
132 : fd_pubkey_t authority_address;
133 : uchar has_authority_address;
134 : };
135 : typedef struct fd_bpf_state_buffer fd_bpf_state_buffer_t;
136 :
137 : struct fd_bpf_state_program {
138 : fd_pubkey_t programdata_address;
139 : };
140 : typedef struct fd_bpf_state_program fd_bpf_state_program_t;
141 :
142 : struct fd_bpf_state_program_data {
143 : ulong slot;
144 : fd_pubkey_t upgrade_authority_address;
145 : uchar has_upgrade_authority_address;
146 : };
147 : typedef struct fd_bpf_state_program_data fd_bpf_state_program_data_t;
148 :
149 : union fd_bpf_state_inner {
150 : fd_bpf_state_buffer_t buffer;
151 : fd_bpf_state_program_t program;
152 : fd_bpf_state_program_data_t program_data;
153 : };
154 : typedef union fd_bpf_state_inner fd_bpf_state_inner_t;
155 :
156 : struct fd_bpf_state {
157 : uint discriminant;
158 : fd_bpf_state_inner_t inner;
159 : };
160 : typedef struct fd_bpf_state fd_bpf_state_t;
161 :
162 : /* fd_bpf_instruction_decode parses a bincode-encoded
163 : UpgradeableLoaderInstruction from [data, data+data_sz).
164 :
165 : Only bytes up to FD_TXN_MTU_V0 are parsed, the rest are discarded,
166 : matching Agave's limited_deserialize(data, PACKET_DATA_SIZE).
167 :
168 : Variable-length fields (`write.bytes`) point directly into `data`, so
169 : callers must keep that buffer alive. Trailing bytes beyond the parsed
170 : region are accepted (matches Agave's default `allow_trailing_bytes()`).
171 : Returns 0 on success, -1 on malformed input. */
172 :
173 : static inline int
174 : fd_bpf_instruction_decode( fd_bpf_instruction_t * out,
175 : uchar const * data,
176 27 : ulong data_sz ) {
177 27 : uchar const * _payload = data;
178 : /* limited_deserialize(data, PACKET_DATA_SIZE)
179 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/bpf_loader/src/lib.rs#L157 */
180 27 : ulong const _payload_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
181 27 : ulong _i = 0UL;
182 :
183 36 : # define CHECK( cond ) { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
184 36 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
185 36 : # define INC( n ) (_i += (ulong)(n))
186 27 : # define CURSOR (_payload+_i)
187 :
188 27 : CHECK_LEFT( 4UL );
189 27 : uint disc = FD_LOAD( uint, CURSOR ); INC( 4UL );
190 27 : out->discriminant = disc;
191 :
192 27 : switch( disc ) {
193 :
194 0 : case FD_BPF_INSTR_WRITE: {
195 0 : fd_bpf_instruction_write_t * w = &out->inner.write;
196 0 : CHECK_LEFT( 4UL ); w->offset = FD_LOAD( uint, CURSOR ); INC( 4UL );
197 0 : CHECK_LEFT( 8UL ); w->bytes_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
198 0 : CHECK_LEFT( w->bytes_len );
199 0 : w->bytes = w->bytes_len ? CURSOR : NULL;
200 0 : INC( w->bytes_len );
201 0 : return 0;
202 0 : }
203 :
204 6 : case FD_BPF_INSTR_DEPLOY_WITH_MAX_DATA_LEN: {
205 6 : fd_bpf_instruction_deploy_with_max_data_len_t * d = &out->inner.deploy_with_max_data_len;
206 6 : CHECK_LEFT( 8UL );
207 6 : d->max_data_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
208 6 : return 0;
209 6 : }
210 :
211 3 : case FD_BPF_INSTR_EXTEND_PROGRAM: {
212 3 : fd_bpf_instruction_extend_program_t * e = &out->inner.extend_program;
213 3 : CHECK_LEFT( 4UL );
214 3 : e->additional_bytes = FD_LOAD( uint, CURSOR ); INC( 4UL );
215 3 : return 0;
216 3 : }
217 :
218 0 : case FD_BPF_INSTR_EXTEND_PROGRAM_CHECKED: {
219 0 : fd_bpf_instruction_extend_program_checked_t * e = &out->inner.extend_program_checked;
220 0 : CHECK_LEFT( 4UL );
221 0 : e->additional_bytes = FD_LOAD( uint, CURSOR ); INC( 4UL );
222 0 : return 0;
223 0 : }
224 :
225 0 : case FD_BPF_INSTR_INITIALIZE_BUFFER:
226 0 : case FD_BPF_INSTR_UPGRADE:
227 3 : case FD_BPF_INSTR_SET_AUTHORITY:
228 18 : case FD_BPF_INSTR_CLOSE:
229 18 : case FD_BPF_INSTR_SET_AUTHORITY_CHECKED:
230 18 : case FD_BPF_INSTR_MIGRATE:
231 18 : return 0;
232 :
233 0 : default: return -1;
234 27 : }
235 :
236 27 : # undef CHECK
237 27 : # undef CHECK_LEFT
238 27 : # undef INC
239 27 : # undef CURSOR
240 27 : }
241 :
242 : /* fd_bpf_upgradeable_loader_program_instruction_encode serializes an
243 : UpgradeableLoaderInstruction into [buf, buf+bufsz). On success stores
244 : the number of bytes written to *out_sz and returns 0. Returns -1 on
245 : short buffer or unknown discriminant. */
246 :
247 : static inline int
248 : fd_bpf_instruction_encode( fd_bpf_instruction_t const * in,
249 : uchar * buf,
250 : ulong bufsz,
251 6 : ulong * out_sz ) {
252 6 : uchar * const _payload = buf;
253 6 : ulong const _payload_sz = bufsz;
254 6 : ulong _i = 0UL;
255 :
256 6 : # define CHECK_LEFT( n ) { if( FD_UNLIKELY( (n)>(_payload_sz-_i) ) ) { return -1; } }
257 6 : # define INC( n ) (_i += (ulong)(n))
258 6 : # define CURSOR (_payload+_i)
259 :
260 6 : CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->discriminant ); INC( 4UL );
261 :
262 6 : switch( in->discriminant ) {
263 :
264 0 : case FD_BPF_INSTR_WRITE: {
265 0 : fd_bpf_instruction_write_t const * w = &in->inner.write;
266 0 : CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, w->offset ); INC( 4UL );
267 0 : CHECK_LEFT( 8UL ); FD_STORE( ulong, CURSOR, w->bytes_len ); INC( 8UL );
268 0 : if( w->bytes_len ) {
269 0 : CHECK_LEFT( w->bytes_len );
270 0 : fd_memcpy( CURSOR, w->bytes, w->bytes_len );
271 0 : INC( w->bytes_len );
272 0 : }
273 0 : break;
274 0 : }
275 :
276 0 : case FD_BPF_INSTR_DEPLOY_WITH_MAX_DATA_LEN: {
277 0 : fd_bpf_instruction_deploy_with_max_data_len_t const * d = &in->inner.deploy_with_max_data_len;
278 0 : CHECK_LEFT( 8UL );
279 0 : FD_STORE( ulong, CURSOR, d->max_data_len ); INC( 8UL );
280 0 : break;
281 0 : }
282 :
283 0 : case FD_BPF_INSTR_EXTEND_PROGRAM: {
284 0 : fd_bpf_instruction_extend_program_t const * e = &in->inner.extend_program;
285 0 : CHECK_LEFT( 4UL );
286 0 : FD_STORE( uint, CURSOR, e->additional_bytes ); INC( 4UL );
287 0 : break;
288 0 : }
289 :
290 0 : case FD_BPF_INSTR_EXTEND_PROGRAM_CHECKED: {
291 0 : fd_bpf_instruction_extend_program_checked_t const * e = &in->inner.extend_program_checked;
292 0 : CHECK_LEFT( 4UL );
293 0 : FD_STORE( uint, CURSOR, e->additional_bytes ); INC( 4UL );
294 0 : break;
295 0 : }
296 :
297 0 : case FD_BPF_INSTR_INITIALIZE_BUFFER:
298 0 : case FD_BPF_INSTR_UPGRADE:
299 0 : case FD_BPF_INSTR_SET_AUTHORITY:
300 6 : case FD_BPF_INSTR_CLOSE:
301 6 : case FD_BPF_INSTR_SET_AUTHORITY_CHECKED:
302 6 : case FD_BPF_INSTR_MIGRATE:
303 6 : break;
304 :
305 0 : default: return -1;
306 6 : }
307 :
308 6 : *out_sz = _i;
309 :
310 6 : # undef CHECK_LEFT
311 6 : # undef INC
312 6 : # undef CURSOR
313 :
314 6 : return 0;
315 6 : }
316 :
317 : /* fd_bpf_state_decode parses a bincode-encoded
318 : UpgradeableLoaderState from [data, data+data_sz). The output struct
319 : has no variable-length fields, so the decoder performs a fixed-size
320 : copy and does not retain any pointer into `data`. Trailing bytes
321 : beyond the parsed region are accepted (matches Agave's top-level
322 : `bincode::deserialize` which uses `allow_trailing_bytes()`). Returns
323 : 0 on success, -1 on malformed input. */
324 :
325 : static inline int
326 : fd_bpf_state_decode( fd_bpf_state_t * out,
327 : uchar const * data,
328 507 : ulong data_sz ) {
329 507 : uchar const * _payload = data;
330 507 : ulong const _payload_sz = data_sz;
331 507 : ulong _i = 0UL;
332 :
333 1452 : # define CHECK( cond ) { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
334 1269 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
335 1269 : # define INC( n ) (_i += (ulong)(n))
336 615 : # define CURSOR (_payload+_i)
337 :
338 507 : CHECK_LEFT( 4UL );
339 507 : uint disc = FD_LOAD( uint, CURSOR ); INC( 4UL );
340 507 : out->discriminant = disc;
341 :
342 507 : switch( disc ) {
343 :
344 39 : case FD_BPF_STATE_UNINITIALIZED:
345 39 : return 0;
346 :
347 36 : case FD_BPF_STATE_BUFFER: {
348 36 : fd_bpf_state_buffer_t * b = &out->inner.buffer;
349 36 : CHECK_LEFT( 1UL ); uchar tag = *CURSOR; INC( 1UL );
350 36 : CHECK( tag<=1 );
351 36 : b->has_authority_address = tag;
352 36 : if( tag ) {
353 27 : CHECK_LEFT( 32UL );
354 27 : fd_memcpy( b->authority_address.key, CURSOR, 32UL ); INC( 32UL );
355 27 : } else {
356 9 : fd_memset( b->authority_address.key, 0, 32UL );
357 9 : }
358 36 : return 0;
359 36 : }
360 :
361 282 : case FD_BPF_STATE_PROGRAM: {
362 282 : fd_bpf_state_program_t * p = &out->inner.program;
363 282 : CHECK_LEFT( 32UL );
364 282 : fd_memcpy( p->programdata_address.key, CURSOR, 32UL ); INC( 32UL );
365 282 : return 0;
366 282 : }
367 :
368 147 : case FD_BPF_STATE_PROGRAM_DATA: {
369 147 : fd_bpf_state_program_data_t * pd = &out->inner.program_data;
370 147 : CHECK_LEFT( 8UL ); pd->slot = FD_LOAD( ulong, CURSOR ); INC( 8UL );
371 147 : CHECK_LEFT( 1UL ); uchar tag = *CURSOR; INC( 1UL );
372 147 : CHECK( tag<=1 );
373 147 : pd->has_upgrade_authority_address = tag;
374 147 : if( tag ) {
375 123 : CHECK_LEFT( 32UL );
376 123 : fd_memcpy( pd->upgrade_authority_address.key, CURSOR, 32UL ); INC( 32UL );
377 123 : } else {
378 24 : fd_memset( pd->upgrade_authority_address.key, 0, 32UL );
379 24 : }
380 147 : return 0;
381 147 : }
382 :
383 3 : default: return -1;
384 507 : }
385 :
386 507 : # undef CHECK
387 507 : # undef CHECK_LEFT
388 507 : # undef INC
389 507 : # undef CURSOR
390 507 : }
391 :
392 : /* fd_bpf_state_encode serializes an UpgradeableLoaderState into
393 : [buf, buf+bufsz). On success stores the number of bytes written to
394 : *out_sz and returns 0. Returns -1 on short buffer or unknown
395 : discriminant. */
396 :
397 : static inline int
398 : fd_bpf_state_encode( fd_bpf_state_t const * in,
399 : uchar * buf,
400 : ulong bufsz,
401 243 : ulong * out_sz ) {
402 243 : uchar * const _payload = buf;
403 243 : ulong const _payload_sz = bufsz;
404 243 : ulong _i = 0UL;
405 :
406 747 : # define CHECK_LEFT( n ) { if( FD_UNLIKELY( (n)>(_payload_sz-_i) ) ) { return -1; } }
407 747 : # define INC( n ) (_i += (ulong)(n))
408 375 : # define CURSOR (_payload+_i)
409 :
410 243 : CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->discriminant ); INC( 4UL );
411 :
412 243 : switch( in->discriminant ) {
413 :
414 9 : case FD_BPF_STATE_UNINITIALIZED:
415 9 : break;
416 :
417 21 : case FD_BPF_STATE_BUFFER: {
418 21 : fd_bpf_state_buffer_t const * b = &in->inner.buffer;
419 21 : CHECK_LEFT( 1UL ); *CURSOR = (uchar)( !!b->has_authority_address ); INC( 1UL );
420 21 : if( b->has_authority_address ) {
421 15 : CHECK_LEFT( 32UL );
422 15 : fd_memcpy( CURSOR, b->authority_address.key, 32UL ); INC( 32UL );
423 15 : }
424 21 : break;
425 21 : }
426 :
427 84 : case FD_BPF_STATE_PROGRAM: {
428 84 : fd_bpf_state_program_t const * p = &in->inner.program;
429 84 : CHECK_LEFT( 32UL );
430 84 : fd_memcpy( CURSOR, p->programdata_address.key, 32UL ); INC( 32UL );
431 84 : break;
432 84 : }
433 :
434 129 : case FD_BPF_STATE_PROGRAM_DATA: {
435 129 : fd_bpf_state_program_data_t const * pd = &in->inner.program_data;
436 129 : CHECK_LEFT( 8UL ); FD_STORE( ulong, CURSOR, pd->slot ); INC( 8UL );
437 129 : CHECK_LEFT( 1UL ); *CURSOR = (uchar)( !!pd->has_upgrade_authority_address ); INC( 1UL );
438 129 : if( pd->has_upgrade_authority_address ) {
439 126 : CHECK_LEFT( 32UL );
440 126 : fd_memcpy( CURSOR, pd->upgrade_authority_address.key, 32UL ); INC( 32UL );
441 126 : }
442 129 : break;
443 129 : }
444 :
445 129 : default: return -1;
446 243 : }
447 :
448 243 : *out_sz = _i;
449 :
450 243 : # undef CHECK_LEFT
451 243 : # undef INC
452 243 : # undef CURSOR
453 :
454 243 : return 0;
455 243 : }
456 :
457 : /* fd_bpf_state_size returns the bincode-exact wire size for
458 : encoding. Returns 0 for unknown discriminants. */
459 :
460 : static inline ulong
461 30 : fd_bpf_state_size( fd_bpf_state_t const * in ) {
462 30 : switch( in->discriminant ) {
463 9 : case FD_BPF_STATE_UNINITIALIZED: return 4UL;
464 0 : case FD_BPF_STATE_BUFFER: return 4UL + 1UL + (in->inner.buffer.has_authority_address ? 32UL : 0UL);
465 9 : case FD_BPF_STATE_PROGRAM: return 4UL + 32UL;
466 12 : case FD_BPF_STATE_PROGRAM_DATA: return 4UL + 8UL + 1UL + (in->inner.program_data.has_upgrade_authority_address ? 32UL : 0UL);
467 0 : default: return 0UL;
468 30 : }
469 30 : }
470 :
471 : FD_PROTOTYPES_BEGIN
472 :
473 : /* Mirrors solana_sdk::transaction_context::BorrowedAccount::get_state()
474 : https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L965-L969 */
475 :
476 : int
477 : fd_bpf_loader_program_get_state( fd_acc_t const * acc,
478 : fd_bpf_state_t * state );
479 :
480 : int
481 : fd_bpf_loader_program_get_state2( uchar const * data,
482 : ulong data_len,
483 : fd_bpf_state_t * state );
484 :
485 : int
486 : fd_deploy_program( fd_exec_instr_ctx_t * instr_ctx,
487 : uchar const * programdata,
488 : ulong programdata_size,
489 : int disable_sbpf_v0_v1_v2_deployment );
490 :
491 : /* SIMD-0500 finalize gate. Returns
492 : FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA when `feature_active` is
493 : non-zero and the ELF embedded in `programdata` parses as
494 : SBPFv0/v1/v2; FD_EXECUTOR_INSTR_SUCCESS otherwise. */
495 : int
496 : fd_bpf_loader_finalize_v3_check( int feature_active,
497 : uchar const * programdata,
498 : ulong programdata_len );
499 :
500 : int
501 : fd_bpf_execute( fd_exec_instr_ctx_t * instr_ctx,
502 : fd_progcache_rec_t const * program,
503 : uchar is_deprecated );
504 :
505 : int
506 : fd_bpf_loader_program_execute( fd_exec_instr_ctx_t * instr_ctx );
507 :
508 : FD_PROTOTYPES_END
509 :
510 : #endif /* HEADER_fd_src_flamenco_runtime_program_fd_bpf_loader_program_h */
|