diff --git a/contrib/test/test-vectors-commit-sha.txt b/contrib/test/test-vectors-commit-sha.txt index 05eac0743e2..60782e6ee97 100644 --- a/contrib/test/test-vectors-commit-sha.txt +++ b/contrib/test/test-vectors-commit-sha.txt @@ -1 +1 @@ -0a97cc29937eaa6b31e27448f2c43adf758f021c +427914aeaf81891755d7b0eaa443620665b59681 diff --git a/src/flamenco/rewards/fd_rewards.c b/src/flamenco/rewards/fd_rewards.c index 5b49ffa75bf..aa0fb046def 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -166,16 +166,8 @@ calculate_stake_points_and_credits_recalculation( fd_stake_history_t const * new_credits_observed = fd_ulong_max( new_credits_observed, final_epoch_credits ); - fd_delegation_t delegation = { - .voter_pubkey = stake->vote_account, - .stake = stake->stake, - .activation_epoch = stake->activation_epoch, - .deactivation_epoch = stake->deactivation_epoch, - .warmup_cooldown_rate = stake->warmup_cooldown_rate, - }; - ulong stake_amount = fd_stake_activating_and_deactivating( - &delegation, + stake, recalc_vote_state_credits->epoch[ i ], stake_history, new_rate_activation_epoch ).effective; @@ -260,16 +252,8 @@ calculate_stake_points_and_credits( fd_accdb_user_t * accdb, new_credits_observed = fd_ulong_max( new_credits_observed, final_epoch_credits ); - fd_delegation_t delegation = { - .voter_pubkey = stake->vote_account, - .stake = stake->stake, - .activation_epoch = stake->activation_epoch, - .deactivation_epoch = stake->deactivation_epoch, - .warmup_cooldown_rate = stake->warmup_cooldown_rate, - }; - ulong stake_amount = fd_stake_activating_and_deactivating( - &delegation, + stake, ele->epoch, stake_history, new_rate_activation_epoch ).effective; diff --git a/src/flamenco/runtime/fd_bank.c b/src/flamenco/runtime/fd_bank.c index 9dde86ca4ec..3817d05ed24 100644 --- a/src/flamenco/runtime/fd_bank.c +++ b/src/flamenco/runtime/fd_bank.c @@ -865,7 +865,7 @@ fd_banks_stake_delegations_apply_delta( fd_bank_data_t * bank, stake_delegation->activation_epoch, stake_delegation->deactivation_epoch, stake_delegation->credits_observed, - stake_delegation->warmup_cooldown_rate + fd_stake_delegations_warmup_cooldown_rate_to_double( stake_delegation->warmup_cooldown_rate ) ); } else { fd_stake_delegations_remove( stake_delegations_base, &stake_delegation->stake_account ); diff --git a/src/flamenco/runtime/fd_runtime_const.h b/src/flamenco/runtime/fd_runtime_const.h index 8c3011bb0e8..34cc0066a5c 100644 --- a/src/flamenco/runtime/fd_runtime_const.h +++ b/src/flamenco/runtime/fd_runtime_const.h @@ -33,15 +33,6 @@ FD_PROTOTYPES_BEGIN #define FD_RUNTIME_INITIAL_BLOCK_ID (0xF17EDA2CE7B1DUL) -/* The stake program is now a BPF program which means that there is a - variable cost in CUs to execute the stake program. This is the - absolute minimum cost of executing the stake program. - - FIXME: This is a reasonable estimate based off of BPF withdraw - instructions. The hard bound still needs to be determined. */ - -#define FD_RUNTIME_MIN_STAKE_INSN_CUS (6000UL) - /* FD_RUNTIME_ACC_SZ_MAX is the protocol level hardcoded size limit of a Solana account. */ diff --git a/src/flamenco/runtime/program/fd_stake_program.c b/src/flamenco/runtime/program/fd_stake_program.c index 2618d45da55..33fb76a9980 100644 --- a/src/flamenco/runtime/program/fd_stake_program.c +++ b/src/flamenco/runtime/program/fd_stake_program.c @@ -3297,10 +3297,19 @@ fd_stake_get_state( fd_account_meta_t const * meta, } fd_stake_history_entry_t -fd_stake_activating_and_deactivating( fd_delegation_t const * self, - ulong target_epoch, - fd_stake_history_t const * stake_history, - ulong * new_rate_activation_epoch ) { +fd_stake_activating_and_deactivating( fd_stake_delegation_t const * stake_delegation, + ulong target_epoch, + fd_stake_history_t const * stake_history, + ulong * new_rate_activation_epoch ) { + fd_delegation_t delegation = { + .voter_pubkey = stake_delegation->vote_account, + .stake = stake_delegation->stake, + .deactivation_epoch = stake_delegation->deactivation_epoch==USHORT_MAX ? ULONG_MAX : stake_delegation->deactivation_epoch, + .activation_epoch = stake_delegation->activation_epoch==USHORT_MAX ? ULONG_MAX : stake_delegation->activation_epoch, + .warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_to_double( stake_delegation->warmup_cooldown_rate ), + }; + return stake_activating_and_deactivating( - self, target_epoch, stake_history, new_rate_activation_epoch ); + &delegation, target_epoch, stake_history, new_rate_activation_epoch ); } + diff --git a/src/flamenco/runtime/program/fd_stake_program.h b/src/flamenco/runtime/program/fd_stake_program.h index 89e1a2e6626..3f12594e594 100644 --- a/src/flamenco/runtime/program/fd_stake_program.h +++ b/src/flamenco/runtime/program/fd_stake_program.h @@ -41,11 +41,18 @@ int fd_stake_get_state( fd_account_meta_t const * meta, fd_stake_state_v2_t * out ); +/* TODO: This is a temporary hack to reuse stake program code which + should be refactored out when local ledgers no longer rely on the + deprecated native stake program. */ + +struct fd_stake_delegation; +typedef struct fd_stake_delegation fd_stake_delegation_t; + fd_stake_history_entry_t -fd_stake_activating_and_deactivating( fd_delegation_t const * self, - ulong target_epoch, - fd_stake_history_t const * stake_history, - ulong * new_rate_activation_epoch ); +fd_stake_activating_and_deactivating( fd_stake_delegation_t const * self, + ulong target_epoch, + fd_stake_history_t const * stake_history, + ulong * new_rate_activation_epoch ); FD_PROTOTYPES_END diff --git a/src/flamenco/runtime/test_bank.c b/src/flamenco/runtime/test_bank.c index d09647b7d0c..adb72e65727 100644 --- a/src/flamenco/runtime/test_bank.c +++ b/src/flamenco/runtime/test_bank.c @@ -332,7 +332,7 @@ main( int argc, char ** argv ) { the larger combined frontier state. */ fd_stake_delegations_t * stake_delegations = fd_bank_stake_delegations_delta_locking_modify( bank ); - fd_stake_delegations_update( stake_delegations, &key_0, &key_9, 100UL, 100UL, 100UL, 100UL, 100UL ); + fd_stake_delegations_update( stake_delegations, &key_0, &key_9, 100UL, 100UL, 100UL, 100UL, 0.09 ); fd_stake_delegation_t const * stake_delegation = fd_stake_delegations_query( stake_delegations, &key_0 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 1UL ); @@ -382,8 +382,8 @@ main( int argc, char ** argv ) { /* Make updates to delta */ stake_delegations = fd_bank_stake_delegations_delta_locking_modify( bank2 ); - fd_stake_delegations_update( stake_delegations, &key_0, &key_0, 200UL, 100UL, 100UL, 100UL, 100UL ); - fd_stake_delegations_update( stake_delegations, &key_1, &key_8, 100UL, 100UL, 100UL, 100UL, 100UL ); + fd_stake_delegations_update( stake_delegations, &key_0, &key_0, 200UL, 100UL, 100UL, 100UL, 0.09 ); + fd_stake_delegations_update( stake_delegations, &key_1, &key_8, 100UL, 100UL, 100UL, 100UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 2UL ); stake_delegation = fd_stake_delegations_query( stake_delegations, &key_0 ); FD_TEST( stake_delegation ); @@ -417,7 +417,7 @@ main( int argc, char ** argv ) { the updates don't get incorrectly applied. */ stake_delegations = fd_bank_stake_delegations_delta_locking_modify( bank3 ); - fd_stake_delegations_update( stake_delegations, &key_2, &key_7, 10UL, 100UL, 100UL, 100UL, 100UL ); + fd_stake_delegations_update( stake_delegations, &key_2, &key_7, 10UL, 100UL, 100UL, 100UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 1UL ); stake_delegation = fd_stake_delegations_query( stake_delegations, &key_2 ); FD_TEST( stake_delegation ); @@ -483,7 +483,7 @@ main( int argc, char ** argv ) { FD_TEST( fd_bank_capitalization_get( bank7 ) == 2100UL ); stake_delegations = fd_bank_stake_delegations_delta_locking_modify( bank7 ); - fd_stake_delegations_update( stake_delegations, &key_3, &key_6, 7UL, 100UL, 100UL, 100UL, 100UL ); + fd_stake_delegations_update( stake_delegations, &key_3, &key_6, 7UL, 100UL, 100UL, 100UL, 0.09 ); stake_delegation = fd_stake_delegations_query( stake_delegations, &key_3 ); FD_TEST( stake_delegation ); FD_TEST( stake_delegation->stake == 7UL ); @@ -516,7 +516,7 @@ main( int argc, char ** argv ) { FD_TEST( fd_bank_capitalization_get( bank8 ) == 2100UL ); stake_delegations = fd_bank_stake_delegations_delta_locking_modify( bank8 ); - fd_stake_delegations_update( stake_delegations, &key_4, &key_5, 4UL, 100UL, 100UL, 100UL, 100UL ); + fd_stake_delegations_update( stake_delegations, &key_4, &key_5, 4UL, 100UL, 100UL, 100UL, 0.09 ); fd_bank_stake_delegations_delta_end_locking_modify( bank8 ); stake_delegations = fd_bank_stake_delegations_frontier_query( banks, bank8 ); diff --git a/src/flamenco/runtime/test_static_instruction_limit.c b/src/flamenco/runtime/test_static_instruction_limit.c index 2f982fad5ad..2b1218dc6bb 100644 --- a/src/flamenco/runtime/test_static_instruction_limit.c +++ b/src/flamenco/runtime/test_static_instruction_limit.c @@ -101,7 +101,7 @@ main( int argc, fd_boot( &argc, &argv ); char * _page_sz = "normal"; - ulong page_cnt = 1000UL; + ulong page_cnt = 2000UL; ulong numa_idx = fd_shmem_numa_idx( 0 ); fd_wksp_t * wksp = fd_wksp_new_anonymous( fd_cstr_to_shmem_page_sz( _page_sz ), page_cnt, diff --git a/src/flamenco/stakes/fd_stake_delegations.c b/src/flamenco/stakes/fd_stake_delegations.c index e52af25a86a..9ab346825fc 100644 --- a/src/flamenco/stakes/fd_stake_delegations.c +++ b/src/flamenco/stakes/fd_stake_delegations.c @@ -2,9 +2,10 @@ #include "../accdb/fd_accdb_pipe.h" #include "../runtime/program/fd_stake_program.h" -#define POOL_NAME fd_stake_delegation_pool -#define POOL_T fd_stake_delegation_t -#define POOL_NEXT next_ +#define POOL_NAME fd_stake_delegation_pool +#define POOL_T fd_stake_delegation_t +#define POOL_NEXT next_ +#define POOL_IDX_T uint #include "../../util/tmpl/fd_pool.c" #define MAP_NAME fd_stake_delegation_map @@ -14,8 +15,21 @@ #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 )) #define MAP_KEY_HASH(key,seed) (fd_funk_rec_key_hash1( key->uc, seed )) #define MAP_NEXT next_ +#define MAP_IDX_T uint #include "../../util/tmpl/fd_map_chain.c" + +static inline uchar +fd_stake_delegations_warmup_cooldown_rate_enum( double warmup_cooldown_rate ) { + /* TODO: Replace with fd_double_eq */ + if( FD_LIKELY( warmup_cooldown_rate==FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_025 ) ) { + return FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_025; + } else if( FD_LIKELY( warmup_cooldown_rate==FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_009 ) ) { + return FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009; + } + FD_LOG_CRIT(( "Invalid warmup cooldown rate %f", warmup_cooldown_rate )); +} + static inline fd_stake_delegation_t * fd_stake_delegations_get_pool( fd_stake_delegations_t const * stake_delegations ) { return fd_stake_delegation_pool_join( (uchar *)stake_delegations + stake_delegations->pool_offset_ ); @@ -227,10 +241,10 @@ fd_stake_delegations_update( fd_stake_delegations_t * stake_delegations, ulong idx = fd_stake_delegation_map_idx_query_const( stake_delegation_map, stake_account, - ULONG_MAX, + UINT_MAX, stake_delegation_pool ); - if( idx!=ULONG_MAX ) { + if( idx!=UINT_MAX ) { fd_stake_delegation_t * stake_delegation = fd_stake_delegation_pool_ele( stake_delegation_pool, idx ); if( FD_UNLIKELY( !stake_delegation ) ) { @@ -239,10 +253,10 @@ fd_stake_delegations_update( fd_stake_delegations_t * stake_delegations, stake_delegation->vote_account = *vote_account; stake_delegation->stake = stake; - stake_delegation->activation_epoch = activation_epoch; - stake_delegation->deactivation_epoch = deactivation_epoch; + stake_delegation->activation_epoch = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX ); + stake_delegation->deactivation_epoch = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX ); stake_delegation->credits_observed = credits_observed; - stake_delegation->warmup_cooldown_rate = warmup_cooldown_rate; + stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate ); stake_delegation->is_tombstone = 0; return; } @@ -257,10 +271,10 @@ fd_stake_delegations_update( fd_stake_delegations_t * stake_delegations, stake_delegation->stake_account = *stake_account; stake_delegation->vote_account = *vote_account; stake_delegation->stake = stake; - stake_delegation->activation_epoch = activation_epoch; - stake_delegation->deactivation_epoch = deactivation_epoch; + stake_delegation->activation_epoch = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX ); + stake_delegation->deactivation_epoch = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX ); stake_delegation->credits_observed = credits_observed; - stake_delegation->warmup_cooldown_rate = warmup_cooldown_rate; + stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate ); stake_delegation->is_tombstone = 0; if( FD_UNLIKELY( !fd_stake_delegation_map_ele_insert( @@ -287,7 +301,7 @@ fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations, ulong delegation_idx = fd_stake_delegation_map_idx_query( stake_delegation_map, stake_account, - ULONG_MAX, + UINT_MAX, stake_delegation_pool ); if( stake_delegations->leave_tombstones_==1 ) { @@ -295,7 +309,7 @@ fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations, update the entry's is_tombstone flag or insert a new entry. */ fd_stake_delegation_t * stake_delegation = NULL; - if( delegation_idx!=ULONG_MAX ) { + if( delegation_idx!=UINT_MAX ) { /* The delegation was found, update the is_tombstone flag. */ stake_delegation = fd_stake_delegation_pool_ele( stake_delegation_pool, delegation_idx ); } else { @@ -310,7 +324,7 @@ fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations, } else { /* If we are not configured to leave tombstones, we need to remove the entry from the map and release it from the pool. */ - if( FD_UNLIKELY( delegation_idx == ULONG_MAX ) ) { + if( FD_UNLIKELY( delegation_idx==UINT_MAX ) ) { /* The delegation was not found, nothing to do. */ return; } @@ -322,12 +336,12 @@ fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations, FD_LOG_CRIT(( "unable to retrieve stake delegation" )); } - ulong idx = fd_stake_delegation_map_idx_remove( stake_delegation_map, stake_account, ULONG_MAX, stake_delegation_pool ); - if( FD_UNLIKELY( idx==ULONG_MAX ) ) { + ulong idx = fd_stake_delegation_map_idx_remove( stake_delegation_map, stake_account, UINT_MAX, stake_delegation_pool ); + if( FD_UNLIKELY( idx==UINT_MAX ) ) { FD_LOG_CRIT(( "unable to remove stake delegation" )); } - stake_delegation->next_ = fd_stake_delegation_pool_idx_null( stake_delegation_pool ); + stake_delegation->next_ = UINT_MAX; fd_stake_delegation_pool_idx_release( stake_delegation_pool, delegation_idx ); } @@ -385,7 +399,7 @@ fd_stake_delegations_refresh( fd_stake_delegations_t * stake_delegations, continue; /* ok */ remove: - fd_stake_delegation_map_idx_remove( map, address, ULONG_MAX, pool ); + fd_stake_delegation_map_idx_remove( map, address, UINT_MAX, pool ); fd_stake_delegation_pool_ele_release( pool, delegation ); } } diff --git a/src/flamenco/stakes/fd_stake_delegations.h b/src/flamenco/stakes/fd_stake_delegations.h index ed328dd2a1d..96fcf0fca8e 100644 --- a/src/flamenco/stakes/fd_stake_delegations.h +++ b/src/flamenco/stakes/fd_stake_delegations.h @@ -60,47 +60,31 @@ reward distribution. The stake accounts are read-only during the epoch boundary. */ -/* The max number of stake accounts that can be modified in a current - slot from transactions can be bounded based on CU consumption. The - best strategy to maximize the max number of stake accounts modified - in a single transaction. A stake program instruction can either - modify one or two stake accounts. Stake program instructions that - modify two stake accounts (merge/split) are assumed to be at least 2x - as expensive as a stake program instruction that modifies one stake - account. So we will assume that the most efficient strategy is to - modify one stake account per instruction and have as many instruction - as posssible in this transaction. We can have 63 stake program - instructions in this transaction because one account will be the fee - payer/signature and the other 63 are free to be writable accounts. - - Given the above: - 100000000 - CUs per slot - 64 - Max number of writable accounts per transaction. - 63 - Max number of writable stake accounts per transaction. - 720 - Cost of a signature - 300 - Cost of a writable account lock. - 6000 - Cost of a stake program instruction. - - We can have (100000000 / (720 + 300 * 64 + 6000 * 63)) = 251 - optimal stake program transactions per slot. With 63 stake accounts - per transaction, we can have 251 * 63 = 15813 stake accounts modified - in a slot. */ - -#define MAX_OPTIMAL_STAKE_ACCOUNTS_POSSIBLE_IN_TXN (FD_MAX_BLOCK_UNITS_SIMD_0286/(FD_WRITE_LOCK_UNITS * FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION + FD_RUNTIME_MIN_STAKE_INSN_CUS * (FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION - 1UL) + FD_PACK_COST_PER_SIGNATURE)) -FD_STATIC_ASSERT(MAX_OPTIMAL_STAKE_ACCOUNTS_POSSIBLE_IN_TXN==251, "Incorrect MAX_STAKE_ACCOUNTS_POSSIBLE_IN_TXN"); -#define MAX_STAKE_ACCOUNTS_POSSIBLE_IN_SLOT_FROM_TXNS (MAX_OPTIMAL_STAKE_ACCOUNTS_POSSIBLE_IN_TXN * (FD_RUNTIME_MAX_WRITABLE_ACCOUNTS_PER_TRANSACTION - 1UL)) -FD_STATIC_ASSERT(MAX_STAKE_ACCOUNTS_POSSIBLE_IN_SLOT_FROM_TXNS==15813, "Incorrect MAX_STAKE_ACCOUNTS_PER_SLOT"); +/* The max number of stake accounts that can be modified in a single + slot from transactions can be conservatively bounded based on bounds + set by the cost tracker: the max writable account CUs per slot. This + bound is set at 12M CUs and each writable account costs 300 CUs. + Very loosely this would give us 12M/300 = 40000 stake accounts per + slot. A tighter bound can be found by considering the fee payer must + be writable as well and can not be a stake account. We can have 64 + unique writable accounts per transaction. So the best utilization of + transactions are ones where 63/64 stake accounts are writable. This + gives us 40000 * 63/64 = 39375 stake accounts per slot. */ + +#define MAX_STAKE_ACCOUNTS_IN_SLOT_FROM_TXNS (FD_MAX_WRITABLE_ACCOUNT_UNITS/FD_PACK_COST_PER_WRITABLE_ACCT * (FD_RUNTIME_WRITABLE_ACCOUNTS_MAX - 1UL)/FD_RUNTIME_WRITABLE_ACCOUNTS_MAX) +FD_STATIC_ASSERT( MAX_STAKE_ACCOUNTS_IN_SLOT_FROM_TXNS==39375UL, "Incorrect MAX_STAKE_ACCOUNTS_IN_SLOT_FROM_TXNS" ); /* The static footprint of fd_stake_delegations_t when it is a delta is determined by the max total number of stake accounts that can get changed in a single slot. Stake accounts can get modified in two ways: - 1. Through transactions. This bound is calculated using CU - consumption as described above. + 1. Through transactions. This bound is calculated using CU bounds set + by the cost tracker as described above. 2. Through epoch rewards. This is a protocol-level bound is defined in fd_rewards_base.h and is the max number of stake accounts that can reside in a single reward partition. */ -#define FD_STAKE_DELEGATIONS_MAX_PER_SLOT (MAX_STAKE_ACCOUNTS_POSSIBLE_IN_SLOT_FROM_TXNS + STAKE_ACCOUNT_STORES_PER_BLOCK) +#define FD_STAKE_DELEGATIONS_MAX_PER_SLOT (MAX_STAKE_ACCOUNTS_IN_SLOT_FROM_TXNS + STAKE_ACCOUNT_STORES_PER_BLOCK) +FD_STATIC_ASSERT( FD_STAKE_DELEGATIONS_MAX_PER_SLOT==43471UL, "Incorrect FD_STAKE_DELEGATIONS_MAX_PER_SLOT" ); /* The static footprint of the vote states assumes that there are FD_RUNTIME_MAX_STAKE_ACCOUNTS. It also assumes worst case alignment @@ -126,13 +110,11 @@ FD_STATIC_ASSERT(MAX_STAKE_ACCOUNTS_POSSIBLE_IN_SLOT_FROM_TXNS==15813, "Incorrec FD_STAKE_DELEGATIONS_ALIGN + 128UL /* MAP_ALIGN */ + (FD_STAKE_DELEGATIONS_CHAIN_CNT_EST * sizeof(ulong)) /* We need a footprint for the max amount of stake delegations that - can be added in a single slot. We know that there can be up to - 8192 writable accounts in a slot (bound determined from the cost - tracker). Using the same calculation as above, we get 120 bytes per - stake delegation with up to ~19K delegations we have a total - footprint of ~2.5MB. */ + can be added in a single slot. Based on the above calculation we can + have roughly ~43k stake delegations in a single slot in the worst + case. This leaves us with roughly 4.3MB per slot. */ -#define FD_STAKE_DELEGATIONS_DELTA_CHAIN_CNT_EST (16384UL) +#define FD_STAKE_DELEGATIONS_DELTA_CHAIN_CNT_EST (32768UL) #define FD_STAKE_DELEGATIONS_DELTA_FOOTPRINT \ /* First, layout the struct with alignment */ \ sizeof(fd_stake_delegations_t) + alignof(fd_stake_delegations_t) + \ @@ -146,16 +128,24 @@ FD_STATIC_ASSERT(MAX_STAKE_ACCOUNTS_POSSIBLE_IN_SLOT_FROM_TXNS==15813, "Incorrec #define FD_STAKE_DELEGATIONS_ALIGN (128UL) +/* The warmup cooldown rate can only be one of two values: 0.25 or 0.09. + The reason that the double is mapped to an enum is to save space in + the stake delegations struct. */ +#define FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_025 (0) +#define FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 (1) +#define FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_025 (0.25) +#define FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_009 (0.09) + struct fd_stake_delegation { fd_pubkey_t stake_account; fd_pubkey_t vote_account; - ulong next_; /* Only for internal pool/map usage */ ulong stake; - ulong activation_epoch; - ulong deactivation_epoch; ulong credits_observed; - double warmup_cooldown_rate; - int is_tombstone; + uint next_; /* Only for internal pool/map usage */ + ushort activation_epoch; + ushort deactivation_epoch; + uchar is_tombstone; + uchar warmup_cooldown_rate; /* enum representing 0.25 or 0.09 */ }; typedef struct fd_stake_delegation fd_stake_delegation_t; @@ -180,6 +170,11 @@ typedef struct fd_stake_delegations_iter fd_stake_delegations_iter_t; FD_PROTOTYPES_BEGIN +static inline double +fd_stake_delegations_warmup_cooldown_rate_to_double( uchar warmup_cooldown_rate ) { + return warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_025 ? FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_025 : FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_009; +} + /* fd_stake_delegations_align returns the alignment of the stake delegations struct. */ diff --git a/src/flamenco/stakes/fd_stakes.c b/src/flamenco/stakes/fd_stakes.c index 433f093da08..5c38ca4032d 100644 --- a/src/flamenco/stakes/fd_stakes.c +++ b/src/flamenco/stakes/fd_stakes.c @@ -56,16 +56,8 @@ fd_refresh_vote_accounts( fd_bank_t * bank, fd_stake_delegations_iter_next( iter ) ) { fd_stake_delegation_t const * stake_delegation = fd_stake_delegations_iter_ele( iter ); - fd_delegation_t delegation = { - .voter_pubkey = stake_delegation->vote_account, - .stake = stake_delegation->stake, - .deactivation_epoch = stake_delegation->deactivation_epoch, - .activation_epoch = stake_delegation->activation_epoch, - .warmup_cooldown_rate = stake_delegation->warmup_cooldown_rate, - }; - fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( - &delegation, + stake_delegation, epoch, history, new_rate_activation_epoch ); @@ -117,16 +109,8 @@ fd_stakes_activate_epoch( fd_bank_t * bank, fd_stake_delegations_iter_next( iter ) ) { fd_stake_delegation_t const * stake_delegation = fd_stake_delegations_iter_ele( iter ); - fd_delegation_t delegation = { - .voter_pubkey = stake_delegation->vote_account, - .stake = stake_delegation->stake, - .activation_epoch = stake_delegation->activation_epoch, - .deactivation_epoch = stake_delegation->deactivation_epoch, - .warmup_cooldown_rate = stake_delegation->warmup_cooldown_rate, - }; - fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( - &delegation, + stake_delegation, fd_bank_epoch_get( bank ), stake_history, new_rate_activation_epoch ); diff --git a/src/flamenco/stakes/test_stake_delegations.c b/src/flamenco/stakes/test_stake_delegations.c index e088f1d898f..b2537f5a7f1 100644 --- a/src/flamenco/stakes/test_stake_delegations.c +++ b/src/flamenco/stakes/test_stake_delegations.c @@ -64,11 +64,11 @@ int main( int argc, char ** argv ) { fd_pubkey_t voter_pubkey_1 = { .ul = { 7, 8 } }; FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 0UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 1UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 200UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 200UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 2UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_2, &voter_pubkey_1, 300UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_2, &voter_pubkey_1, 300UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 3UL ); fd_stake_delegation_t const * stake_delegation_0 = fd_stake_delegations_query( stake_delegations, &stake_account_0 ); @@ -78,7 +78,7 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegation_0->stake == 100UL ); FD_TEST( stake_delegation_0->activation_epoch == 0UL ); FD_TEST( stake_delegation_0->deactivation_epoch == 0UL ); - FD_TEST( stake_delegation_0->warmup_cooldown_rate == 0.0 ); + FD_TEST( stake_delegation_0->warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 ); fd_stake_delegation_t const * stake_delegation_1 = fd_stake_delegations_query( stake_delegations, &stake_account_1 ); FD_TEST( stake_delegation_1 ); @@ -87,7 +87,7 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegation_1->stake == 200UL ); FD_TEST( stake_delegation_1->activation_epoch == 0UL ); FD_TEST( stake_delegation_1->deactivation_epoch == 0UL ); - FD_TEST( stake_delegation_1->warmup_cooldown_rate == 0.0 ); + FD_TEST( stake_delegation_1->warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 ); fd_stake_delegation_t const * stake_delegation_2 = fd_stake_delegations_query( stake_delegations, &stake_account_2 ); FD_TEST( stake_delegation_2 ); @@ -96,25 +96,25 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegation_2->stake == 300UL ); FD_TEST( stake_delegation_2->activation_epoch == 0UL ); FD_TEST( stake_delegation_2->deactivation_epoch == 0UL ); - FD_TEST( stake_delegation_2->warmup_cooldown_rate == 0.0 ); + FD_TEST( stake_delegation_2->warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 ); FD_TEST( !fd_stake_delegations_query( stake_delegations, &stake_account_3 ) ); - fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 200UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 200UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( stake_delegation_0 ); FD_TEST( !memcmp( &stake_delegation_0->stake_account, &stake_account_0, sizeof(fd_pubkey_t) ) ); FD_TEST( !memcmp( &stake_delegation_0->vote_account, &voter_pubkey_0, sizeof(fd_pubkey_t) ) ); FD_TEST( stake_delegation_0->stake == 200UL ); FD_TEST( stake_delegation_0->activation_epoch == 0UL ); FD_TEST( stake_delegation_0->deactivation_epoch == 0UL ); - FD_TEST( stake_delegation_0->warmup_cooldown_rate == 0.0 ); + FD_TEST( stake_delegation_0->warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 3UL ); fd_stake_delegations_remove( stake_delegations, &stake_account_1 ); FD_TEST( !fd_stake_delegations_query( stake_delegations, &stake_account_1 ) ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 2UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 10000UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 10000UL, 0UL, 0UL, 0UL, 0.09 ); stake_delegation_1 = fd_stake_delegations_query( stake_delegations, &stake_account_1 ); FD_TEST( stake_delegation_1 ); FD_TEST( !memcmp( &stake_delegation_1->stake_account, &stake_account_1, sizeof(fd_pubkey_t) ) ); @@ -122,7 +122,7 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegation_1->stake == 10000UL ); FD_TEST( stake_delegation_1->activation_epoch == 0UL ); FD_TEST( stake_delegation_1->deactivation_epoch == 0UL ); - FD_TEST( stake_delegation_1->warmup_cooldown_rate == 0.0 ); + FD_TEST( stake_delegation_1->warmup_cooldown_rate == FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_009 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 3UL ); FD_TEST( !fd_stake_delegations_delete( NULL ) ); @@ -135,9 +135,9 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegations ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 0UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 1UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 200UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_1, &voter_pubkey_1, 200UL, 0UL, 0UL, 0UL, 0.09 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 2UL ); fd_stake_delegation_t const * stake_delegation = fd_stake_delegations_query( stake_delegations, &stake_account_0 ); FD_TEST( stake_delegation ); @@ -158,7 +158,7 @@ int main( int argc, char ** argv ) { FD_TEST( stake_delegation->is_tombstone == 1 ); FD_TEST( fd_stake_delegations_cnt( stake_delegations ) == 3UL ); - fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.0 ); + fd_stake_delegations_update( stake_delegations, &stake_account_0, &voter_pubkey_0, 100UL, 0UL, 0UL, 0UL, 0.09 ); stake_delegation = fd_stake_delegations_query( stake_delegations, &stake_account_0 ); FD_TEST( stake_delegation ); FD_TEST( stake_delegation->is_tombstone == 0 ); diff --git a/src/flamenco/vm/test_vm_interp.c b/src/flamenco/vm/test_vm_interp.c index c1e86ce9204..40c53702504 100644 --- a/src/flamenco/vm/test_vm_interp.c +++ b/src/flamenco/vm/test_vm_interp.c @@ -480,6 +480,7 @@ main( int argc, fd_runtime_t * runtime = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_t), sizeof(fd_runtime_t), wksp_tag ); FD_TEST( runtime ); + fd_bank_data_t * bank_data = fd_wksp_alloc_laddr( wksp, alignof(fd_bank_data_t), sizeof(fd_bank_data_t), wksp_tag ); fd_rng_t _rng[1]; fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, 0U, 0UL ) ); @@ -487,7 +488,6 @@ main( int argc, fd_exec_instr_ctx_t instr_ctx[1]; fd_bank_t bank[1]; - fd_bank_data_t bank_data[1]; fd_banks_locks_t bank_locks[1]; fd_txn_out_t txn_out[1]; test_vm_minimal_exec_instr_ctx( instr_ctx, runtime, bank, bank_data, bank_locks, txn_out );