Line data Source code
1 : #include "fd_cost_tracker.h"
2 : #include "fd_slot_params.h"
3 : #include "fd_system_ids.h"
4 : #include "fd_bank.h"
5 : #include "fd_runtime.h"
6 : #include "fd_executor.h"
7 : #include "../features/fd_features.h"
8 : #include "../vm/fd_vm_base.h"
9 : #include "program/fd_system_program.h"
10 : #include "../../util/fd_hash32.h"
11 :
12 : struct account_cost {
13 : fd_pubkey_t account;
14 : uint cost;
15 :
16 : struct {
17 : uint next;
18 : } map;
19 : };
20 :
21 : typedef struct account_cost account_cost_t;
22 :
23 : #define MAP_NAME account_cost_map
24 : #define MAP_KEY_T fd_pubkey_t
25 : #define MAP_ELE_T account_cost_t
26 285 : #define MAP_KEY account
27 468 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
28 1323 : #define MAP_KEY_HASH(key,seed) (fd_hash32( key->uc, seed ))
29 285 : #define MAP_NEXT map.next
30 7134 : #define MAP_IDX_T uint
31 : #include "../../util/tmpl/fd_map_chain.c"
32 :
33 : struct cost_tracker_outer {
34 : fd_cost_tracker_t cost_tracker[1];
35 : ulong pool_offset;
36 : ulong accounts_used;
37 : ulong magic;
38 : fd_rwlock_t lock;
39 : };
40 :
41 : typedef struct cost_tracker_outer cost_tracker_outer_t;
42 :
43 : FD_FN_CONST ulong
44 2469 : fd_cost_tracker_align( void ) {
45 2469 : return FD_COST_TRACKER_ALIGN;
46 2469 : }
47 :
48 : FD_FN_CONST ulong
49 9 : fd_cost_tracker_footprint( void ) {
50 9 : ulong map_chain_cnt = FD_COST_TRACKER_CHAIN_CNT_EST;
51 :
52 9 : ulong l = FD_LAYOUT_INIT;
53 9 : l = FD_LAYOUT_APPEND( l, fd_cost_tracker_align(), sizeof(cost_tracker_outer_t) );
54 9 : l = FD_LAYOUT_APPEND( l, account_cost_map_align(), account_cost_map_footprint( map_chain_cnt ) );
55 9 : l = FD_LAYOUT_APPEND( l, alignof(account_cost_t), FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT*sizeof(account_cost_t) );
56 9 : return FD_LAYOUT_FINI( l, fd_cost_tracker_align() );
57 9 : }
58 :
59 : void *
60 : fd_cost_tracker_new( void * shmem,
61 : int larger_max_cost_per_block,
62 810 : ulong seed ) {
63 810 : if( FD_UNLIKELY( !shmem ) ) {
64 3 : FD_LOG_WARNING(( "NULL shmem" ));
65 3 : return NULL;
66 3 : }
67 :
68 807 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_cost_tracker_align() ) ) ) {
69 0 : FD_LOG_WARNING(( "misaligned shmem" ));
70 0 : return NULL;
71 0 : }
72 :
73 807 : ulong map_chain_cnt = FD_COST_TRACKER_CHAIN_CNT_EST;
74 :
75 807 : FD_SCRATCH_ALLOC_INIT( l, shmem );
76 807 : cost_tracker_outer_t * cost_tracker = FD_SCRATCH_ALLOC_APPEND( l, fd_cost_tracker_align(), sizeof(cost_tracker_outer_t) );
77 807 : void * _map = FD_SCRATCH_ALLOC_APPEND( l, account_cost_map_align(), account_cost_map_footprint( map_chain_cnt ) );
78 807 : void * _accounts = FD_SCRATCH_ALLOC_APPEND( l, alignof(account_cost_t), FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT*sizeof(account_cost_t) );
79 :
80 807 : account_cost_map_t * map = account_cost_map_join( account_cost_map_new( _map, map_chain_cnt, seed ) );
81 807 : FD_TEST( map );
82 :
83 807 : cost_tracker->pool_offset = (ulong)_accounts-(ulong)cost_tracker;
84 :
85 807 : cost_tracker->cost_tracker->larger_max_cost_per_block = larger_max_cost_per_block;
86 :
87 807 : fd_rwlock_new( &cost_tracker->lock );
88 :
89 807 : (void)_accounts;
90 :
91 807 : FD_COMPILER_MFENCE();
92 807 : FD_VOLATILE( cost_tracker->magic ) = FD_COST_TRACKER_MAGIC;
93 807 : FD_COMPILER_MFENCE();
94 :
95 807 : return shmem;
96 807 : }
97 :
98 : fd_cost_tracker_t *
99 813 : fd_cost_tracker_join( void * shct ) {
100 813 : if( FD_UNLIKELY( !shct ) ) {
101 3 : FD_LOG_WARNING(( "NULL mem" ));
102 3 : return NULL;
103 3 : }
104 :
105 810 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shct, fd_cost_tracker_align() ) ) ) {
106 0 : FD_LOG_WARNING(( "misaligned mem" ));
107 0 : return NULL;
108 0 : }
109 :
110 810 : cost_tracker_outer_t * cost_tracker = (cost_tracker_outer_t *)shct;
111 :
112 810 : if( FD_UNLIKELY( cost_tracker->magic!=FD_COST_TRACKER_MAGIC ) ) {
113 3 : FD_LOG_WARNING(( "Invalid cost tracker magic" ));
114 3 : return NULL;
115 3 : }
116 :
117 807 : return cost_tracker->cost_tracker;
118 810 : }
119 :
120 : void
121 : fd_cost_tracker_init( fd_cost_tracker_t * cost_tracker,
122 : fd_features_t const * features,
123 : fd_slot_params_t const * slot_params,
124 4485 : ulong slot ) {
125 : /* https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/bank.rs#L4809-L4816 */
126 4485 : cost_tracker->block_cost_limit = slot_params->max_block_units;
127 4485 : cost_tracker->account_cost_limit = slot_params->max_writable_account_units;
128 4485 : cost_tracker->data_size_limit = slot_params->max_block_accounts_data_size_delta;
129 :
130 : /* Only the block and account cost limits scale with the block limit
131 : https://github.com/anza-xyz/agave/blob/v4.2/runtime/src/slot_params.rs#L94-L119 */
132 4485 : if( FD_FEATURE_ACTIVE( slot, features, raise_block_limits_to_100m ) ) {
133 9 : cost_tracker->block_cost_limit = fd_ulong_sat_mul( cost_tracker->block_cost_limit, 100UL ) / 60UL;
134 9 : cost_tracker->account_cost_limit = fd_ulong_sat_mul( cost_tracker->account_cost_limit, 100UL ) / 60UL;
135 9 : }
136 :
137 4485 : if( FD_UNLIKELY( cost_tracker->larger_max_cost_per_block ) ) cost_tracker->block_cost_limit = LARGER_MAX_COST_PER_BLOCK;
138 :
139 4485 : cost_tracker->block_cost = 0UL;
140 4485 : cost_tracker->allocated_accounts_data_size = 0UL;
141 :
142 4485 : cost_tracker_outer_t * outer = fd_type_pun( cost_tracker );
143 4485 : outer->accounts_used = 0UL;
144 4485 : account_cost_map_reset( fd_type_pun( outer+1UL ) );
145 4485 : }
146 :
147 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L209-L212 */
148 : FD_FN_PURE static inline uint
149 414 : get_instructions_data_cost( fd_txn_in_t const * txn_in ) {
150 414 : uint total_instr_data_sz = 0U;
151 801 : for( ushort i=0; i<TXN( txn_in->txn )->instr_cnt; i++ ) {
152 387 : total_instr_data_sz += TXN( txn_in->txn )->instr[ i ].data_sz;
153 387 : }
154 414 : return total_instr_data_sz / FD_PACK_INV_COST_PER_INSTR_DATA_BYTE;
155 414 : }
156 :
157 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L147-L178 */
158 : FD_FN_PURE static inline uint
159 414 : get_signature_cost( fd_txn_in_t const * txn_in ) {
160 414 : fd_txn_t const * txn = TXN( txn_in->txn );
161 414 : void const * payload = txn_in->txn->payload;
162 414 : fd_acct_addr_t const * accounts = fd_txn_get_acct_addrs( txn, payload );
163 :
164 : /* Compute signature counts (both normal + precompile)
165 : TODO: Factor this logic out into a shared function that can be used
166 : both here and in fd_pack_cost.h */
167 414 : uint num_secp256k1_instruction_signatures = 0U;
168 414 : uint num_ed25519_instruction_signatures = 0U;
169 414 : uint num_secp256r1_instruction_signatures = 0U;
170 :
171 801 : for( ushort i=0; i<txn->instr_cnt; i++ ) {
172 387 : fd_txn_instr_t const * instr = &txn->instr[ i ];
173 387 : if( instr->data_sz==0UL ) continue;
174 :
175 303 : fd_acct_addr_t const * prog_id = accounts + instr->program_id;
176 303 : uchar const * instr_data = fd_txn_get_instr_data( instr, payload );
177 :
178 303 : if( fd_memeq( prog_id, fd_solana_ed25519_sig_verify_program_id.key, sizeof(fd_pubkey_t) ) ) {
179 0 : num_ed25519_instruction_signatures += (uint)instr_data[ 0 ];
180 303 : } else if( fd_memeq( prog_id, fd_solana_keccak_secp_256k_program_id.key, sizeof(fd_pubkey_t) ) ) {
181 0 : num_secp256k1_instruction_signatures += (uint)instr_data[ 0 ];
182 303 : } else if( fd_memeq( prog_id, fd_solana_secp256r1_program_id.key, sizeof(fd_pubkey_t) ) ) {
183 0 : num_secp256r1_instruction_signatures += (uint)instr_data[ 0 ];
184 0 : }
185 303 : }
186 :
187 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L160-L177 */
188 414 : uint signature_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SIGNATURE, (uint)txn->signature_cnt );
189 414 : uint secp256k1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256K1_SIGNATURE, num_secp256k1_instruction_signatures );
190 414 : uint ed25519_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_ED25519_SIGNATURE, num_ed25519_instruction_signatures );
191 414 : uint secp256r1_verify_cost = fd_uint_sat_mul( FD_PACK_COST_PER_SECP256R1_SIGNATURE, num_secp256r1_instruction_signatures );
192 414 : return fd_uint_sat_add( fd_uint_sat_add( fd_uint_sat_add(
193 414 : signature_cost, secp256k1_verify_cost), ed25519_verify_cost), secp256r1_verify_cost );
194 414 : }
195 :
196 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L180-L183 */
197 : FD_FN_CONST static inline uint
198 414 : get_write_lock_cost( uint num_write_locks ) {
199 414 : return fd_uint_sat_mul( num_write_locks, FD_WRITE_LOCK_UNITS );
200 414 : }
201 :
202 : /* Loop through all instructions here and deserialize the instruction data to try to determine any
203 : system program allocations done.
204 :
205 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L281-L319 */
206 : static inline ulong
207 414 : calculate_allocated_accounts_data_size( fd_bank_t * bank, fd_txn_in_t const * txn_in ) {
208 414 : fd_txn_t const * txn = TXN( txn_in->txn );
209 414 : void const * payload = txn_in->txn->payload;
210 :
211 414 : ulong allocated_accounts_data_size = 0UL;
212 789 : for( ushort i=0; i<txn->instr_cnt; i++ ) {
213 387 : fd_txn_instr_t const * instr = &txn->instr[ i ];
214 387 : fd_acct_addr_t const * accounts = fd_txn_get_acct_addrs( txn, payload );
215 387 : fd_acct_addr_t const * prog_id = accounts + instr->program_id;
216 387 : uchar const * instr_data = fd_txn_get_instr_data( instr, payload );
217 :
218 387 : if( !fd_memeq( prog_id, &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) continue;
219 :
220 147 : fd_system_program_instruction_t instruction = {0};
221 147 : if( FD_UNLIKELY( fd_system_program_instruction_decode( &instruction, instr_data, instr->data_sz ) ) ) return 0UL;
222 :
223 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L330-L346 */
224 144 : ulong space = 0UL;
225 144 : switch( instruction.discriminant ) {
226 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L234 */
227 15 : case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT: {
228 15 : space = instruction.inner.create_account.space;
229 15 : break;
230 0 : }
231 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L235 */
232 0 : case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
233 0 : space = instruction.inner.create_account_with_seed.space;
234 0 : break;
235 0 : }
236 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L236 */
237 39 : case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
238 39 : space = instruction.inner.allocate;
239 39 : break;
240 0 : }
241 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L237 */
242 0 : case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
243 0 : space = instruction.inner.allocate_with_seed.space;
244 0 : break;
245 0 : }
246 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L238-L243 */
247 54 : case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
248 54 : if( !FD_FEATURE_ACTIVE_BANK( bank, create_account_allow_prefund ) ) {
249 3 : return 0UL;
250 3 : }
251 51 : space = instruction.inner.create_account_allow_prefund.space;
252 51 : break;
253 54 : }
254 144 : }
255 :
256 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L225-L231 */
257 141 : if( FD_UNLIKELY( space>FD_RUNTIME_ACC_SZ_MAX ) ) return 0UL;
258 :
259 135 : allocated_accounts_data_size = fd_ulong_sat_add( allocated_accounts_data_size, space );
260 135 : }
261 :
262 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L309-L318 */
263 402 : return fd_ulong_min( 2UL*FD_RUNTIME_ACC_SZ_MAX, allocated_accounts_data_size );
264 414 : }
265 :
266 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L119-L145 */
267 : static inline fd_transaction_cost_t
268 : calculate_transaction_cost( fd_bank_t * bank,
269 : fd_txn_in_t const * txn_in,
270 : fd_txn_out_t const * txn_out,
271 : uint loaded_accounts_data_size_cost,
272 414 : uint data_bytes_cost ) {
273 :
274 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L128 */
275 414 : uint signature_cost = get_signature_cost( txn_in );
276 :
277 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L129 */
278 414 : uint write_lock_cost = get_write_lock_cost( (uint)fd_txn_account_cnt( TXN( txn_in->txn ), FD_TXN_ACCT_CAT_WRITABLE ) );
279 :
280 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L131-L132 */
281 414 : ulong allocated_accounts_data_size = calculate_allocated_accounts_data_size( bank, txn_in );
282 :
283 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L134-L144 */
284 414 : return (fd_transaction_cost_t) {
285 414 : .transaction = {
286 414 : .signature_cost = signature_cost,
287 414 : .write_lock_cost = write_lock_cost,
288 414 : .data_bytes_cost = data_bytes_cost,
289 414 : .allocated_accounts_data_size = allocated_accounts_data_size,
290 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.7/cost-model/src/cost_model.rs#L185-L207 */
291 414 : .programs_execution_cost = fd_uint_sat_sub(
292 414 : (uint)txn_out->details.compute_budget.compute_unit_limit,
293 414 : (uint)txn_out->details.compute_budget.compute_meter ),
294 414 : .loaded_accounts_data_size_cost = loaded_accounts_data_size_cost,
295 414 : }
296 414 : };
297 414 : }
298 :
299 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L26-L42 */
300 : static inline uint
301 504 : transaction_cost_sum( fd_transaction_cost_t const * txn_cost ) {
302 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L164-L171 */
303 504 : fd_usage_cost_details_t const * usage_cost = &txn_cost->transaction;
304 504 : uint cost = 0U;
305 :
306 504 : cost = fd_uint_sat_add( cost, usage_cost->signature_cost );
307 504 : cost = fd_uint_sat_add( cost, usage_cost->write_lock_cost );
308 504 : cost = fd_uint_sat_add( cost, usage_cost->data_bytes_cost );
309 504 : cost = fd_uint_sat_add( cost, usage_cost->programs_execution_cost );
310 504 : cost = fd_uint_sat_add( cost, usage_cost->loaded_accounts_data_size_cost );
311 :
312 504 : return cost;
313 504 : }
314 :
315 : static inline ulong
316 504 : get_allocated_accounts_data_size( fd_transaction_cost_t const * txn_cost ) {
317 504 : return txn_cost->transaction.allocated_accounts_data_size;
318 504 : }
319 :
320 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L277-L322 */
321 : static inline int
322 : would_fit( fd_cost_tracker_t const * cost_tracker,
323 : fd_txn_out_t * txn_out,
324 252 : fd_transaction_cost_t const * tx_cost ) {
325 :
326 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L281 */
327 252 : uint cost = transaction_cost_sum( tx_cost );
328 :
329 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L290-L293 */
330 252 : if( FD_UNLIKELY( fd_ulong_sat_add( cost_tracker->block_cost, cost )>cost_tracker->block_cost_limit ) ) {
331 0 : return FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT;
332 0 : }
333 :
334 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L295-L298 */
335 252 : if( FD_UNLIKELY( cost>cost_tracker->account_cost_limit ) ) {
336 0 : return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
337 0 : }
338 :
339 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L300-L301 */
340 252 : ulong allocated_accounts_data_size = fd_ulong_sat_add( cost_tracker->allocated_accounts_data_size,
341 252 : get_allocated_accounts_data_size( tx_cost ) );
342 :
343 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L303-L304 */
344 252 : if( FD_UNLIKELY( allocated_accounts_data_size>cost_tracker->data_size_limit ) ) {
345 0 : return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT;
346 0 : }
347 :
348 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L308-L319 */
349 :
350 252 : account_cost_map_t const * map = fd_type_pun_const(((cost_tracker_outer_t const *)cost_tracker)+1UL);
351 252 : account_cost_t const * pool = fd_type_pun_const( (void*)((ulong)cost_tracker + ((cost_tracker_outer_t const *)cost_tracker)->pool_offset) );
352 :
353 1467 : for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
354 1215 : if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
355 :
356 519 : fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
357 :
358 519 : account_cost_t const * chained_cost = account_cost_map_ele_query_const( map, writable_acc, NULL, pool );
359 519 : if( FD_UNLIKELY( chained_cost && fd_ulong_sat_add( chained_cost->cost, cost )>cost_tracker->account_cost_limit ) ) {
360 0 : return FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT;
361 0 : }
362 519 : }
363 :
364 252 : return FD_COST_TRACKER_SUCCESS;
365 252 : }
366 :
367 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L352-L372 */
368 : static inline void
369 : add_transaction_execution_cost( fd_cost_tracker_t * _cost_tracker,
370 : fd_txn_out_t * txn_out,
371 252 : uint adjustment ) {
372 252 : cost_tracker_outer_t * cost_tracker = fd_type_pun( _cost_tracker );
373 252 : account_cost_map_t * map = fd_type_pun( cost_tracker+1UL );
374 252 : account_cost_t * pool = fd_type_pun( (void*)((ulong)cost_tracker+cost_tracker->pool_offset) );
375 :
376 1467 : for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
377 1215 : if( FD_UNLIKELY( !txn_out->accounts.is_writable[ i ] ) ) continue;
378 :
379 519 : fd_pubkey_t const * writable_acc = &txn_out->accounts.keys[i];
380 :
381 519 : account_cost_t * account_cost = account_cost_map_ele_query( map, writable_acc, NULL, pool );
382 519 : if( FD_UNLIKELY( !account_cost ) ) {
383 285 : FD_TEST( cost_tracker->accounts_used<FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT );
384 :
385 285 : account_cost = pool+cost_tracker->accounts_used;
386 285 : cost_tracker->accounts_used++;
387 :
388 285 : account_cost->account = *writable_acc;
389 285 : account_cost->cost = adjustment;
390 :
391 285 : account_cost_map_ele_insert( map, account_cost, pool );
392 285 : } else {
393 234 : account_cost->cost = fd_uint_sat_add( account_cost->cost, adjustment );
394 234 : }
395 519 : }
396 :
397 252 : cost_tracker->cost_tracker->block_cost = fd_ulong_sat_add( cost_tracker->cost_tracker->block_cost, adjustment );
398 252 : }
399 :
400 :
401 :
402 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */
403 : FD_FN_PURE uint
404 414 : fd_cost_tracker_calculate_loaded_accounts_data_size_cost( fd_txn_out_t const * txn_out ) {
405 414 : uint cost = fd_uint_sat_sub( fd_uint_sat_add( (uint)txn_out->details.loaded_accounts_data_size,
406 414 : (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE ),
407 414 : 1U );
408 414 : cost /= (uint)FD_ACCOUNT_DATA_COST_PAGE_SIZE;
409 414 : return fd_uint_sat_mul( cost, (uint)FD_VM_HEAP_COST );
410 414 : }
411 :
412 : void
413 : fd_cost_tracker_calculate_cost( fd_bank_t * bank,
414 : fd_txn_in_t const * txn_in,
415 414 : fd_txn_out_t * txn_out ) {
416 414 : fd_transaction_cost_t * txn_cost = &txn_out->details.txn_cost;
417 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L78-L81 */
418 414 : uint loaded_accounts_data_size_cost = fd_cost_tracker_calculate_loaded_accounts_data_size_cost( txn_out );
419 :
420 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L82-L83 */
421 414 : uint instructions_data_cost = get_instructions_data_cost( txn_in );
422 :
423 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L85-L93 */
424 414 : *txn_cost = calculate_transaction_cost( bank, txn_in, txn_out, loaded_accounts_data_size_cost, instructions_data_cost );
425 414 : }
426 :
427 : int
428 : fd_cost_tracker_try_add_cost( fd_cost_tracker_t * cost_tracker,
429 252 : fd_txn_out_t * txn_out ) {
430 :
431 252 : cost_tracker_outer_t * cost_tracker_outer = fd_type_pun( cost_tracker );
432 252 : fd_rwlock_write( &cost_tracker_outer->lock );
433 :
434 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L167 */
435 252 : int err = would_fit( cost_tracker, txn_out, &txn_out->details.txn_cost );
436 252 : if( FD_UNLIKELY( err!=FD_COST_TRACKER_SUCCESS ) ) {
437 0 : fd_rwlock_unwrite( &cost_tracker_outer->lock );
438 0 : return err;
439 0 : }
440 :
441 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L325-L335 */
442 :
443 : /* We don't need `updated_costliest_account_cost` since it seems to be
444 : for a different use case other than validating block cost limits.
445 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L168 */
446 :
447 : /* Note: We purposely omit signature counts updates since they're not relevant to cost calculations right now. */
448 252 : cost_tracker->allocated_accounts_data_size += get_allocated_accounts_data_size( &txn_out->details.txn_cost );
449 252 : add_transaction_execution_cost( cost_tracker, txn_out, transaction_cost_sum( &txn_out->details.txn_cost ) );
450 :
451 252 : fd_rwlock_unwrite( &cost_tracker_outer->lock );
452 252 : return FD_COST_TRACKER_SUCCESS;
453 252 : }
|