Line data Source code
1 : #ifndef HEADER_fd_src_disco_pack_fd_pack_cost_h
2 : #define HEADER_fd_src_disco_pack_fd_pack_cost_h
3 :
4 : #include "../../ballet/fd_ballet_base.h"
5 : #include "fd_pack.h"
6 : #include "fd_compute_budget_program.h"
7 : #include "../../flamenco/runtime/fd_system_ids_pp.h"
8 : #include "../../ballet/txn/fd_txn.h"
9 :
10 : /* The functions in this header implement the transaction cost model
11 : that is soon to be part of consensus.
12 : The cost model consists of several components:
13 : * per-signature cost: The costs associated with transaction
14 : signatures + signatures from precompiles (ED25519 + SECP256*)
15 : * per-write-lock cost: cost assiciated with aquiring write locks
16 : for writable accounts listed in the transaction.
17 : * instruction data length cost: The fixed cost for each instruction
18 : data byte in the transaction payload.
19 : * built-in execution cost: The fixed cost associated with "builtin"
20 : instructions. "What are builtins" is defined here:
21 : https://github.com/anza-xyz/agave/blob/1baa4033e0d2d4175373f07b73ddda2f3cc0a8d6/builtins-default-costs/src/lib.rs#L120-L200
22 : After SIMD 170, all builtins have a fixed cost of 3000 cus.
23 : * BPF execution cost: The costs assosiated with any instruction
24 : that is not a builtin. This value comes from the VM after
25 : transaction execution.
26 : * loaded accounts data cost: Costs associated with all the account
27 : data loaded from the chain. This value is known in the
28 : transaction loading stage, after accounts data is loaded.
29 : These are all summed to determine the total transaction cost. */
30 :
31 : /* Simple votes: before the remove_simple_vote_from_cost_model
32 : feature, simple votes had a fixed cost instead of going through the
33 : full cost model.
34 :
35 : To avoid feature-gating pack code, pack uses an upper bound on the
36 : actual cost of simple votes which is guaranteed to be larger than the
37 : cost consumed both before and after feature gate activation. bank
38 : tiles must then carefully rebate the correct amount based on whether
39 : the feature is active or not.
40 :
41 : Since this is higher than the static cost used before
42 : remove_simple_vote_from_cost_model is activated, this can be
43 : used both before and after the feature is activated.
44 :
45 : Once remove_simple_vote_from_cost_model is activated, the vote cu
46 : limit is no longer part of consensus, so we are free to use a
47 : different simple vote classifier than Agave. */
48 :
49 : /* To compute the built-in cost, we need to check a table. The table
50 : is known ahead of time though, so we can build a perfect hash
51 : table for performance.
52 : The values of the table are based on https://github.com/
53 : solana-labs/solana/blob/9fb105c801e2999a24f0773443d6164e30c9ff0c/
54 : runtime/src/block_cost_limits.rs#L34-L47 . */
55 :
56 :
57 :
58 : struct __attribute__((aligned(32))) fd_pack_builtin_prog_cost {
59 : uchar program_id[32];
60 : ulong cost_per_instr;
61 : };
62 : typedef struct fd_pack_builtin_prog_cost fd_pack_builtin_prog_cost_t;
63 :
64 : #define MAP_PERFECT_NAME fd_pack_builtin
65 : #define MAP_PERFECT_LG_TBL_SZ 4
66 : #define MAP_PERFECT_T fd_pack_builtin_prog_cost_t
67 : #define MAP_PERFECT_HASH_C 478U
68 : #define MAP_PERFECT_KEY program_id
69 : #define MAP_PERFECT_KEY_T fd_acct_addr_t const *
70 : #define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
71 : #define MAP_PERFECT_COMPLEX_KEY 1
72 9690543 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
73 :
74 77597208 : #define PERFECT_HASH( u ) (((478U*(u))>>28)&0xFU)
75 :
76 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
77 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
78 : PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
79 9690543 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
80 :
81 :
82 : /* The cost model estimates 200,000 CUs for builtin programs that were migrated to BPF */
83 : #define MAP_PERFECT_0 ( SYS_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
84 : #define MAP_PERFECT_1 ( COMPUTE_BUDGET_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
85 : #define MAP_PERFECT_2 ( BPF_UPGRADEABLE_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
86 : #define MAP_PERFECT_3 ( BPF_LOADER_1_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
87 : #define MAP_PERFECT_4 ( BPF_LOADER_2_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
88 : #define MAP_PERFECT_5 ( LOADER_V4_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
89 : #define MAP_PERFECT_6 ( KECCAK_SECP_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
90 : #define MAP_PERFECT_7 ( ED25519_SV_PROG_ID ), .cost_per_instr= FD_COMPUTE_BUDGET_MAX_BUILTIN_CU_LIMIT
91 : #define MAP_PERFECT_8 ( SECP256R1_PROG_ID ), .cost_per_instr= 0UL /* Not officially a builtin */
92 :
93 : #include "../../util/tmpl/fd_map_perfect.c"
94 :
95 : /* Redefine it so we can use it below */
96 : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
97 : a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
98 67906665 : PERFECT_HASH( ((uint)a08 | ((uint)a09<<8) | ((uint)a10<<16) | ((uint)a11<<24)) )
99 :
100 13581552 : #define FD_PACK_COST_PER_SIGNATURE ( 720U)
101 219 : #define FD_PACK_COST_PER_ED25519_SIGNATURE ( 2400U)
102 219 : #define FD_PACK_COST_PER_SECP256K1_SIGNATURE ( 6690U)
103 219 : #define FD_PACK_COST_PER_SECP256R1_SIGNATURE ( 4800U)
104 13582710 : #define FD_PACK_COST_PER_WRITABLE_ACCT ( 300U)
105 13581549 : #define FD_PACK_INV_COST_PER_INSTR_DATA_BYTE ( 4U)
106 :
107 : /* The computation here is similar to the computation for the max
108 : fd_txn_t size. There are various things a transaction can include
109 : that consume CUs, and they also consume some bytes of payload. It
110 : then becomes an integer linear programming problem. First, the best
111 : use of bytes is to include a compute budget program instruction that
112 : requests 1.4M CUs. That also requires the invocation of another
113 : non-builtin program, consuming 3 bytes of payload. In total to do
114 : this, we need 2 pubkey and 11 bytes of instruction payload. This is
115 : >18,000 CUs per byte, which is obviously the best move.
116 :
117 : From there, we can also invoke built-in programs with no accounts and
118 : no instruction data, which also consumes 3 bytes of payload. The
119 : most expensive built-in is the BPF upgradeable loader. We're limited
120 : to 64 instructions, so we can only consume it at most 62 times. This
121 : is about 675 CUs per byte. This is more efficient than precompiles,
122 : which consume <609 CUs per byte in the worst case.
123 :
124 : We've maxed out the instruction limit, so we can only continue to
125 : increase the cost by adding writable accounts or writable signer
126 : accounts. Writable signers consume 96 bytes use 1020 CUs. Writable
127 : non-signers consume 32 bytes and use 300 CUs. That's 10.6 CUs/byte
128 : and 9.4 CUs/byte, respectively, so in general, writable signers are
129 : more efficient and we want to add as many as we can. We also need at
130 : least one writable signer to be the fee payer, and, although it's
131 : unusual, there's actually no reason the non-builtin program can't be
132 : a writable signer too.
133 :
134 : Finally, with any bytes that remain, we can add them to one of the
135 : instruction datas for 0.25 CUs/byte.
136 :
137 : Note that by default, 64MiB of data are assumed for the loaded
138 : accounts data size cost. This corresponds (currently) to 16384 CUs.
139 :
140 : This gives a transaction that looks like
141 : Field bytes consumed CUs used
142 : sig cnt 1 0
143 : fee payer sig 64 720
144 : 8 other signatures 512 5,670
145 : fixed header (no ALTs) 3 0
146 : acct addr cnt 1 0
147 : fee payer pubkey 32 300
148 : 8 writable pubkeys 256 2,400
149 : 2 writable non-signers 64 600
150 : CBP, BPF upg loader 64 0
151 : Recent blockhash 32 0
152 : Instruction count 1 0
153 : Compute budget program ix 8 151.25
154 : 62 dummy BPF upg ixs 186 146,940
155 : 1 dummy non-builtin ix 8 1,400,001.25
156 : loaded accts data cost 0 16384
157 : + ---------------------------------------------------------------
158 : 1,232 1,573,166
159 :
160 : One of the main take-aways from this is that the cost of a
161 : transaction easily fits in a uint. */
162 : #define FD_PACK_MAX_TXN_COST (1573166UL)
163 : FD_STATIC_ASSERT( FD_PACK_MAX_TXN_COST < (ulong)UINT_MAX, fd_pack_max_cost );
164 :
165 : /* Every transaction has at least a fee payer, a writable signer. */
166 : #define FD_PACK_MIN_TXN_COST (FD_PACK_COST_PER_SIGNATURE+FD_PACK_COST_PER_WRITABLE_ACCT)
167 :
168 : /* The Solana protocol tries to impose a limit on the total amount of
169 : account data that can be allocated in a block (via the creation of
170 : new accounts and the growth of existing accounts). Unfortunately,
171 : the way this limit is specified by the protocol is buggy and means
172 : that it is neither an upper bound nor a lower bound for what it is
173 : supposed to measure. If USE_TRUE_ALLOC_BOUND is set to 1, this code
174 : will compute a true upper bound for the amount the transaction can
175 : allocate. If it is set to 0, it will compute the value in an
176 : Agave-compatible way, that is, a value that is normally identical to
177 : what Agave produces, but slightly higher in certain cases. */
178 : #define FD_PACK_COST_USE_TRUE_ALLOC_BOUND 0
179 :
180 : /* NOTE: THE FOLLOWING CONSTANTS ARE CONSENSUS CRITICAL AND CANNOT BE
181 : CHANGED WITHOUT COORDINATING WITH ANZA. */
182 :
183 : /* These are bounds on known limits. Upper bound values are used to
184 : calculate memory footprints while lower bounds are used for
185 : initializing consensus-dependent logic and invariant checking. As a
186 : leader, it is OK to produce blocks using limits smaller than the
187 : active on-chain limits. Replay should always use the correct
188 : chain-derived limits.
189 :
190 : The actual limits used by pack may be updated dynamically to some
191 : in-bounds value. If there is an anticipated feature activation that
192 : changes these limits, the upper bound should be the largest
193 : anticipated value while the lower bound should be the current active
194 : limit. For Frankendancer, the actual value used for consensus will be
195 : retrieved from Agave at runtime. */
196 0 : #define FD_PACK_MAX_COST_PER_BLOCK_LOWER_BOUND (48000000UL)
197 0 : #define FD_PACK_MAX_VOTE_COST_PER_BLOCK_LOWER_BOUND (36000000UL)
198 0 : #define FD_PACK_MAX_WRITE_COST_PER_ACCT_LOWER_BOUND (12000000UL)
199 :
200 0 : #define FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND (100000000UL) /* simd 0286 */
201 0 : #define FD_PACK_MAX_VOTE_COST_PER_BLOCK_UPPER_BOUND ( 36000000UL)
202 0 : #define FD_PACK_MAX_WRITE_COST_PER_ACCT_UPPER_BOUND ( FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND * 4UL / 10UL ) /* simd 0306 */
203 :
204 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.1/cost-model/src/block_cost_limits.rs#L39-L41 */
205 315 : #define FD_PACK_MAX_ALLOCATED_DATA_PER_BLOCK ( 100UL*1000UL*1000UL )
206 :
207 : FD_STATIC_ASSERT( FD_MAX_TXN_PER_SLOT_CU==(FD_PACK_MAX_COST_PER_BLOCK_UPPER_BOUND/FD_PACK_MIN_TXN_COST), max_txn_per_slot_cu );
208 :
209 : /* The txncache should at most store one entry for each transaction, so
210 : you would expect this value to be just FD_MAX_TXN_PER_SLOT. But
211 : there's a minor complication ... Agave inserts each transaction into
212 : the status cache twice, once with the signature as the key, and
213 : once with the message hash as the key. This is to support querying
214 : transactions by either signature or message hash. We load snapshots
215 : from Agave nodes which serve both entries, and there is no way to
216 : filter out the by signature entries which are useless to us, so
217 : initially the status cache needs twice as much space. */
218 0 : #define FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT (2UL*FD_MAX_TXN_PER_SLOT)
219 :
220 :
221 : /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L55 */
222 :
223 7425 : #define FD_PACK_VOTE_DEFAULT_COMPUTE_UNITS (2100UL)
224 :
225 : /* SIMD-0387: BLS proof-of-possession verification cost charged by the
226 : vote program for authorize instructions.
227 :
228 : https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L83 */
229 7425 : #define FD_PACK_BLS_PROOF_OF_POSSESSION_VERIFICATION_COMPUTE_UNITS (34500UL)
230 :
231 : /* Upper bound on execution CUs used by vote instructions.
232 :
233 : The only vote instructions which use more than the default cost are
234 : the authorize instruction, which also charge the BLS
235 : proof-of-possession verification cost.
236 :
237 : IMPORTANT: if the vote program starts charging more CUs for any
238 : instructions, this constant will need to be updated.
239 : */
240 7425 : #define FD_PACK_VOTE_MAX_COMPUTE_UNITS (FD_PACK_VOTE_DEFAULT_COMPUTE_UNITS + FD_PACK_BLS_PROOF_OF_POSSESSION_VERIFICATION_COMPUTE_UNITS)
241 :
242 : /* Max loaded account data size: FD_COMPUTE_BUDGET_MAX_LOADED_DATA_SZ
243 :
244 : Cost: ceil( FD_COMPUTE_BUDGET_MAX_LOADED_DATA_SZ / 32,768 ) * 8
245 : = ceil( 67,108,864 / 32,768 ) * 8
246 : = 2,048 * 8
247 : = 16,384 CUs */
248 : #define FD_PACK_VOTE_DEFAULT_LOADED_ACCOUNTS_DATA_COST (16384UL)
249 :
250 : /* Maximum instruction data cost for a simple vote transaction:
251 : - 1 signature
252 : - 2 transaction accounts
253 : - 0 instruction accounts
254 :
255 : Which results in a fixed overhead of:
256 : - Signature count: 1
257 : - 1 signature: 64
258 : - Message header: 3
259 : - Account count: 1
260 : - 2 account entries: 64
261 : - Recent blockhash: 32
262 : - Instruction count: 1
263 : - program_id: 1
264 : - Instruction account count: 1
265 : - Instruction data length: 1
266 : Total: 169 bytes
267 :
268 : Leaving (FD_TXN_MTU - 169) = 1063 bytes for the instruction data.
269 : This results in a cost of 1063 / 4 = 265 CUs.
270 : */
271 : #define FD_PACK_SIMPLE_VOTE_MAX_INSTR_DATA_COST (265UL)
272 :
273 : /* A simple vote transaction is any transaction that satisfies the
274 : following conditions:
275 : - Has 1 or 2 signatures
276 : - Is a legacy transaction
277 : - Has exactly one instruction
278 : - Must invoke the vote program
279 :
280 : Therefore the worst-case most expensive simple vote transaction has:
281 : - 2 signatures
282 : - 35 writable accounts (see FD_TXN_ACCT_ADDR_MAX)
283 : - The maximum amount of compute units for a vote program instruction
284 : - 1 instruction of the maximum instruction data size
285 : - The maximum amount of loaded accounts data
286 : = 65,189 CUs
287 : */
288 : static const ulong FD_PACK_MAX_SIMPLE_VOTE_COST = ( 2UL*FD_PACK_COST_PER_SIGNATURE + /* 1,440 */
289 : 35UL*FD_PACK_COST_PER_WRITABLE_ACCT + /* 10,500 */
290 : FD_PACK_VOTE_MAX_COMPUTE_UNITS + /* 36,600 */
291 : FD_PACK_VOTE_DEFAULT_LOADED_ACCOUNTS_DATA_COST + /* 16,384 */
292 : FD_PACK_SIMPLE_VOTE_MAX_INSTR_DATA_COST ); /* 265 */
293 :
294 : /* The fixed cost for simple votes before the activation of
295 : remove_simple_vote_from_cost_model */
296 : static const ulong FD_PACK_FIXED_SIMPLE_VOTE_COST = ( FD_PACK_COST_PER_SIGNATURE +
297 : 2UL*FD_PACK_COST_PER_WRITABLE_ACCT +
298 : FD_PACK_VOTE_DEFAULT_COMPUTE_UNITS +
299 : 8UL );
300 :
301 : #undef FD_PACK_SIMPLE_VOTE_MAX_INSTR_DATA_COST
302 :
303 : /* Computes the total cost and a few related properties for the
304 : specified transaction. On success, returns the cost, which is in
305 : [1020, FD_PACK_MAX_TXN_COST] and sets or clears the
306 : FD_TXN_P_FLAG_IS_SIMPLE_VOTE bit of the value pointed to by flags to
307 : indicate whether the transaction is a simple vote or not.
308 :
309 : Additionally:
310 : If opt_execution_cost is non-null, on success it will contain the
311 : execution cost (BPF execution cost + built-in execution cost). This
312 : value is in [0, the returned value).
313 : If opt_fee is non-null, on success it will contain the priority fee,
314 : measured in lamports (i.e. the part of the fee that excludes the
315 : per-signature fee). This value is in [0, ULONG_MAX].
316 : If opt_precompile_sig_cnt is non-null, on success it will contain the
317 : total number of signatures in precompile instructions, namely Keccak
318 : and Ed25519 signature verification programs. This value is in [0,
319 : 256*64]. Note that this does not do full parsing of the precompile
320 : instruction, and it may be malformed.
321 : If opt_loaded_accounts_data_cost is non-null, on success it will
322 : contain the total requested cost due to loaded accounts data. This
323 : value is in [0, the returned value).
324 : If opt_allocated_data is non-null, on success it will contain a value
325 : that depends on FD_PACK_COST_USE_TRUE_ALLOC_BOUND (see above),
326 : relating to the amount of data (in bytes) this transaction can
327 : allocate. This value is in [0, 20MB].
328 :
329 : On failure, returns 0 and does not modify the value pointed to by
330 : flags, opt_execution_cost, opt_fee, or opt_precompile_sig_cnt. */
331 : static inline ulong
332 : fd_pack_compute_cost( fd_txn_t const * txn,
333 : uchar const * payload,
334 : uint * flags,
335 : ulong * opt_execution_cost,
336 : ulong * opt_fee,
337 : ulong * opt_precompile_sig_cnt,
338 : ulong * opt_loaded_accounts_data_cost,
339 13581333 : ulong * opt_allocated_data ) {
340 :
341 67906665 : #define ROW(x) fd_pack_builtin_tbl + MAP_PERFECT_HASH_PP( x )
342 13581333 : fd_pack_builtin_prog_cost_t const * compute_budget_row = ROW( COMPUTE_BUDGET_PROG_ID );
343 13581333 : fd_pack_builtin_prog_cost_t const * ed25519_precompile_row = ROW( ED25519_SV_PROG_ID );
344 13581333 : fd_pack_builtin_prog_cost_t const * secp256k1_precomp_row = ROW( KECCAK_SECP_PROG_ID );
345 13581333 : fd_pack_builtin_prog_cost_t const * secp256r1_precomp_row = ROW( SECP256R1_PROG_ID );
346 : /* The three programs that are able to allocate more than 10 kB per
347 : account */
348 13581333 : fd_pack_builtin_prog_cost_t const * system_program_row = ROW( SYS_PROG_ID );
349 : #if FD_PACK_COST_USE_TRUE_ALLOC_BOUND
350 : fd_pack_builtin_prog_cost_t const * upgradeable_loader_row = ROW( BPF_UPGRADEABLE_PROG_ID );
351 : fd_pack_builtin_prog_cost_t const * loader_v4_row = ROW( LOADER_V4_PROG_ID );
352 : #endif /* FD_PACK_COST_USE_TRUE_ALLOC_BOUND */
353 13581333 : #undef ROW
354 :
355 13581333 : int is_simple_vote = fd_txn_is_simple_vote_transaction( txn, payload );
356 13581333 : if( FD_UNLIKELY( is_simple_vote ) ) *flags |= FD_TXN_P_FLAGS_IS_SIMPLE_VOTE;
357 13573908 : else *flags &= ~FD_TXN_P_FLAGS_IS_SIMPLE_VOTE;
358 :
359 : /* We need to be mindful of overflow here, but it's not terrible.
360 : signature_cost < FD_TXN_ACCT_ADDR_MAX*720 + FD_TXN_INSTR_MAX * UCHAR_MAX * 6690,
361 : writable_cost <= FD_TXN_ACCT_ADDR_MAX*300 */
362 13581333 : ulong signature_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_SIGNER );
363 13581333 : ulong signature_cost = FD_PACK_COST_PER_SIGNATURE * signature_cnt;
364 13581333 : ulong writable_cost = FD_PACK_COST_PER_WRITABLE_ACCT * fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_WRITABLE );
365 :
366 13581333 : ulong instr_data_sz = 0UL; /* < FD_TPU_MTU */
367 13581333 : ulong non_builtin_cnt = 0UL; /* <= FD_TXN_INSTR_MAX */
368 13581333 : ulong precompile_sig_cnt = 0UL; /* <= FD_TXN_INSTR_MAX * UCHAR_MAX */
369 13581333 : ulong allocated_data = 0UL; /* in bytes */
370 13581333 : fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
371 :
372 13581333 : fd_compute_budget_program_state_t cbp[1];
373 13581333 : fd_compute_budget_program_init( cbp );
374 :
375 23271873 : for( ulong i=0UL; i<txn->instr_cnt; i++ ) {
376 9690543 : ulong data_sz = txn->instr[i].data_sz;
377 9690543 : instr_data_sz += data_sz;
378 :
379 9690543 : ulong prog_id_idx = (ulong)txn->instr[i].program_id;
380 9690543 : fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
381 :
382 : /* Lookup prog_id in hash table */
383 :
384 9690543 : fd_pack_builtin_prog_cost_t null_row[1] = {{{ 0 }, 0UL }};
385 9690543 : fd_pack_builtin_prog_cost_t const * in_tbl = fd_pack_builtin_query( prog_id, null_row );
386 9690543 : non_builtin_cnt += !in_tbl->cost_per_instr; /* null row has 0 cost */
387 :
388 9690543 : if( FD_UNLIKELY( in_tbl==compute_budget_row ) ) {
389 4226079 : if( FD_UNLIKELY( 0==fd_compute_budget_program_parse( payload+txn->instr[i].data_off, data_sz, cbp ) ) )
390 3 : return 0UL;
391 5464464 : } else if( FD_UNLIKELY( (in_tbl==ed25519_precompile_row) ) ) {
392 : /* First byte is # of signatures. Branchless tail reading here is
393 : probably okay, but this seems safer. */
394 0 : ulong ed25519_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
395 0 : if( FD_UNLIKELY( data_sz<2UL+14UL*ed25519_signature_cnt ) ) return 0UL;
396 0 : precompile_sig_cnt += ed25519_signature_cnt;
397 0 : signature_cost += ed25519_signature_cnt * FD_PACK_COST_PER_ED25519_SIGNATURE;
398 5464464 : } else if( FD_UNLIKELY( (in_tbl==secp256k1_precomp_row) ) ) {
399 0 : ulong secp256k1_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
400 0 : if( FD_UNLIKELY( data_sz<1UL+11UL*secp256k1_signature_cnt ) ) return 0UL;
401 0 : precompile_sig_cnt += secp256k1_signature_cnt;
402 0 : signature_cost += secp256k1_signature_cnt * FD_PACK_COST_PER_SECP256K1_SIGNATURE;
403 5464464 : } else if( FD_UNLIKELY( (in_tbl==secp256r1_precomp_row) ) ) {
404 0 : ulong secp256r1_signature_cnt = (data_sz>0) ? (ulong)payload[ txn->instr[i].data_off ] : 0UL;
405 0 : if( FD_UNLIKELY( data_sz<2UL+14UL*secp256r1_signature_cnt ) ) return 0UL;
406 0 : precompile_sig_cnt += secp256r1_signature_cnt;
407 0 : signature_cost += secp256r1_signature_cnt * FD_PACK_COST_PER_SECP256R1_SIGNATURE;
408 0 : }
409 : /* BPF programs can allocate 10kB per account per instruction.
410 : The vote program (see below) and the address lookup table program
411 : (up to 56+32*256 bytes) do allocate, and several native programs
412 : can reduce the size of an account, but the only ones that can
413 : possibly allocate more than 10kB per account are below.
414 : Additionally, none of the above programs allocate at all.
415 :
416 : A normal vote does not allocate any data, but a simple vote may
417 : actually invoke one of the vote program instructions that does
418 : allocate FD_VOTE_STATE_V3_SZ or V4, which are both 3762 bytes.
419 : If it invokes the vote program but isn't a simple vote, it will
420 : be caught by the general case and overestimated at 10kB per
421 : account, which is fine.
422 :
423 : Note: This complexity here is pretty gross, but we need a better
424 : bound for allocated_data than 20MB, and this seems to be the best
425 : way. */
426 5464464 : #define MAX_ALLOC (20UL*1024UL*1024UL) /* mostly to prevent attacker-induced overflow */
427 5464464 : #define DEFAULT_ALLOC (10UL*1024UL) /* == MAX_PERMITTED_DATA_INCREASE */
428 5464464 : else if( FD_UNLIKELY( in_tbl==system_program_row ) ) {
429 1395 : ulong discriminant = ULONG_MAX;
430 1395 : uchar const * base = payload + txn->instr[i].data_off;
431 1395 : if( FD_UNLIKELY( data_sz<12UL ) ) continue;
432 240 : discriminant = FD_LOAD( uint, base );
433 240 : base += sizeof(uint); data_sz -= sizeof(uint);
434 240 : ulong seed_len;
435 240 : switch( discriminant ) {
436 60 : case 0UL: /* FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT */
437 60 : if( FD_UNLIKELY( data_sz<8UL+8UL ) ) break;
438 : /* Note: here (and below), Agave sets alloc to 0 if any of
439 : these instructions request more than 10 MB. We don't
440 : bother with that. If a transaction has an instruction that
441 : requests more than 10 MB and pays a sufficient fee for it,
442 : and then fails, that's not a big problem. We're always
443 : computing a conservative estimate. */
444 60 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
445 60 : break;
446 60 : case 3UL: /* FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED */
447 60 : if( FD_UNLIKELY( data_sz<32UL+8UL ) ) break;
448 60 : seed_len = FD_LOAD( ulong, base+32UL );
449 60 : base += 32UL+8UL; data_sz -= 32UL+8UL;
450 60 : if( FD_UNLIKELY( data_sz<seed_len ) ) break;
451 60 : base += seed_len; data_sz -= seed_len;
452 60 : if( FD_UNLIKELY( data_sz<(8UL+8UL) ) ) break;
453 60 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
454 60 : break;
455 60 : case 8UL: /* FD_SYSTEM_PROGRAM_INSTR_ALLOCATE */
456 60 : if( FD_UNLIKELY( data_sz<8UL ) ) break;
457 60 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base ) );
458 60 : break;
459 60 : case 9UL: /* FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED */
460 60 : if( FD_UNLIKELY( data_sz<32UL+8UL ) ) break;
461 60 : seed_len = FD_LOAD( ulong, base+32UL );
462 60 : base += 32UL+8UL; data_sz -= 32UL+8UL;
463 60 : if( FD_UNLIKELY( data_sz<seed_len ) ) break;
464 60 : base += seed_len; data_sz -= seed_len;
465 60 : if( FD_UNLIKELY( data_sz<8UL ) ) break;
466 60 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base ) );
467 60 : break;
468 0 : case 13UL: /* create_account_allow_prefund */
469 : /* Agave returns 0 here until the feature gate has been
470 : activated. Rather than feature gate this, we just act
471 : conservatively. */
472 0 : if( FD_UNLIKELY( data_sz<8UL+8UL ) ) break;
473 0 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( ulong, base+8UL ) );
474 0 : break;
475 0 : default:
476 0 : break;
477 240 : }
478 : #if FD_PACK_COST_USE_TRUE_ALLOC_BOUND
479 : } else if( FD_UNLIKELY( in_tbl==upgradeable_loader_row ) ) {
480 : ulong discriminant = ULONG_MAX;
481 : uchar const * base = payload + txn->instr[i].data_off;
482 : if( FD_UNLIKELY( data_sz<8UL ) ) continue;
483 : discriminant = FD_LOAD( uint, base );
484 : base += sizeof(uint); data_sz -= sizeof(uint);
485 : switch( discriminant ) {
486 : case 6UL: /* fd_bpf_upgradeable_loader_program_instruction_enum_extend_program */
487 : case 9UL: /* fd_bpf_upgradeable_loader_program_instruction_enum_extend_program_checked */
488 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( uint, base ) );
489 : break;
490 : default:
491 : allocated_data += DEFAULT_ALLOC; /* Some other instructions may alloc a tiny bit */
492 : break;
493 : }
494 : } else if( FD_UNLIKELY( in_tbl==loader_v4_row ) ) {
495 : ulong discriminant = ULONG_MAX;
496 : uchar const * base = payload + txn->instr[i].data_off;
497 : if( FD_UNLIKELY( data_sz<8UL ) ) continue;
498 : discriminant = FD_LOAD( uint, base );
499 : base += sizeof(uint); data_sz -= sizeof(uint);
500 : switch( discriminant ) {
501 : case 2UL: /* fd_loader_v4_program_instruction_enum_set_program_length */
502 : allocated_data += fd_ulong_min( MAX_ALLOC, FD_LOAD( uint, base ) );
503 : break;
504 : default:
505 : break;
506 : }
507 : } else {
508 : /* This could be the writable accounts only, but this bound is
509 : much cheaper, and good enough. */
510 : allocated_data += DEFAULT_ALLOC * txn->instr[i].acct_cnt;
511 : #endif /* FD_PACK_COST_USE_TRUE_ALLOC_BOUND */
512 240 : }
513 9690543 : }
514 : /* E.g. a transaction can alloc a 10MB account, close it, and repeat
515 : many times. According to the spec, this would count as a 20MB
516 : allocation. See
517 : https://github.com/anza-xyz/agave/blob/2a61a3ecd417b0515c0b2f322d0128394f20626b/cost-model/src/cost_model.rs#L317-L318
518 : */
519 13581330 : allocated_data = fd_ulong_min( allocated_data, 20UL*1024UL*1024UL ); /* MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION */
520 13581330 : #undef MAX_ALLOC
521 13581330 : #undef DEFAULT_ALLOC
522 :
523 13581330 : ulong instr_data_cost = instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE; /* <= 320 */
524 :
525 13581330 : ulong fee[1];
526 13581330 : uint execution_cost[1];
527 13581330 : ulong loaded_account_data_cost[1];
528 13581330 : fd_compute_budget_program_finalize( cbp, txn->instr_cnt, txn->instr_cnt-non_builtin_cnt, fee, execution_cost, loaded_account_data_cost );
529 :
530 : /* As an optimization, for simple votes we can override execution cost
531 : with a known tighter upper bound. */
532 13581330 : if( FD_UNLIKELY( is_simple_vote ) ) *execution_cost = (uint)FD_PACK_VOTE_MAX_COMPUTE_UNITS;
533 :
534 13581330 : fd_ulong_store_if( !!opt_execution_cost, opt_execution_cost, (ulong)(*execution_cost) );
535 13581330 : fd_ulong_store_if( !!opt_fee, opt_fee, *fee );
536 13581330 : fd_ulong_store_if( !!opt_precompile_sig_cnt, opt_precompile_sig_cnt, precompile_sig_cnt );
537 13581330 : fd_ulong_store_if( !!opt_loaded_accounts_data_cost, opt_loaded_accounts_data_cost, *loaded_account_data_cost );
538 13581330 : fd_ulong_store_if( !!opt_allocated_data, opt_allocated_data, allocated_data );
539 :
540 : #if DETAILED_LOGGING
541 : FD_BASE58_ENCODE_64_BYTES( (const uchar *)fd_txn_get_signatures(txn, payload), signature_cstr );
542 : FD_LOG_NOTICE(( "TXN signature[%s] signature_cost[%lu] writable_cost[%lu] instr_data_cost[%lu] non_builtin_cnt[%lu] loaded_account_data_cost[%lu] precompile_sig_cnt[%lu] fee[%lu]",
543 : signature_cstr, signature_cost, writable_cost, instr_data_cost, non_builtin_cnt, *loaded_account_data_cost, precompile_sig_cnt, *fee));
544 : #endif
545 :
546 : /* <= FD_PACK_MAX_COST, so no overflow concerns */
547 13581330 : ulong total_cost = signature_cost + writable_cost + (ulong)(*execution_cost) + instr_data_cost + *loaded_account_data_cost;
548 :
549 : /* Simple votes should always cost at least as much as the old fixed
550 : cost model charged for them. */
551 13581330 : if( FD_UNLIKELY( is_simple_vote ) ) FD_TEST( total_cost>=FD_PACK_FIXED_SIMPLE_VOTE_COST );
552 :
553 13581330 : return total_cost;
554 13581330 : }
555 : #undef MAP_PERFECT_HASH_PP
556 : #undef PERFECT_HASH
557 :
558 : #endif /* HEADER_fd_src_disco_pack_fd_pack_cost_h */
|