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