Line data Source code
1 : #ifndef HEADER_fd_src_ballet_txn_fd_txn_h
2 : #define HEADER_fd_src_ballet_txn_fd_txn_h
3 :
4 : /* The main structure this header defines is fd_txn_t, which represents a
5 : Solana transaction. A transaction, like a SQL database transaction, is the
6 : unit of execution atomicity in Solana, i.e. intermediate state is never
7 : visible to other transactions, and a failure at any point in the transaction
8 : causes the entire transaction to be rolled back (other than charging the
9 : transaction fee).
10 :
11 : A transaction primarily consists of a list of instructions to execute in
12 : sequence. The struct fd_txn_instr_t describes one instruction. An instruction
13 : specifies the invocation of a smart contract with some specified data and
14 : accounts. The name 'instruction' was a poor choice, (since on-chain code is
15 : composed of eBPF instructions and using the same word to refer to very
16 : different concepts is confusing) but it's too late to change. Thinking of a
17 : transaction-level instruction as a 'command' might be more useful.
18 :
19 : The other major component of a transaction is a list of account addresses.
20 : The address of any account that is referenced by any instruction in the
21 : transaction must appear in the list. The address of any signer (including
22 : the fee payer) must appear in the list. An account address is sometimes
23 : called a pubkey since it has the same format as one, though it is not always
24 : a public key strictly speaking (i.e. a corresponding private key may not
25 : exist). Each account address in the list has associated permissions flags:
26 : signer/not signer and writable/readonly. All 4 combinations are possible.
27 : These flags declare the transaction's intention in accessing the account,
28 : similar to the `mode` field of fopen( ). */
29 :
30 : #include "../fd_ballet_base.h"
31 :
32 : #include "../ed25519/fd_ed25519.h"
33 :
34 : /* FD_TXN_VLEGACY: the initial, pre-V0 transaction format. */
35 30975615 : #define FD_TXN_VLEGACY ((uchar)0xFF)
36 : /* FD_TXN_V0: The second transaction format. Includes a version number and
37 : potentially some address lookup tables */
38 391035 : #define FD_TXN_V0 ((uchar)0x00)
39 :
40 : /* FD_TXN_SIGNATURE_SZ: The size (in bytes) of an Ed25519 signature. */
41 166106675 : #define FD_TXN_SIGNATURE_SZ (64UL)
42 : /* FD_TXN_PUBKEY_SZ: The size (in bytes) of an Ed25519 public key. */
43 : #define FD_TXN_PUBKEY_SZ (32UL)
44 : /* FD_TXN_ACCT_ADDR_SZ: The size (in bytes) of a Solana account address.
45 : Account addresses are sometimes Ed25519 public keys, but they can also be
46 : the output of a SHA256 hash (program derived addresses and seeded accounts),
47 : or just hardcoded values (sysvars accounts). It's important that all types
48 : of account addresses have this same size. */
49 5460543287 : #define FD_TXN_ACCT_ADDR_SZ (32UL)
50 : /* FD_TXN_BLOCKHASH_SZ: The size (in bytes) of a blockhash. A blockhash is a
51 : SHA256 hash, giving a size of 256 bits = 32 bytes. */
52 61371837 : #define FD_TXN_BLOCKHASH_SZ (32UL)
53 :
54 :
55 : /* FD_TXN_SIG_MAX: The (inclusive) maximum number of signatures a transaction
56 : can have. Note: for the current MTU size of 1232 B, the maximum that a
57 : valid transaction can have is 12 signatures. The most I've seen in practice
58 : is about 7.
59 :
60 : FD_TXN_ACTUAL_SIG_MAX: used to allocate arrays of signatures, pubkeys, etc.
61 :
62 : From the spec: "The Solana runtime verifies that the number of signatures
63 : [stored as a compact-u16] matches the number in the first 8 bits of the
64 : message header."
65 : Thus this value must live in the range where compact-u16 and uint8
66 : representations are identical, hence a max of 127. */
67 221118 : #define FD_TXN_SIG_MAX (127UL)
68 402 : #define FD_TXN_ACTUAL_SIG_MAX (12UL)
69 :
70 : /* FD_TXN_ACCT_ADDR_MAX: The (inclusive) maximum number of account addresses
71 : that a transaction can have. The spec only guarantees <= 256, but the
72 : current MTU of 1232 B restricts this to 35 account addresses. An artificial
73 : limit of 64 is currently in place, but this is being changed to 128 in the
74 : near future (https://github.com/solana-labs/solana/issues/27241), so we'll
75 : use 128. */
76 : /* https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/sdk/program/src/message/versions/v0/mod.rs#L139 */
77 10278 : #define FD_TXN_ACCT_ADDR_MAX (128UL)
78 :
79 : /* FD_TXN_ADDR_TABLE_LOOKUP_MAX: The (inclusive) maximum number of address
80 : tables that this transaction references. The spec is pretty sloppy about
81 : the maximum number allowed. Since there's a maximum of 128 total accounts
82 : (including the fee payer) that the transaction can reference, if you have
83 : more than 127 table lookups, then you must have some from which you are not
84 : using any account. Realistically, the current MTU of 1232 B restricts this
85 : to 33. FIXME: We should petition to limit this to approx 8. */
86 25155 : #define FD_TXN_ADDR_TABLE_LOOKUP_MAX (127UL)
87 :
88 : /* FD_TXN_INSTR_MAX: The (inclusive) maximum number of instructions a transaction
89 : can have. As of Solana 1.15.0, this is limited to 64. */
90 198 : #define FD_TXN_INSTR_MAX (64UL)
91 :
92 :
93 : /* FD_TXN_MAX_SZ: The maximum amount of memory (in bytes) that a fd_txn can
94 : take up, including the instruction array and any address tables. The
95 : worst-case transaction is a V0 transaction with only two account
96 : addresses (a program and a fee payer), and tons of empty instructions (no
97 : accounts, no data) and as many address table lookups loading a single
98 : account as possible. */
99 21 : #define FD_TXN_MAX_SZ (852UL)
100 :
101 :
102 : /* FD_TXN_MTU: The maximum size (in bytes, inclusive) of a serialized
103 : transaction. */
104 435957 : #define FD_TXN_MTU (1232UL)
105 :
106 : /* FD_TXN_MIN_SERIALIZED_SZ: The minimum size (in bytes) of a serialized
107 : transaction, using fd_txn_parse() verification rules. */
108 408870 : #define FD_TXN_MIN_SERIALIZED_SZ (134UL)
109 :
110 : /* BEGIN Agave limits */
111 :
112 : /* "Maximum number of accounts that a transaction may lock.
113 : 128 was chosen because it is the minimum number of accounts
114 : needed for the Neon EVM implementation."
115 : https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/sdk/src/transaction/sanitized.rs#L30 */
116 825093 : #define MAX_TX_ACCOUNT_LOCKS (128UL)
117 : /* In the FD runtime, we've sized things assuming up to
118 : MAX_TX_ACCOUNT_LOCKS accounts per transaction. We rely on the txn
119 : parser to enforce this limit, up till the point of
120 : validate_account_locks(). If the txn parser bumps the account limit,
121 : then we might overflow in the runtime. */
122 : FD_STATIC_ASSERT( MAX_TX_ACCOUNT_LOCKS==FD_TXN_ACCT_ADDR_MAX, num_accounts_per_txn );
123 :
124 : /* END Agave limits */
125 :
126 :
127 : /* A Solana transaction instruction, i.e. one command or step to execute in a
128 : transaction.
129 :
130 : An instruction tells the runtime to execute one on-chain program (smart
131 : contract) with some arguments (think argc, argv). The arguments come in the
132 : form of binary data and/or accounts, each of which is variable-sized and
133 : optional.
134 :
135 : Note that instructions specify accounts by giving an index into the
136 : transaction-level list of account addresses. This means there are
137 : essentially two layers of indirection: a 1 B index to a 32 B address which
138 : specifies an account. */
139 : struct fd_txn_instr {
140 : /* program_id: The on-chain program that this instruction invokes,
141 : represented as the index of the program's account address in the
142 : containing transaction's list of account addresses. */
143 : uchar program_id;
144 : uchar _padding_reserved_1; /* explicitly declare what the compiler would
145 : insert anyways */
146 :
147 : /* acct_cnt: The number of accounts this instruction references.
148 : N.B. It is possible to pass > 256 accounts to an instruction, but not more
149 : than 256 unique accounts. */
150 : ushort acct_cnt;
151 :
152 : /* data_sz: The size (in bytes) of the data passed to this instruction. The
153 : data itself is included in the transaction, so is limited to the overall
154 : transaction size. */
155 : ushort data_sz;
156 :
157 : /* acct_off: The offset (relative to the start of the transaction) in bytes
158 : where the account address index array starts. This array has size
159 : acct_cnt.
160 :
161 : Specifically, if uchar const * payload is a pointer to the first byte of
162 : the transaction data in the packet, then the array (payload+acct_off)[i]
163 : for i in [0, acct_cnt) gives all of the accounts passed to this
164 : instruction. As with the program_id, these accounts are represented as
165 : indices into the transaction's list of account addresses.
166 : */
167 : ushort acct_off;
168 :
169 : /* data_off: The offset (relative to the start of the transaction) in bytes
170 : where the instruction data array starts. This array has size data_sz.
171 :
172 : Specifically, if uchar const * payload is a pointer to the first byte of
173 : the transaction data in the packet, then the array (payload+data_off)[i]
174 : for i in [0, data_sz) gives the binary data passed to this instruction. */
175 : ushort data_off;
176 : };
177 :
178 : typedef struct fd_txn_instr fd_txn_instr_t;
179 :
180 :
181 : /* fd_txn_t: A Solana transaction. As explained above, a transaction is mostly
182 : a list of instructions, but there are a few other major components:
183 : - a list of account addresses,
184 : - the hash of a recent block (used as a nonce and TTL), and
185 : - potentially (if it's a V2 transaction) some address lookup tables. */
186 : struct fd_txn {
187 : /* transaction_version: The version number of this transaction. Currently
188 : must be one of { FD_TXN_VLEGACY, FD_TXN_V0 }. */
189 : uchar transaction_version;
190 :
191 : /* signature_cnt: The number of signatures in this transaction. signature_cnt
192 : in [1, FD_TXN_SIG_MAX]. */
193 : uchar signature_cnt;
194 :
195 : /* signature_off: The offset (relative to the start of the transaction) in
196 : bytes where the signatures start.
197 :
198 : Specifically, if uchar const * payload is a pointer to the first byte of
199 : the transaction data in the packet, then signature i starts at
200 : (payload+signature_off)[ FD_TXN_SIGNATURE_SZ*i ] for i in
201 : [0, signature_cnt).
202 :
203 : Note that signature_off is always 1 in current transaction versions. */
204 : ushort signature_off;
205 :
206 : /* message_off: The offset (relative to the start of the transaction) in
207 : bytes where the 'message' starts.
208 :
209 : The message, which is the part of the packet covered by the signatures,
210 : spans from this offset to the end of the packet. */
211 : ushort message_off;
212 :
213 : /* readonly_signed_cnt: Of the signature_cnt signatures, readonly_signed_cnt
214 : of them are read only. Since there must be a fee payer,
215 : readonly_signed_cnt in [0, signature_cnt) */
216 : uchar readonly_signed_cnt;
217 :
218 : /* readonly_unsigned_cnt: Of the account addresses that don't have an
219 : accompanying signature, readonly_unsigned_cnt of them are read only.
220 : readonly_unsigned_cnt in [0, acct_addr_cnt-signature_cnt]. Excludes any
221 : accounts from address table lookups. */
222 : uchar readonly_unsigned_cnt;
223 :
224 : /* acct_addr_cnt: The number of account addresses in this transaction.
225 : acct_addr_cnt in [1, FD_TXN_ACCT_ADDR_MAX]. Excludes any accounts from
226 : address table lookups. */
227 : ushort acct_addr_cnt;
228 :
229 : /* acct_addr_off: The offset (relative to the start of the transaction) in
230 : bytes where the account addresses start.
231 :
232 : Specifically, if uchar const * payload is a pointer to the first byte of
233 : the transaction data in the packet, then the array
234 : (payload+acct_addr_off)[ FD_TXN_ACCT_ADDR_SZ*i ] for i in [0, account_cnt)
235 : gives all of the account addresses in this transaction. Since
236 : (payload+acct_addr_off) points inside the packet, it should be treated as
237 : pointing to unaligned data.
238 :
239 : The order of these addresses is important, because it determines the
240 : "permission flags" for the account in this transaction.
241 : Accounts ordered:
242 : Index Range | Signer? | Writeable?
243 : ---------------------------------------------------------------------------------|--------------|-------------
244 : [0, signature_cnt - readonly_signed_cnt) | signer | writable
245 : [signature_cnt - readonly_signed_cnt, signature_cnt) | signer | readonly
246 : [signature_cnt, acct_addr_cnt - readonly_unsigned_cnt) | not signer | writable
247 : [acct_addr_cnt - readonly_unsigned_cnt, acct_addr_cnt) | not signer | readonly
248 : */
249 : ushort acct_addr_off;
250 :
251 : /* recent_blockhash_off: The offset (relative to the start of the
252 : transaction) in bytes where the recent blockhash starts.
253 :
254 : Specifically, if uchar const * payload is a pointer to the first byte of
255 : the transaction data in the packet, then (payload+recent_blockhash_off) is
256 : a pointer to the blockhash. Since the resulting pointer points inside the
257 : packet, it should be treated as pointing to unaligned data. In practice,
258 : recent_blockhash_off is 5 or 6 (mod 32). */
259 : ushort recent_blockhash_off;
260 :
261 : /* addr_table_lookup_cnt: The number of address lookup tables this
262 : transaction contains. Must be 0 if transaction_version==FD_TXN_VLEGACY.
263 : addr_table_lookup_cnt in [0, FD_TXN_ADDR_TABLE_LOOKUP_MAX]. */
264 : uchar addr_table_lookup_cnt;
265 :
266 : /* addr_table_adtl_writable_cnt: The total number of writable account
267 : addresses across all of the address table lookups.
268 : addr_table_adtl_writable_cnt in [0, addr_table_adtl_cnt]. */
269 : uchar addr_table_adtl_writable_cnt;
270 :
271 : /* addr_table_adtl_cnt: The total number of account addresses summed across
272 : all the address lookup tables. addr_table_adtl_cnt in
273 : [0, FD_TXN_ADDT_ADDR_MAX - acct_addr_cnt]. Since acct_addr_cnt > 0,
274 : addr_table_adtl_cnt < 256. */
275 : uchar addr_table_adtl_cnt;
276 : uchar _padding_reserved_1; /* explicit padding the compiler would have
277 : inserted anyways */
278 :
279 : /* From the address table lookups, we can add the following to the above table
280 : Index Range | Signer? | Writeable?
281 : -----------------------------------------------------------------------------------------------|--------------|-------------
282 : ...
283 : [acct_addr_cnt, acct_addr_cnt + addr_table_adtl_writable_cnt) | not signer | writable
284 : [acct_addr_cnt + addr_table_adtl_writable_cnt, acct_addr_cnt + addr_table_adtl_cnt) | not signer | readonly
285 : */
286 :
287 : /* instr_cnt: The number of instructions in this transaction.
288 : instr_cnt in [0, FD_TXN_INSTR_MAX]. */
289 : ushort instr_cnt;
290 :
291 : /* instr: The array of instructions in this transaction. It's a "flexible array
292 : member" since C does not allow the pretty typical 0-len array at the end
293 : of the struct trick.
294 : Indexed [0, instr_cnt). */
295 : fd_txn_instr_t instr[ ];
296 :
297 : /* Logically, there's another field here:
298 : address_tables: The address tables this transaction imports and which
299 : accounts from them are selected for inclusion in this transaction's
300 : overall list of accounts. Indexed [0, addr_table_lookup_cnt).
301 : fd_txn_acct_addr_lut_t address_tables[ ];
302 : To access it, call fd_txn_get_address_tables( ). */
303 :
304 : };
305 :
306 : typedef struct fd_txn fd_txn_t;
307 :
308 : /* fd_txn_acct_addr_lut: An on-chain address lookup table. Solana added this to
309 : the Transaction v2 spec in order to allow a transaction to reference more
310 : accounts. This struct specifies which account addresses from an on-chain
311 : list should be selected to include in the list of account addresses
312 : available to instructions in this transaction */
313 : struct fd_txn_acct_addr_lut {
314 : /* addr_off: The offset (relative to the start of the transaction) in bytes
315 : where the address of the account containing the list of to load is stored.
316 :
317 : Specifically, if uchar const * payload is a pointer to the first byte of
318 : the transaction data in the packet, then
319 : (fd_txn_acct_addr_t*)(payload+addr_off) is a pointer to the account
320 : address. Since (payload+acct_addr_off) points inside the packet, it
321 : should be treated as pointing to unaligned data. */
322 : ushort addr_off;
323 :
324 : /* writable_cnt: The number of account addresses this LUT selects as writable
325 : from the on-chain list. */
326 : uchar writable_cnt;
327 : /* readonly_cnt: The number of account addresses this LUT selects as read
328 : only from the on-chain list. */
329 : uchar readonly_cnt;
330 :
331 : /* writable_off: The offset (relative to the start of the transaction) in
332 : bytes where the writable account indices begins.
333 :
334 : Specifically, if uchar const * payload is a pointer to the first byte of
335 : the transaction data in the packet, then (payload+writable_off)[i] for i
336 : in [0, writable_cnt) gives the indices into the on-chain list that are
337 : selected for inclusion in this transaction's list of account addresses as
338 : writable accounts. */
339 : ushort writable_off;
340 :
341 : /* readonly_off: The offset (relative to the start of the transaction) in
342 : bytes where the read only account indices begins.
343 :
344 : Specifically, if uchar const * payload is a pointer to the first byte of
345 : the transaction data in the packet, then (payload+readonly_off)[i] for i
346 : in [0, readonly_cnt) gives the indices into the on-chain list that are
347 : selected for inclusion in this transaction's list of account addresses as
348 : read only accounts. */
349 : ushort readonly_off;
350 : };
351 :
352 : typedef struct fd_txn_acct_addr_lut fd_txn_acct_addr_lut_t;
353 :
354 87783 : #define FD_TXN_PARSE_COUNTERS_RING_SZ (32UL)
355 :
356 : /* Counters for collecting some metrics about the outcome of parsing
357 : transactions */
358 : struct fd_txn_parse_counters {
359 : /* success_cnt: the number of times a transaction parsed successfully */
360 : ulong success_cnt;
361 : /* failure_cnt: the number of times a transaction was ill-formed and failed
362 : to parse for any reason */
363 : ulong failure_cnt;
364 : /* failure_ring: some information about the causes of recent transaction
365 : parsing failures. Specifically, the line of code which detected that the
366 : ith malformed transaction was malformed maps to
367 : failure_ring[ i%FD_TXN_PARSE_COUNTERS_RING_SZ ] (where i starts at 0), and the
368 : last instance mapping to each element of the array is the one that is
369 : actually present. If fewer than FD_TXN_PARSE_COUNTERS_RING_SZ failures have
370 : occurred, the contents of some entries in this array are undefined. */
371 : ulong failure_ring[ FD_TXN_PARSE_COUNTERS_RING_SZ ];
372 : };
373 : typedef struct fd_txn_parse_counters fd_txn_parse_counters_t;
374 :
375 : FD_PROTOTYPES_BEGIN
376 : /* fd_txn_get_address_tables: Returns the array of address tables in this
377 : transaction. This depends on the value of txn->instr_cnt being correct. The
378 : lifetime of the returned pointer is the same as the fd_txn_t pointer passed
379 : as an argument, so it's not necessary to free the returned pointer
380 : separately. Treat it as if this function returned a pointer to a member of
381 : the struct. Suppose x=fd_txn_get_address_tables( txn ), then x[ i ] is valid
382 : for i in [0, txn->addr_table_lookup_cnt ). */
383 : static inline fd_txn_acct_addr_lut_t *
384 61325043 : fd_txn_get_address_tables( fd_txn_t * txn ) {
385 61325043 : return (fd_txn_acct_addr_lut_t *)(txn->instr + txn->instr_cnt);
386 61325043 : }
387 :
388 : static inline fd_txn_acct_addr_lut_t const *
389 12243 : fd_txn_get_address_tables_const( fd_txn_t const * txn ) {
390 12243 : return (fd_txn_acct_addr_lut_t const *)(txn->instr + txn->instr_cnt);
391 12243 : }
392 :
393 : /* fd_acct_addr_t: An Solana account address, which may be an Ed25519
394 : public key, a SHA256 hash from a program derived address, a hardcoded
395 : sysvar, etc. This type does not imply any alignment. */
396 : union fd_acct_addr {
397 : uchar b[FD_TXN_ACCT_ADDR_SZ];
398 : };
399 : typedef union fd_acct_addr fd_acct_addr_t;
400 :
401 : /* fd_txn_get_{signatures, acct_addrs}: Returns the array of Ed25519
402 : signatures or account addresses (commonly, yet imprecisely called
403 : pubkeys), respectively, in `payload`, the serialization of the
404 : transaction described by `txn`. The number of signatures is seen in
405 : `txn->signature_cnt` and the number of account addresses is in
406 : `txn->acct_addr_cnt`.
407 :
408 : The lifetime of the returned signature is the lifetime of `payload`.
409 : Expect the returned pointer to point to memory with no particular
410 : alignment. U.B. If `payload` and `txn` were not arguments to a valid
411 : `fd_txn_parse` call or if either was modified after the parse call.
412 : */
413 : static inline fd_ed25519_sig_t const *
414 : fd_txn_get_signatures( fd_txn_t const * txn,
415 40717008 : void const * payload ) {
416 40717008 : return (fd_ed25519_sig_t const *)((ulong)payload + (ulong)txn->signature_off);
417 40717008 : }
418 :
419 : static inline fd_acct_addr_t const *
420 : fd_txn_get_acct_addrs( fd_txn_t const * txn,
421 40804657 : void const * payload ) {
422 40804657 : return (fd_acct_addr_t const *)((ulong)payload + (ulong)txn->acct_addr_off);
423 40804657 : }
424 :
425 : static inline uchar const *
426 : fd_txn_get_recent_blockhash( fd_txn_t const * txn,
427 0 : void const * payload ) {
428 0 : return (uchar const *)((ulong)payload + (ulong)txn->recent_blockhash_off);
429 0 : }
430 :
431 : static inline uchar const *
432 : fd_txn_get_instr_accts( fd_txn_instr_t const * instr,
433 13038 : void const * payload ) {
434 13038 : return (uchar const *)((ulong)payload + (ulong)instr->acct_off);
435 13038 : }
436 :
437 : static inline uchar const *
438 : fd_txn_get_instr_data( fd_txn_instr_t const * instr,
439 27048 : void const * payload ) {
440 27048 : return (uchar const *)((ulong)payload + (ulong)instr->data_off);
441 27048 : }
442 :
443 : /*
444 : * 1. has 1 or 2 signatures
445 : * 2. is legacy message
446 : * 3. has only one instruction
447 : * 4. which must be a Vote instruction
448 : */
449 : static inline int
450 : fd_txn_is_simple_vote_transaction( fd_txn_t const * txn,
451 : void const * payload,
452 0 : uchar const vote_program_id[ static 32 ] ) {
453 0 : fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
454 :
455 0 : ulong instr_cnt = txn->instr_cnt;
456 0 : ulong vote_instr_cnt = 0UL;
457 0 : for( ulong i=0UL; i<txn->instr_cnt; i++ ) {
458 0 : ulong prog_id_idx = (ulong)txn->instr[i].program_id;
459 0 : fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
460 0 : vote_instr_cnt += (ulong)(0 == memcmp(prog_id->b, vote_program_id, 32UL) );
461 0 : }
462 0 : return (vote_instr_cnt==1UL) && (instr_cnt==1UL) && (txn->transaction_version==FD_TXN_VLEGACY) && (txn->signature_cnt<3UL);
463 0 : }
464 :
465 : /* fd_txn_align returns the alignment in bytes required of a region of
466 : memory to be used as a fd_txn_t. It is the same as
467 : alignof(fd_txn_t). */
468 : static inline ulong
469 12741 : fd_txn_align( void ) {
470 12741 : return alignof(fd_txn_t);
471 12741 : }
472 :
473 : /* fd_txn_footprint: Returns the total size of txn, including the
474 : instructions and the address tables (if any). */
475 : static inline ulong
476 : fd_txn_footprint( ulong instr_cnt,
477 88069347 : ulong addr_table_lookup_cnt ) {
478 88069347 : return sizeof(fd_txn_t) + instr_cnt*sizeof(fd_txn_instr_t) + addr_table_lookup_cnt*sizeof(fd_txn_acct_addr_lut_t);
479 88069347 : }
480 :
481 :
482 : /* Each account address in a transaction has 3 independent binary
483 : properties:
484 : - readonly/writable: this is enforced in the runtime, but a
485 : transaction fails if it tries to modify the contents of an
486 : account it marks as readonly
487 : - signer/nonsigner: the sigverify tile ensures that the transaction
488 : has been validly signed by the key associated to each account
489 : address marked as a signer
490 : - immediate/address lookup table: account addresses can come from
491 : the transaction itself ("immediate"), which is the only option
492 : for legacy transactions, or from an address lookup table
493 :
494 : For example, the fee payer must be writable, a signer, and immediate.
495 :
496 : From these properties, we can make categories of account addresses
497 : for counting and iterating over account addresses. Since these
498 : properties can be set independently, it would seem to give us 2*2*2=8
499 : categories of accounts based on the properties, but account addresses
500 : that come from an address lookup table cannot be signers, giving 6
501 : raw categories instead of 8.
502 :
503 : The individual types of accounts are defined as bitflags so that
504 : combination categories can be created easily, e.g. all readonly
505 : accounts or all signers. */
506 :
507 : /* Signer? Writable? Source? */
508 166927890 : #define FD_TXN_ACCT_CAT_WRITABLE_SIGNER 0x01 /* Yes Yes imm */
509 166927890 : #define FD_TXN_ACCT_CAT_READONLY_SIGNER 0x02 /* Yes No imm */
510 166981443 : #define FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM 0x04 /* No Yes imm */
511 166981443 : #define FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM 0x08 /* No No imm */
512 166927890 : #define FD_TXN_ACCT_CAT_WRITABLE_ALT 0x10 /* No Yes lookup */
513 166927890 : #define FD_TXN_ACCT_CAT_READONLY_ALT 0x20 /* No No lookup */
514 :
515 : /* Define some groupings for convenience. In the
516 : table below, "Any" means "don't care" */
517 67374540 : #define FD_TXN_ACCT_CAT_WRITABLE 0x15 /* Any Yes Any */
518 40222566 : #define FD_TXN_ACCT_CAT_READONLY 0x2A /* Any No Any */
519 13572945 : #define FD_TXN_ACCT_CAT_SIGNER 0x03 /* Yes Any Any/imm*/
520 384 : #define FD_TXN_ACCT_CAT_NONSIGNER 0x3C /* No Any Any */
521 40737724 : #define FD_TXN_ACCT_CAT_IMM 0x0F /* Any Any imm */
522 13572945 : #define FD_TXN_ACCT_CAT_ALT 0x30 /* No Any lookup */
523 384 : #define FD_TXN_ACCT_CAT_NONE 0x00 /* --- Empty set --- */
524 384 : #define FD_TXN_ACCT_CAT_ALL 0x3F /* Any Any Any */
525 :
526 : /* fd_txn_account_cnt: Returns the number of accounts referenced by this
527 : transaction that have the property specified by include_category.
528 : txn must be a pointer to a valid transaction. include_cat must be
529 : one of the previously defined FD_TXN_ACCT_CAT_* values. Ideally,
530 : include_cat should be a compile-time constant, in which case this
531 : function typically compiles to about 3 instructions. */
532 : static inline ulong
533 : fd_txn_account_cnt( fd_txn_t const * txn,
534 166927506 : int include_cat ) {
535 166927506 : ulong cnt = 0UL;
536 166927506 : if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_SIGNER ) cnt += (ulong)txn->signature_cnt - (ulong)txn->readonly_signed_cnt;
537 166927506 : if( include_cat & FD_TXN_ACCT_CAT_READONLY_SIGNER ) cnt += (ulong)txn->readonly_signed_cnt;
538 166927506 : if( include_cat & FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM ) cnt += (ulong)txn->readonly_unsigned_cnt;
539 166927506 : if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_ALT ) cnt += (ulong)txn->addr_table_adtl_writable_cnt;
540 166927506 : if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM )
541 139778928 : cnt += (ulong)txn->acct_addr_cnt - (ulong)txn->signature_cnt - (ulong)txn->readonly_unsigned_cnt;
542 166927506 : if( include_cat & FD_TXN_ACCT_CAT_READONLY_ALT )
543 27147039 : cnt += (ulong)txn->addr_table_adtl_cnt - (ulong)txn->addr_table_adtl_writable_cnt;
544 :
545 166927506 : return cnt;
546 166927506 : }
547 :
548 : /* fd_txn_acct_iter_{init, next, end, idx}: These functions are used for
549 : iterating over the accounts in a transaction that have the property
550 : specified by include_cat.
551 :
552 : Example usage:
553 :
554 : fd_txn_acct_addr_t const * acct = fd_txn_get_acct_addrs( txn, payload );
555 : for( fd_txn_acct_iter_t i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
556 : i!=fd_txn_acct_iter_end(); i=fd_txn_acct_iter_next( i ) ) {
557 : // Do something with acct[ fd_txn_acct_iter_idx( i ) ]
558 : }
559 :
560 : For fd_txn_acct_iter_init, txn must be a pointer to a valid
561 : transaction and include_cat must be one of the FD_TXN_ACCT_CAT_*
562 : values defined above (or a bitwise combination of them). On
563 : completion, returns a value i such that fd_txn_acct_iter_idx( i ) is
564 : the index of the first account address meeting the specified
565 : criteria, or i==fd_txn_acct_iter_end() if there aren't any account
566 : addresses that meet the criteria.
567 :
568 : For fd_acct_iter_next, cur should be the current value of the
569 : iteration variable. Advances the iteration variable such that
570 : fd_txn_acct_iter_idx( i ) is the index of the next account meeting
571 : the initially specified criteria, or i==fd_txn_acct_iter_end() if
572 : there aren't any more account addresses meeting the criteria. It is
573 : undefined behavior to call fd_acct_iter_next with a value of cur not
574 : returned by a call to either fd_acct_iter_init or fd_acct_iter_next.
575 : It's also U.B. to call fd_acct_iter_next after fd_acct_iter_end has
576 : been returned.
577 :
578 : fd_txn_acct_iter_t should be treated as an opaque handle and not
579 : modified other than by using fd_txn_acc_iter_next. You can peek and
580 : see that it's a ulong, so it fits in a register and doesn't need to
581 : be destroyed or cleaned up. It's safe to save a fd_txn_acct_iter_t
582 : value to resume iteration later with the same transaction. */
583 :
584 : typedef ulong fd_txn_acct_iter_t;
585 :
586 : /* Account addresses are categorized into 6 categories, and all the
587 : account addresses for each category are stored contiguously. This
588 : means that for any subset of the 6 categories that the user wants to
589 : iterate over, there are at most 3 disjoint ranges.
590 :
591 : For any iteration space I, we can choose 6 integers
592 : {start,count}_{0,1,2} so that
593 : I = [start0, start0+count0) U [start1, start1+count1)
594 : U [start2, start2+count2)
595 : Any empty intervals are represented as [0, 0).
596 : We store the control word as a single ulong with start0 in the low
597 : order bits. Then the current account index can be retrieved by
598 : taking the low order byte, and the count remaining in the current
599 : interval is the second lowest byte. We can update both in one
600 : instruction by subtracting 255. */
601 :
602 : static inline fd_txn_acct_iter_t FD_FN_PURE
603 : fd_txn_acct_iter_init( fd_txn_t const * txn,
604 94129812 : int include_cat ) {
605 : /* Our goal is to output something that looks like [start0, count0,
606 : start1, count1, start2, count2, 0, 0] from lowest order to highest.
607 : We construct the potentially 3 (start, count) pairs and then
608 : branchlessly get rid of any empty ones. */
609 94129812 : ulong control[3] = { 0 }; /* High 6 bytes of each stay element not touched */
610 94129812 : ulong i = (ulong)(-1L); /* So that it is 0 post increment */
611 :
612 : /* Make references more convenient. Dead code elimination seems to
613 : take care of the unneeded ones. */
614 94129812 : ulong s = txn->signature_cnt;
615 94129812 : ulong q = txn->readonly_signed_cnt;
616 94129812 : ulong r = txn->readonly_unsigned_cnt;
617 94129812 : ulong a = txn->acct_addr_cnt;
618 94129812 : ulong t = txn->addr_table_adtl_cnt;
619 94129812 : ulong u = txn->addr_table_adtl_writable_cnt;
620 :
621 : /* All the branches here should be known at compile time. */
622 : /* If WRITABLE_SIGNER is included, then f>>1 is 0, so the second
623 : branch will always be true, setting control[0]=0. */
624 94129812 : # define INCLUDE_RANGE(f, start, cnt) \
625 564778872 : if( include_cat & (f) ) { \
626 282168684 : if( !(include_cat & ((f)>>1) ) ) control[ ++i ]=(start); \
627 282168684 : control[ i ] += (cnt)<<8; \
628 282168684 : }
629 :
630 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_SIGNER, 0, s-q );
631 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_SIGNER, s-q, q );
632 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM, s, a-r-s );
633 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM, a-r, r );
634 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_ALT, a, u );
635 94129812 : INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_ALT, a+u, t-u );
636 94129812 : # undef INCLUDE_RANGE
637 :
638 : /* We now need to delete the empty intervals (if any). */
639 94129812 : ulong control0 = control[0];
640 94129812 : ulong control1 = control[1];
641 94129812 : ulong control2 = control[2];
642 :
643 94129812 : int control2_empty = !(control2&0xFF00UL);
644 94129812 : control2 = fd_ulong_if( control2_empty, 0UL, control2 );
645 :
646 94129812 : int control1_empty = !(control1&0xFF00UL);
647 94129812 : control1 = fd_ulong_if( control1_empty, control2, control1 );
648 94129812 : control2 = fd_ulong_if( control1_empty, 0UL, control2 );
649 :
650 94129812 : int control0_empty = !(control0&0xFF00UL);
651 94129812 : control0 = fd_ulong_if( control0_empty, control1, control0 );
652 94129812 : control1 = fd_ulong_if( control0_empty, control2, control1 );
653 94129812 : control2 = fd_ulong_if( control0_empty, 0UL, control2 );
654 :
655 94129812 : return control0 | (control1<<16) | (control2<<32);
656 94129812 : }
657 :
658 : static inline fd_txn_acct_iter_t FD_FN_CONST
659 71466423 : fd_txn_acct_iter_next( fd_txn_acct_iter_t cur ) {
660 71466423 : cur = cur + 0x0001UL - 0x0100UL; /* Increment low byte, decrement count */
661 : /* Move to the next interval if we're done with this one. */
662 71466423 : return fd_ulong_if( cur&0xFF00UL, cur, cur>>16 );
663 71466423 : }
664 :
665 0 : static inline fd_txn_acct_iter_t FD_FN_CONST fd_txn_acct_iter_end( void ) { return 0UL; }
666 71466429 : static inline ulong FD_FN_CONST fd_txn_acct_iter_idx( fd_txn_acct_iter_t cur ) { return cur & 0xFFUL; }
667 :
668 : /* fd_txn_parse_core: Parses a transaction from the canonical encoding, i.e.
669 : the format used on the wire.
670 :
671 : Payload points to the first byte of encoded transaction, e.g. the
672 : first byte of the UDP/Quic payload if the transaction comes from the
673 : network. The encoded transaction must occupy exactly [payload,
674 : payload+payload_sz), i.e. this method will read no more than
675 : payload_sz bytes from payload, but it will reject the transaction if
676 : it contains extra padding at the end or continues past
677 : payload+payload_sz. payload_sz <= FD_TXN_MTU.
678 :
679 : out_buf is the memory where the parsed transaction will be stored.
680 : out_buf must have room for at least FD_TXN_MAX_SZ bytes.
681 :
682 : Returns the total size of the resulting fd_txn struct on success and
683 : 0 on failure. On failure, the contents of out_buf are undefined,
684 : although nothing will be written beyond FD_TXN_MAX_SZ bytes.
685 :
686 : If counters_opt is non-NULL, some counters about the result of the
687 : parsing process will be accumulated into the struct pointed to by
688 : counters_opt. Note: The returned txn object is not self-contained
689 : since it refers to byte ranges inside the payload.
690 :
691 : payload_sz_opt, if supplied, gets filled with the total bytes this txn
692 : uses (allowing for walking of an entry/microblock). If it is not supplied, the
693 : parse will return an error if the payload_sz does not exactly match. */
694 :
695 : ulong
696 : fd_txn_parse_core( uchar const * payload,
697 : ulong payload_sz,
698 : void * out_buf,
699 : fd_txn_parse_counters_t * counters_opt,
700 : ulong * payload_sz_opt );
701 :
702 :
703 : /* fd_txn_parse: Convenient wrapper around fd_txn_parse_core that eliminates some optional arguments */
704 : static inline ulong
705 61359099 : fd_txn_parse( uchar const * payload, ulong payload_sz, void * out_buf, fd_txn_parse_counters_t * counters_opt ) {
706 61359099 : return fd_txn_parse_core( payload, payload_sz, out_buf, counters_opt, NULL );
707 61359099 : }
708 :
709 : /* fd_txn_is_writable: Is the account at the supplied index writable
710 :
711 : Accounts ordered:
712 : Index Range | Signer? | Writeable?
713 : ---------------------------------------------------------------------------------|--------------|-------------
714 : [0, signature_cnt - readonly_signed_cnt) | signer | writable
715 : [signature_cnt, acct_addr_cnt - readonly_unsigned_cnt) | not signer | writable
716 : */
717 :
718 : static inline int
719 105279 : fd_txn_is_writable( fd_txn_t const * txn, int idx ) {
720 105279 : if (txn->transaction_version == FD_TXN_V0 && idx >= txn->acct_addr_cnt) {
721 29493 : if (idx < (txn->acct_addr_cnt + txn->addr_table_adtl_writable_cnt)) {
722 19794 : return 1;
723 19794 : }
724 9699 : return 0;
725 29493 : }
726 :
727 75786 : if (idx < (txn->signature_cnt - txn->readonly_signed_cnt))
728 54606 : return 1;
729 21180 : if ((idx >= txn->signature_cnt) & (idx < (txn->acct_addr_cnt - txn->readonly_unsigned_cnt)))
730 7545 : return 1;
731 :
732 13635 : return 0;
733 21180 : }
734 :
735 : /* fd_txn_is_signer: Is the account at the supplied index a signer
736 :
737 : Accounts ordered:
738 : Index Range | Signer? | Writeable?
739 : ---------------------------------------------------------------------------------|--------------|-------------
740 : [0, signature_cnt - readonly_signed_cnt) | signer | writable
741 : [signature_cnt - readonly_signed_cnt, signature_cnt) | signer | readonly
742 : */
743 : static inline int
744 43002 : fd_txn_is_signer( fd_txn_t const * txn, int idx ) {
745 43002 : return idx < txn->signature_cnt;
746 43002 : }
747 :
748 : FD_PROTOTYPES_END
749 :
750 : #endif /* HEADER_fd_src_ballet_txn_fd_txn_h */
|