Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_runtime_fd_cost_tracker_h 2 : #define HEADER_fd_src_flamenco_runtime_fd_cost_tracker_h 3 : 4 : /* fd_cost_tracker_t is a block-level tracker for various limits 5 : including CU consumption, writable account usage, and account data 6 : size. A cost is calculated per-transaction and is accumulated to the 7 : block. If a block's limits are exceeded, then the block is marked as 8 : dead. */ 9 : 10 : #include "fd_executor.h" 11 : #include "../../disco/pack/fd_pack.h" /* TODO: Layering violation */ 12 : #include "../../disco/pack/fd_pack_cost.h" 13 : 14 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L62-L79 */ 15 : 16 39 : #define FD_WRITE_LOCK_UNITS ( 300UL) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L20 */ 17 : #define FD_MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA (100000000UL) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L42 */ 18 0 : #define FD_MAX_WRITABLE_ACCOUNT_UNITS ( 12000000UL) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L34 */ 19 0 : #define FD_MAX_BLOCK_UNITS_SIMD_0207 ( 50000000UL) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L50-L56 */ 20 0 : #define FD_MAX_BLOCK_UNITS_SIMD_0256 ( 60000000UL) /* https://github.com/anza-xyz/agave/blob/v2.3.0/cost-model/src/block_cost_limits.rs#L50-L56 */ 21 39 : #define FD_MAX_BLOCK_UNITS_SIMD_0286 (100000000UL) /* https://github.com/anza-xyz/agave/blob/v3.0.0/cost-model/src/block_cost_limits.rs#L30 */ 22 0 : #define FD_MAX_VOTE_UNITS ( 36000000UL) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L38 */ 23 : 24 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L18-L33 */ 25 0 : #define FD_COST_TRACKER_SUCCESS (0) 26 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT (1) 27 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_VOTE_MAX_LIMIT (2) 28 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT (3) 29 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT (4) 30 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT (5) 31 : 32 : /* A reasonably tight bound can be derived based on CUs. The most 33 : optimal use of CUs is to pack as many writable accounts as possible 34 : for as cheaply as possible. This means we should try to pack as many 35 : writable accounts as possible into each transaction. Each 36 : transaction requires at least one signature. We will assume that all 37 : of these accounts have no account data. 38 : 39 : 64 - Max number of accounts per transaction. In this case we will 40 : assume that all of these accounts are writable and have no data. 41 : 100000000 - CUs per slot 42 : 720 - Cost of a signature 43 : 300 - Cost of a writable account write lock 44 : 45 : We can have (100000000 / (720 + 64 * 300)) = 5020 transactions per 46 : slot with maximum writable account utilization. 47 : 48 : So, 5020 transactions per slot * 64 accounts per transaction = 49 : 321280 writable accounts per slot. 50 : 51 : NOTE: A slightly tighter bound can probably be derived. */ 52 : 53 24 : #define FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ( \ 54 24 : FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION * (FD_MAX_BLOCK_UNITS_SIMD_0286 / ( FD_WRITE_LOCK_UNITS * FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION + FD_PACK_COST_PER_SIGNATURE)) ) 55 : FD_STATIC_ASSERT( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT==321280UL, "Incorrect FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT" ); 56 : 57 : /* TODO: Extremely gross. Used because these are in a pool which needs 58 : to be compile time sized T. */ 59 : #define FD_COST_TRACKER_CHAIN_CNT_EST (262144UL) 60 : #define FD_COST_TRACKER_FOOTPRINT \ 61 : ( FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( \ 62 : FD_LAYOUT_INIT, \ 63 : 128UL /* alignof(fd_cost_tracker_t) */, 128UL /* sizeof(fd_cost_tracker_t) */ ), \ 64 : 128UL /* alignof(cost_tracker_out_t )*/, 128UL /* sizeof(cost_tracker_out_t ) */ ), \ 65 : 8UL /* alignof(account_cost_map_t) */, FD_COST_TRACKER_CHAIN_CNT_EST*8UL /*sizeof(ulong)*/ +24UL /* sizeof(account_cost_map_t) */ ), \ 66 : 8UL /* alignof(account_cost_t) */, FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT*48UL /*sizeof(account_cost_t)*/ ), \ 67 : 128UL ) ) \ 68 : 69 : #define FD_COST_TRACKER_MAGIC (0xF17EDA2CE7C05170UL) /* FIREDANCER COST V0 */ 70 : 71 108 : #define FD_COST_TRACKER_ALIGN (128UL) 72 : 73 15 : #define FD_COST_TRACKER_MAGIC (0xF17EDA2CE7C05170UL) /* FIREDANCER COST V0 */ 74 : 75 : struct __attribute__((aligned(FD_COST_TRACKER_ALIGN))) fd_cost_tracker { 76 : ulong block_cost; 77 : ulong vote_cost; 78 : ulong allocated_accounts_data_size; 79 : 80 : ulong block_cost_limit; 81 : ulong vote_cost_limit; 82 : ulong account_cost_limit; 83 : }; 84 : 85 : typedef struct fd_cost_tracker fd_cost_tracker_t; 86 : 87 : FD_PROTOTYPES_BEGIN 88 : 89 : FD_FN_CONST ulong 90 : fd_cost_tracker_align( void ); 91 : 92 : FD_FN_CONST ulong 93 : fd_cost_tracker_footprint( void ); 94 : 95 : void * 96 : fd_cost_tracker_new( void * shmem, 97 : ulong seed ); 98 : 99 : fd_cost_tracker_t * 100 : fd_cost_tracker_join( void * shct ); 101 : 102 : void 103 : fd_cost_tracker_init( fd_cost_tracker_t * cost_tracker, 104 : fd_features_t const * features, 105 : ulong slot ); 106 : 107 : ulong 108 : fd_cost_tracker_block_cost_limit( fd_bank_t const * bank ); 109 : 110 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */ 111 : FD_FN_PURE static inline ulong 112 0 : fd_cost_tracker_calculate_loaded_accounts_data_size_cost( fd_exec_txn_ctx_t const * txn_ctx ) { 113 0 : ulong cost = fd_ulong_sat_sub( fd_ulong_sat_add( txn_ctx->loaded_accounts_data_size, 114 0 : FD_ACCOUNT_DATA_COST_PAGE_SIZE ), 115 0 : 1UL ); 116 0 : cost /= FD_ACCOUNT_DATA_COST_PAGE_SIZE; 117 0 : return fd_ulong_sat_mul( cost, FD_VM_HEAP_COST ); 118 0 : } 119 : 120 : /* fd_cost_tracker_calculate_cost_and_add takes a transaction, 121 : calculates the cost of the transaction in terms of various block 122 : level limits and adds it to the cost tracker. If the incremental 123 : transaction fits in the block, then the cost tracking is updated and 124 : FD_COST_TRACKER_SUCCESS is returned. If the transaction does not 125 : fit then FD_COST_TRACKER_ERROR_{*} is returned depending on what 126 : limit is violated. 127 : 128 : This function assumes that the caller is responsible for managing 129 : concurrent callers. 130 : 131 : This function represents the combination of Agave client functions: 132 : `CostModel::calculate_cost_for_executed_transaction()` and 133 : `CostTracker::try_add()`. 134 : 135 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L69-L95 136 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L163-L173 */ 137 : 138 : int 139 : fd_cost_tracker_calculate_cost_and_add( fd_cost_tracker_t * cost_tracker, 140 : fd_exec_txn_ctx_t const * txn_ctx ); 141 : 142 : FD_PROTOTYPES_END 143 : 144 : #endif /* HEADER_fd_src_flamenco_runtime_fd_cost_tracker_h */