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_runtime_err.h" 11 : #include "fd_runtime_const.h" 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 414 : #define FD_WRITE_LOCK_UNITS (300U) /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L20 */ 17 : 18 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L18-L33 */ 19 504 : #define FD_COST_TRACKER_SUCCESS (0) 20 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT (1) 21 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT (3) 22 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT (4) 23 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT (5) 24 : 25 : FD_STATIC_ASSERT( FD_WRITE_LOCK_UNITS*FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT + 26 : FD_PACK_COST_PER_SIGNATURE*((FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+63UL)/64UL)<=87500000UL, 27 : max_writable_accounts_per_slot_fits ); 28 : FD_STATIC_ASSERT( FD_WRITE_LOCK_UNITS*(FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+1UL) + 29 : FD_PACK_COST_PER_SIGNATURE*((FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT+64UL)/64UL)>87500000UL, 30 : max_writable_accounts_per_slot_is_tight ); 31 : 32 : /* TODO: Extremely gross. Used because these are in a pool which needs 33 : to be compile time sized T. */ 34 : 35 : /* The average mainnet block uses around 4200 distinct writable 36 : accounts. We size the cost tracker's account map at 8192 chains 37 : to give ~2x headroom over the observed average load. */ 38 816 : #define FD_COST_TRACKER_CHAIN_CNT_EST (8192UL) 39 : #define FD_COST_TRACKER_FOOTPRINT \ 40 : ( FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( \ 41 : FD_LAYOUT_INIT, \ 42 : 128UL /* alignof(fd_cost_tracker_t) */, 128UL /* sizeof(fd_cost_tracker_t) */ ), \ 43 : 128UL /* alignof(cost_tracker_out_t )*/, 128UL /* sizeof(cost_tracker_out_t ) */ ), \ 44 : 8UL /* alignof(account_cost_map_t) */, FD_COST_TRACKER_CHAIN_CNT_EST*4UL /*sizeof(uint)*/ +24UL /* sizeof(account_cost_map_t) */ ), \ 45 : 4UL /* alignof(account_cost_t) */, FD_RUNTIME_MAX_TXN_ACC_WRITES_PER_SLOT*40UL /*sizeof(account_cost_t)*/ ), \ 46 : 128UL ) ) \ 47 : 48 807 : #define FD_COST_TRACKER_MAGIC (0xF17EDA2CE7C05170UL) /* FIREDANCER COST V0 */ 49 : 50 2469 : #define FD_COST_TRACKER_ALIGN (128UL) 51 : 52 : struct __attribute__((aligned(FD_COST_TRACKER_ALIGN))) fd_cost_tracker { 53 : ulong block_cost; 54 : ulong allocated_accounts_data_size; 55 : 56 : ulong block_cost_limit; 57 : ulong account_cost_limit; 58 : ulong data_size_limit; 59 : 60 : int larger_max_cost_per_block; 61 : }; 62 : 63 : typedef struct fd_cost_tracker fd_cost_tracker_t; 64 : 65 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/transaction_cost.rs#L153-L161 */ 66 : 67 : struct fd_usage_cost_details { 68 : uint signature_cost; 69 : uint write_lock_cost; 70 : uint data_bytes_cost; 71 : uint programs_execution_cost; 72 : uint loaded_accounts_data_size_cost; 73 : ulong allocated_accounts_data_size; 74 : }; 75 : typedef struct fd_usage_cost_details fd_usage_cost_details_t; 76 : 77 : struct fd_transaction_cost { 78 : fd_usage_cost_details_t transaction; 79 : }; 80 : 81 : typedef struct fd_transaction_cost fd_transaction_cost_t; 82 : 83 : FD_PROTOTYPES_BEGIN 84 : 85 : static inline int 86 0 : fd_cost_tracker_err_to_runtime_err( int err ) { 87 0 : switch( err ) { 88 0 : case FD_COST_TRACKER_SUCCESS: 89 0 : return FD_RUNTIME_EXECUTE_SUCCESS; 90 0 : case FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT: 91 0 : return FD_RUNTIME_TXN_ERR_WOULD_EXCEED_MAX_BLOCK_COST_LIMIT; 92 0 : case FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT: 93 0 : return FD_RUNTIME_TXN_ERR_WOULD_EXCEED_MAX_ACCOUNT_COST_LIMIT; 94 0 : case FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT: 95 0 : return FD_RUNTIME_TXN_ERR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT; 96 0 : case FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT: 97 0 : return FD_RUNTIME_TXN_ERR_WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT; 98 0 : default: 99 0 : FD_LOG_CRIT(( "unexpected cost tracker error %d", err )); 100 0 : } 101 0 : } 102 : 103 : FD_FN_CONST ulong 104 : fd_cost_tracker_align( void ); 105 : 106 : FD_FN_CONST ulong 107 : fd_cost_tracker_footprint( void ); 108 : 109 : void * 110 : fd_cost_tracker_new( void * shmem, 111 : int larger_max_cost_per_block, 112 : ulong seed ); 113 : 114 : fd_cost_tracker_t * 115 : fd_cost_tracker_join( void * shct ); 116 : 117 : void 118 : fd_cost_tracker_init( fd_cost_tracker_t * cost_tracker, 119 : fd_features_t const * features, 120 : fd_slot_params_t const * slot_params, 121 : ulong slot ); 122 : 123 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */ 124 : FD_FN_PURE uint 125 : fd_cost_tracker_calculate_loaded_accounts_data_size_cost( fd_txn_out_t const * txn_out ); 126 : 127 : /* fd_cost_tracker_calculate_cost_and_add takes a transaction, 128 : calculates the cost of the transaction in terms of various block 129 : level limits and adds it to the cost tracker. If the incremental 130 : transaction fits in the block, then the cost tracking is updated and 131 : FD_COST_TRACKER_SUCCESS is returned. If the transaction does not 132 : fit then FD_COST_TRACKER_ERROR_{*} is returned depending on what 133 : limit is violated. 134 : 135 : This function assumes that the caller is responsible for managing 136 : concurrent callers. 137 : 138 : This function represents the Agave client function: 139 : `CostModel::calculate_cost_for_executed_transaction()` 140 : 141 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L69-L95 142 : */ 143 : 144 : void 145 : fd_cost_tracker_calculate_cost( fd_bank_t * bank, 146 : fd_txn_in_t const * txn_in, 147 : fd_txn_out_t * txn_out ); 148 : 149 : /* fd_cost_tracker_try_add_cost takes the cost as calculated by 150 : fd_cost_tracker_calculate_cost and tries to accumulate it into the 151 : cost tracker. If the cost fits, the cost is added and 152 : FD_COST_TRACKER_SUCCESS is returned. If the cost does not fit, the 153 : cost will not be updated and FD_COST_TRACKER_ERROR_* is returned 154 : depending on what limit is violated. 155 : 156 : This function is the Agave client function: 'CostTracker::try_add()' 157 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L163-L173 */ 158 : 159 : int 160 : fd_cost_tracker_try_add_cost( fd_cost_tracker_t * cost_tracker, 161 : fd_txn_out_t * txn_out ); 162 : 163 : FD_PROTOTYPES_END 164 : 165 : #endif /* HEADER_fd_src_flamenco_runtime_fd_cost_tracker_h */