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 : #include "../fd_flamenco_base.h" 5 : #include "../types/fd_types.h" 6 : #include "../vm/fd_vm_base.h" 7 : #include "fd_system_ids.h" 8 : #include "fd_executor.h" 9 : #include "fd_runtime_const.h" 10 : #include "../../disco/pack/fd_pack.h" 11 : #include "../../disco/pack/fd_pack_cost.h" 12 : 13 : /* fd_cost_tracker_t is a block-level tracker for various limits 14 : including CU consumption, writable account usage, and account data 15 : size. A cost is calculated per-transaction and is accumulated to the 16 : block. If a block's limits are exceeded, then the block is marked as 17 : dead. */ 18 : 19 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L62-L79 */ 20 : 21 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L20 */ 22 33 : #define FD_WRITE_LOCK_UNITS ( 300UL ) 23 : 24 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L42 */ 25 : #define FD_MAX_BLOCK_ACCOUNTS_DATA_SIZE_DELTA ( 100000000UL ) 26 : 27 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L34 */ 28 3 : #define FD_MAX_WRITABLE_ACCOUNT_UNITS ( 12000000UL ) 29 : 30 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L50-L56 */ 31 0 : #define FD_MAX_BLOCK_UNITS_SIMD_0207 ( 50000000UL ) 32 : 33 : /* https://github.com/anza-xyz/agave/blob/v2.3.0/cost-model/src/block_cost_limits.rs#L50-L56 */ 34 0 : #define FD_MAX_BLOCK_UNITS_SIMD_0256 ( 60000000UL ) 35 : 36 : /* https://github.com/anza-xyz/agave/blob/v3.0.0/cost-model/src/block_cost_limits.rs#L30 */ 37 36 : #define FD_MAX_BLOCK_UNITS_SIMD_0286 ( 100000000UL ) 38 : 39 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/block_cost_limits.rs#L38 */ 40 3 : #define FD_MAX_VOTE_UNITS ( 36000000UL ) 41 : 42 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L18-L33 */ 43 0 : #define FD_COST_TRACKER_SUCCESS ( 0 ) 44 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_BLOCK_MAX_LIMIT ( 1 ) 45 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_VOTE_MAX_LIMIT ( 2 ) 46 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_MAX_LIMIT ( 3 ) 47 0 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_BLOCK_LIMIT ( 4 ) 48 : #define FD_COST_TRACKER_ERROR_WOULD_EXCEED_ACCOUNT_DATA_TOTAL_LIMIT ( 5 ) 49 : 50 : /* A reasonably tight bound can be derived based on CUs. The most 51 : optimal use of CUs is to pack as many writable accounts as possible 52 : for as cheaply as possible. This means we should try to pack as many 53 : writable accounts as possible into each transaction. Each 54 : transaction requires at least one signature. We will assume that all 55 : of these accounts have no account data. 56 : 57 : 64 - Max number of accounts per transaction. In this case we will 58 : assume that all of these accounts are writable and have no data. 59 : 100000000 - CUs per slot 60 : 720 - Cost of a signature 61 : 300 - Cost of a writable account write lock 62 : 63 : We can have (100000000 / (720 + 64 * 300)) = 5020 transactions per 64 : slot with maximum writable account utilization. 65 : 66 : So, 5020 transactions per slot * 64 accounts per transaction = 67 : 321280 writable accounts per slot. 68 : 69 : NOTE: A slightly tighter bound can probably be derived. 70 : */ 71 : 72 18 : #define FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT ( \ 73 18 : 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)) ) 74 : FD_STATIC_ASSERT( FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT==321280UL, "Incorrect FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT" ); 75 : 76 : FD_PROTOTYPES_BEGIN 77 : 78 : struct fd_cost_tracker { 79 : ulong magic; 80 : 81 : /* Current accumulated values */ 82 : ulong block_cost; 83 : ulong vote_cost; 84 : ulong allocated_accounts_data_size; 85 : 86 : /* Limits */ 87 : ulong block_cost_limit; 88 : ulong vote_cost_limit; 89 : ulong account_cost_limit; 90 : 91 : ulong pool_offset_; 92 : ulong map_offset_; 93 : }; 94 : typedef struct fd_cost_tracker fd_cost_tracker_t; 95 : 96 : #define FD_COST_TRACKER_ALIGN (128UL) 97 : 98 : struct fd_account_cost { 99 : fd_pubkey_t account; 100 : ulong cost; 101 : ulong next_; 102 : }; 103 : typedef struct fd_account_cost fd_account_cost_t; 104 : 105 : #define FD_COST_TRACKER_CHAIN_CNT_EST (262144UL) 106 : #define FD_COST_TRACKER_FOOTPRINT \ 107 : /* First, layout the struct with alignment */ \ 108 : sizeof(fd_cost_tracker_t) + FD_COST_TRACKER_ALIGN + \ 109 : /* Now layout the pool's data footprint */ \ 110 : FD_COST_TRACKER_ALIGN + sizeof(fd_account_cost_t) * FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_SLOT + \ 111 : /* Now layout the pool's meta footprint */ \ 112 : FD_COST_TRACKER_ALIGN + 128UL /* POOL_ALIGN */ + \ 113 : /* Now layout the map. We must make assumptions about the chain */ \ 114 : /* count to be equivalent to chain_cnt_est. */ \ 115 : FD_COST_TRACKER_ALIGN + 128UL /* MAP_ALIGN */ + (FD_COST_TRACKER_CHAIN_CNT_EST * sizeof(ulong)) 116 3 : #define FD_COST_TRACKER_MAGIC (0xF17EDA2CE7C05170UL) /* FIREDANCER COST V0 */ 117 : 118 : ulong 119 : fd_cost_tracker_footprint( void ); 120 : 121 : ulong 122 : fd_cost_tracker_align( void ); 123 : 124 : void * 125 : fd_cost_tracker_new( void * mem, 126 : fd_features_t const * features, 127 : ulong slot, 128 : ulong seed ); 129 : 130 : fd_cost_tracker_t * 131 : fd_cost_tracker_join( void * mem ); 132 : 133 : /* fd_cost_tracker_calculate_cost_and_add takes a transaction, 134 : calculates the cost of the transaction in terms of various block 135 : level limits and adds it to the cost tracker. If the incremental 136 : transaction fits in the block, then the cost tracking is updated and 137 : FD_COST_TRACKER_SUCCESS is returned. If the transaction does not 138 : fit then FD_COST_TRACKER_ERROR_{*} is returned depending on what 139 : limit is violated. 140 : 141 : This function assumes that the caller is responsible for managing 142 : concurrent callers. 143 : 144 : This function represents the combination of Agave client functions: 145 : `CostModel::calculate_cost_for_executed_transaction()` and 146 : `CostTracker::try_add()`. 147 : 148 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L69-L95 149 : https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_tracker.rs#L163-L173 */ 150 : int 151 : fd_cost_tracker_calculate_cost_and_add( fd_cost_tracker_t * cost_tracker, 152 : fd_exec_txn_ctx_t const * txn_ctx ); 153 : 154 : FD_PROTOTYPES_END 155 : 156 : #endif /* HEADER_fd_src_flamenco_runtime_fd_cost_tracker_h */