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