diff --git a/src/disco/gui/fd_gui_tile.c b/src/disco/gui/fd_gui_tile.c index ae4d4b4df34..5dba3b7ac23 100644 --- a/src/disco/gui/fd_gui_tile.c +++ b/src/disco/gui/fd_gui_tile.c @@ -376,7 +376,7 @@ after_frag( fd_gui_ctx_t * ctx, ctx->peers->votes[ vote_count ].stake = vote_state->stake; ctx->peers->votes[ vote_count ].last_vote_slot = vote_state->last_vote_slot; ctx->peers->votes[ vote_count ].last_vote_timestamp = vote_state->last_vote_timestamp; - ctx->peers->votes[ vote_count ].commission = vote_state->commission; + ctx->peers->votes[ vote_count ].commission = (uchar)(vote_state->commission_bps / 100U); // ctx->peers->votes[ vote_count ].epoch = fd_ulong_if( !vote_state->credits_cnt, ULONG_MAX, vote_state->epoch[ 0 ] ); // ctx->peers->votes[ vote_count ].epoch_credits = fd_ulong_if( !vote_state->credits_cnt, ULONG_MAX, vote_state->credits[ 0 ] ); diff --git a/src/discof/restore/utils/fd_ssload.c b/src/discof/restore/utils/fd_ssload.c index bf748a43d07..cb92954cffb 100644 --- a/src/discof/restore/utils/fd_ssload.c +++ b/src/discof/restore/utils/fd_ssload.c @@ -221,7 +221,7 @@ fd_ssload_recover( fd_snapshot_manifest_t * manifest, fd_vote_state_ele_t * vote_state = fd_vote_states_update( vote_stakes_prev, (fd_pubkey_t *)elem->vote ); vote_state->node_account = *(fd_pubkey_t *)elem->identity; - vote_state->commission = elem->commission; + vote_state->commission_bps = (ushort)(elem->commission * 100U); vote_state->last_vote_timestamp = elem->timestamp; vote_state->last_vote_slot = elem->slot; vote_state->stake = elem->stake; @@ -259,7 +259,7 @@ fd_ssload_recover( fd_snapshot_manifest_t * manifest, if( FD_UNLIKELY( !elem->stake ) ) continue; fd_vote_state_ele_t * vote_state = fd_vote_states_update( vote_stakes_prev_prev, (fd_pubkey_t *)elem->vote ); vote_state->node_account = *(fd_pubkey_t *)elem->identity; - vote_state->commission = elem->commission; + vote_state->commission_bps = (ushort)(elem->commission * 100U); vote_state->last_vote_timestamp = elem->timestamp; vote_state->last_vote_slot = elem->slot; vote_state->stake = elem->stake; @@ -280,7 +280,7 @@ fd_ssload_recover( fd_snapshot_manifest_t * manifest, fd_vote_state_ele_t * vote_state = fd_vote_states_update( vote_states, (fd_pubkey_t *)elem->vote_account_pubkey ); vote_state->node_account = *(fd_pubkey_t *)elem->node_account_pubkey; - vote_state->commission = elem->commission; + vote_state->commission_bps = (ushort)(elem->commission * 100U); vote_state->last_vote_timestamp = elem->last_timestamp; vote_state->last_vote_slot = elem->last_slot; vote_state->stake = elem->stake; diff --git a/src/flamenco/features/fd_features_generated.c b/src/flamenco/features/fd_features_generated.c index cddd02fa8c5..71924755ae8 100644 --- a/src/flamenco/features/fd_features_generated.c +++ b/src/flamenco/features/fd_features_generated.c @@ -1763,6 +1763,12 @@ fd_feature_id_t const ids[] = { .name = "delay_commission_updates", .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = offsetof(fd_features_t, commission_rate_in_basis_points)>>3, + .id = {"\xcb\x2d\x5e\xc6\xdb\xd8\x88\xd3\xda\xf5\x45\x1b\x70\x19\x53\x07\xdd\x79\xf6\xd3\x71\x9c\x8b\xe1\x53\x8d\x09\xaf\x98\x5e\x6e\x14"}, + /* Eg7tXEwMZzS98xaZ1YHUbdRHsaYZiCsSaR6sKgxreoaj */ + .name = "commission_rate_in_basis_points", + .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = ULONG_MAX } }; /* TODO replace this with fd_map_perfect */ @@ -2028,6 +2034,7 @@ fd_feature_id_query( ulong prefix ) { case 0x010f656d89a4e808: return &ids[ 256 ]; case 0xfc12b1cef363afa7: return &ids[ 257 ]; case 0x2058ca8e0a3dda9a: return &ids[ 258 ]; + case 0xd388d8dbc65e2dcb: return &ids[ 259 ]; default: break; } return NULL; @@ -2292,4 +2299,5 @@ FD_STATIC_ASSERT( offsetof( fd_features_t, enable_bls12_381_syscall FD_STATIC_ASSERT( offsetof( fd_features_t, enable_alt_bn128_g2_syscalls )>>3==256UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, switch_to_chacha8_turbine )>>3==257UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, delay_commission_updates )>>3==258UL, layout ); +FD_STATIC_ASSERT( offsetof( fd_features_t, commission_rate_in_basis_points )>>3==259UL, layout ); FD_STATIC_ASSERT( sizeof( fd_features_t )>>3==FD_FEATURE_ID_CNT, layout ); diff --git a/src/flamenco/features/fd_features_generated.h b/src/flamenco/features/fd_features_generated.h index b5d2221bb56..162c40545da 100644 --- a/src/flamenco/features/fd_features_generated.h +++ b/src/flamenco/features/fd_features_generated.h @@ -8,10 +8,10 @@ #endif /* FEATURE_ID_CNT is the number of features in ids */ -#define FD_FEATURE_ID_CNT (259UL) +#define FD_FEATURE_ID_CNT (260UL) /* Feature set ID calculated from all feature names */ -#define FD_FEATURE_SET_ID (708229304U) +#define FD_FEATURE_SET_ID (2002210363U) union fd_features { ulong f[ FD_FEATURE_ID_CNT ]; @@ -275,5 +275,6 @@ union fd_features { /* 0x010f656d89a4e808 */ ulong enable_alt_bn128_g2_syscalls; /* 0xfc12b1cef363afa7 */ ulong switch_to_chacha8_turbine; /* 0x2058ca8e0a3dda9a */ ulong delay_commission_updates; + /* 0xd388d8dbc65e2dcb */ ulong commission_rate_in_basis_points; }; }; diff --git a/src/flamenco/features/feature_map.json b/src/flamenco/features/feature_map.json index 9b30367a18c..9502ee68077 100644 --- a/src/flamenco/features/feature_map.json +++ b/src/flamenco/features/feature_map.json @@ -257,5 +257,6 @@ {"name":"enable_bls12_381_syscall","pubkey":"b1sraWPVFdcUizB2LV5wQTeMuK8M313bi5bHjco5eVU"}, {"name":"enable_alt_bn128_g2_syscalls","pubkey":"bn1hKNURMGQaQoEVxahcEAcqiX3NwRs6hgKKNSLeKxH"}, {"name":"switch_to_chacha8_turbine","pubkey":"CHaChatUnR3s6cPyPMMGNJa3VdQQ8PNH2JqdD4LpCKnB"}, - {"name":"delay_commission_updates","pubkey":"BRUoCu28xjjPkDcNm7iY9a8LqgftZko99ioXz84wivXh"} + {"name":"delay_commission_updates","pubkey":"BRUoCu28xjjPkDcNm7iY9a8LqgftZko99ioXz84wivXh"}, + {"name":"commission_rate_in_basis_points","pubkey":"Eg7tXEwMZzS98xaZ1YHUbdRHsaYZiCsSaR6sKgxreoaj"} ] diff --git a/src/flamenco/rewards/fd_rewards.c b/src/flamenco/rewards/fd_rewards.c index 1b5ae13b67b..3c1afcd6590 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -12,6 +12,9 @@ #include "../accdb/fd_accdb_sync.h" #include "fd_epoch_rewards.h" +/* https://github.com/anza-xyz/agave/blob/master/runtime/src/inflation_rewards/mod.rs#L244 */ +#define FD_MAX_INFLATION_REWARDS_BPS (10000U) + /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/sdk/src/inflation.rs#L85 */ static double total( fd_inflation_t const * inflation, double year ) { @@ -277,22 +280,24 @@ typedef struct fd_commission_split fd_commission_split_t; /// returns commission split as (voter_portion, staker_portion, was_split) tuple /// /// if commission calculation is 100% one way or other, indicate with false for was_split +/// +/// commission_bps is in basis points (0-10000), where 10000 = 100% -// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L543 +// https://github.com/anza-xyz/agave/blob/master/runtime/src/inflation_rewards/mod.rs#L243 void -fd_vote_commission_split( uchar commission, +fd_vote_commission_split( ushort commission_bps, ulong on, fd_commission_split_t * result ) { - uint commission_split = fd_uint_min( (uint)commission, 100 ); - result->is_split = (commission_split != 0 && commission_split != 100); - // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L545 + uint commission_split = fd_uint_min( (uint)commission_bps, FD_MAX_INFLATION_REWARDS_BPS ); + result->is_split = (commission_split != 0 && commission_split != FD_MAX_INFLATION_REWARDS_BPS); + // https://github.com/anza-xyz/agave/blob/master/runtime/src/inflation_rewards/mod.rs#L247 if( commission_split==0U ) { result->voter_portion = 0; result->staker_portion = on; return; } - // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L546 - if( commission_split==100U ) { + // https://github.com/anza-xyz/agave/blob/master/runtime/src/inflation_rewards/mod.rs#L248 + if( commission_split==FD_MAX_INFLATION_REWARDS_BPS ) { result->voter_portion = on; result->staker_portion = 0; return; @@ -309,11 +314,11 @@ fd_vote_commission_split( uchar commission, // being rewarded at all. Thus, note that we intentionally discard // any residual fractional lamports. - // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L548 + // https://github.com/anza-xyz/agave/blob/master/runtime/src/inflation_rewards/mod.rs#L256 result->voter_portion = - (ulong)((uint128)on * (uint128)commission_split / (uint128)100); + (ulong)((uint128)on * (uint128)commission_split / (uint128)FD_MAX_INFLATION_REWARDS_BPS); result->staker_portion = - (ulong)((uint128)on * (uint128)( 100 - commission_split ) / (uint128)100); + (ulong)((uint128)on * (uint128)( FD_MAX_INFLATION_REWARDS_BPS - commission_split ) / (uint128)FD_MAX_INFLATION_REWARDS_BPS); } /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/programs/stake/src/rewards.rs#L33 */ @@ -323,7 +328,7 @@ redeem_rewards( fd_accdb_user_t * accdb, fd_stake_history_t const * stake_history, fd_stake_delegation_t const * stake, fd_vote_state_ele_t const * vote_state, - uchar commission, + ushort commission_bps, ulong rewarded_epoch, ulong total_rewards, uint128 total_points, @@ -378,7 +383,7 @@ redeem_rewards( fd_accdb_user_t * accdb, } fd_commission_split_t split_result; - fd_vote_commission_split( commission, rewards, &split_result ); + fd_vote_commission_split( commission_bps, rewards, &split_result ); if( split_result.is_split && (split_result.voter_portion == 0 || split_result.staker_portion == 0) ) { return 1; } @@ -495,25 +500,27 @@ calculate_reward_points_partitioned( fd_bank_t * bank, return total_points; } -/* Get commission rate for reward calculation +/* Get commission rate in basis points for reward calculation + + Returns commission in basis points (0-10000). - FIXME: permalink when Agave 4.0 is cut */ -static uchar -get_commission_rate( fd_bank_t * bank, - fd_pubkey_t const * voter_acc, - uchar current_commission ) { + https://github.com/anza-xyz/agave/blob/master/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L467 */ +static ushort +get_commission_rate_bps( fd_bank_t * bank, + fd_pubkey_t const * voter_acc, + ushort current_commission_bps ) { if( !FD_FEATURE_ACTIVE_BANK( bank, delay_commission_updates ) ) { - return current_commission; + return current_commission_bps; } - /* Delayed commission rate */ + /* Delayed commission rate - use snapshot from previous epochs */ fd_vote_state_ele_t const * prev_prev_ele = fd_vote_states_query_const( fd_bank_vote_states_prev_prev_query( bank ), voter_acc ); - if( FD_LIKELY( prev_prev_ele ) ) return prev_prev_ele->commission; + if( FD_LIKELY( prev_prev_ele ) ) return prev_prev_ele->commission_bps; fd_vote_state_ele_t const * prev_ele = fd_vote_states_query_const( fd_bank_vote_states_prev_query( bank ), voter_acc ); - if( FD_LIKELY( prev_ele ) ) return prev_ele->commission; + if( FD_LIKELY( prev_ele ) ) return prev_ele->commission_bps; - return current_commission; + return current_commission_bps; } /* Calculates epoch rewards for stake/vote accounts. @@ -587,7 +594,7 @@ calculate_stake_vote_rewards( fd_bank_t * bank, fd_vote_state_credits_t * realc_credit = !!runtime_stack->stakes.prev_vote_credits_used ? &runtime_stack->stakes.vote_credits[ vote_state_ele->idx ] : NULL; - uchar commission = get_commission_rate( bank, voter_acc, vote_state_ele->commission ); + ushort commission_bps = get_commission_rate_bps( bank, voter_acc, vote_state_ele->commission_bps ); /* redeem_rewards is actually just responsible for calculating the vote and stake rewards for each stake account. It does not do @@ -599,7 +606,7 @@ calculate_stake_vote_rewards( fd_bank_t * bank, stake_history, stake_delegation, vote_state_ele, - commission, + commission_bps, rewarded_epoch, total_rewards, total_points, @@ -616,7 +623,7 @@ calculate_stake_vote_rewards( fd_bank_t * bank, fd_bank_slot_get( bank ), stake_delegation->stake_account, *voter_acc, - commission, + commission_bps, (long)calculated_stake_rewards->voter_rewards, (long)calculated_stake_rewards->staker_rewards, (long)calculated_stake_rewards->new_credits_observed ); diff --git a/src/flamenco/runtime/Local.mk b/src/flamenco/runtime/Local.mk index 54e0ecf4265..6a728bc42be 100644 --- a/src/flamenco/runtime/Local.mk +++ b/src/flamenco/runtime/Local.mk @@ -81,6 +81,8 @@ $(call make-unit-test,test_accounts_resize_delta,tests/test_accounts_resize_delt $(call run-unit-test,test_accounts_resize_delta,) $(call make-unit-test,test_delay_commission_updates,tests/test_delay_commission_updates,fd_flamenco fd_funk fd_ballet fd_util) $(call run-unit-test,test_delay_commission_updates,) +$(call make-unit-test,test_commission_rate_in_basis_points,tests/test_commission_rate_in_basis_points,fd_flamenco fd_funk fd_ballet fd_util) +$(call run-unit-test,test_commission_rate_in_basis_points,) endif endif endif diff --git a/src/flamenco/runtime/program/fd_vote_program.c b/src/flamenco/runtime/program/fd_vote_program.c index eaf16257c86..3078df84749 100644 --- a/src/flamenco/runtime/program/fd_vote_program.c +++ b/src/flamenco/runtime/program/fd_vote_program.c @@ -932,6 +932,71 @@ update_commission( fd_exec_instr_ctx_t * ctx, ); } +/* SIMD-0291: Update commission rate in basis points + https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_state/mod.rs#L871-L906 */ +static int +update_commission_bps( fd_exec_instr_ctx_t * ctx, + int target_version, + fd_borrowed_account_t * vote_account, + ushort commission_bps, + fd_commission_kind_t * kind, + fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], + ulong signers_cnt ) { + + /* SIMD-0291: Commission Rate in Basis Points + Requires SIMD-0185: Vote State V4 + Requires SIMD-0249: Delay Commission Updates + https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_processor.rs#L324-L333 */ + if( !FD_FEATURE_ACTIVE_BANK( ctx->bank, commission_rate_in_basis_points ) || + !FD_FEATURE_ACTIVE_BANK( ctx->bank, delay_commission_updates ) || + target_version != VOTE_STATE_TARGET_VERSION_V4 ) { + return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; + } + + /* TODO: fill in this block when block_revenue_sharing is implemented + https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_state/mod.rs#L880-L884 */ + if( kind->discriminant == fd_commission_kind_enum_block_revenue ) { + return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; + } + + /* https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_state/mod.rs#L886-L889 */ + int rc = get_vote_state_handler_checked( + vote_account, + target_version, + false, + ctx->runtime->vote_program.update_commission.vote_state_mem, + ctx->runtime->vote_program.update_commission.authorized_voters_mem, + ctx->runtime->vote_program.update_commission.landed_votes_mem + ); + if( FD_UNLIKELY( rc ) ) return rc; + + fd_vote_state_versioned_t * vote_state_versioned = + (fd_vote_state_versioned_t *)ctx->runtime->vote_program.update_commission.vote_state_mem; + + /* Require authorized withdrawer to sign. + https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_state/mod.rs#L893-L894 */ + rc = fd_vote_verify_authorized_signer( + fd_vsv_get_authorized_withdrawer( vote_state_versioned ), + signers, + signers_cnt + ); + if( FD_UNLIKELY( rc ) ) return rc; + + /* https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_state/mod.rs#L896-L903 */ + if( vote_state_versioned->discriminant == fd_vote_state_versioned_enum_v4 ) { + vote_state_versioned->inner.v4.inflation_rewards_commission_bps = commission_bps; + } + /* TODO: add BlockRevenue case when implementing block_revenue_sharing */ + + /* Write back to account */ + return fd_vsv_set_vote_account_state( + ctx, + vote_account, + vote_state_versioned, + ctx->runtime->vote_program.update_commission.vote_lockout_mem + ); +} + /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L848C8-L903 */ static int withdraw( fd_exec_instr_ctx_t * ctx, @@ -2081,7 +2146,75 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { break; } + /* InitializeAccountV2 + * + * Instruction: + * https://github.com/anza-xyz/solana-sdk/blob/master/vote-interface/src/instruction.rs#L195-L200 + * + * Processor: + * https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_processor.rs#L302-L319 + * + * Notes: + * - TODO: implement with bls_pubkey_management_in_vote_account + */ + case fd_vote_instruction_enum_initialize_account_v2: { + return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; + } + + /* UpdateCommissionCollector + * + * Instruction: + * https://github.com/anza-xyz/solana-sdk/blob/master/vote-interface/src/instruction.rs#L202-L210 + * + * Processor: + * https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_processor.rs#L343-L371 + * + * Notes: + * - TODO: implement with custom_commission_collector + */ + case fd_vote_instruction_enum_update_commission_collector: { + return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; + } + + /* UpdateCommissionBps + * + * Instruction: + * https://github.com/anza-xyz/solana-sdk/blob/master/vote-interface/src/instruction.rs#L212-L221 + * + * Processor: + * https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_processor.rs#L320-L342 + * + */ + case fd_vote_instruction_enum_update_commission_bps: { + rc = update_commission_bps( + ctx, + target_version, + &me, + instruction->inner.update_commission_bps.commission_bps, + &instruction->inner.update_commission_bps.kind, + signers, + signers_cnt + ); + break; + } + + /* DepositDelegatorRewards + * + * Instruction: + * https://github.com/anza-xyz/solana-sdk/blob/master/vote-interface/src/instruction.rs#L261-L265 + * + * Processor: + * https://github.com/anza-xyz/agave/blob/master/programs/vote/src/vote_processor.rs#L372-L391 + * + * Notes: + * - TODO: implement with block_revenue_sharing + */ + case fd_vote_instruction_enum_deposit_delegator_rewards: { + return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; + } + default: + /* unreachable due to limited_deserialize */ FD_LOG_CRIT(( "unsupported vote instruction: %u", instruction->discriminant )); } diff --git a/src/flamenco/runtime/tests/fd_dump_pb.c b/src/flamenco/runtime/tests/fd_dump_pb.c index e126996953c..820b6172130 100644 --- a/src/flamenco/runtime/tests/fd_dump_pb.c +++ b/src/flamenco/runtime/tests/fd_dump_pb.c @@ -481,7 +481,7 @@ create_synthetic_vote_account_from_vote_state( fd_vote_state_ele_t const * vot .v3 = { .node_pubkey = vote_state->node_account, .authorized_withdrawer = vote_state->node_account, - .commission = vote_state->commission, + .commission = (uchar)(vote_state->commission_bps / 100U), .root_slot = 0UL, .has_root_slot = 0, .last_timestamp = { diff --git a/src/flamenco/runtime/tests/test_commission_rate_in_basis_points.c b/src/flamenco/runtime/tests/test_commission_rate_in_basis_points.c new file mode 100644 index 00000000000..6bae51af5c4 --- /dev/null +++ b/src/flamenco/runtime/tests/test_commission_rate_in_basis_points.c @@ -0,0 +1,162 @@ +/* Test for commission_rate_in_basis_points (SIMD-0291) + + Tests: + - Commission split calculation with basis points (0-10000) + - Commission capping at 10000 (100%) + - Vote states cache stores commission_bps correctly + + Note: Full instruction-level tests require the test environment + which is complex to set up. This file tests the core logic. */ + +#include "../../stakes/fd_vote_states.h" +#include "../../types/fd_types.h" +#include "../../../util/fd_util.h" + +/* Mirror the fd_commission_split struct from fd_rewards.c for testing */ +struct fd_commission_split { + ulong voter_portion; + ulong staker_portion; + uint is_split; +}; +typedef struct fd_commission_split fd_commission_split_t; + +/* External declaration - function is in fd_rewards.c */ +extern void fd_vote_commission_split( ushort commission_bps, ulong on, fd_commission_split_t * result ); + +/* Test fd_vote_commission_split with basis points */ +static void +test_commission_split_bps( void ) { + FD_LOG_NOTICE(( "Testing commission split with basis points..." )); + + fd_commission_split_t result; + + /* Test 0 bps (0%) - all goes to staker */ + fd_vote_commission_split( 0, 1000, &result ); + FD_TEST( result.voter_portion == 0 ); + FD_TEST( result.staker_portion == 1000 ); + FD_TEST( result.is_split == 0 ); + + /* Test 10000 bps (100%) - all goes to voter */ + fd_vote_commission_split( 10000, 1000, &result ); + FD_TEST( result.voter_portion == 1000 ); + FD_TEST( result.staker_portion == 0 ); + FD_TEST( result.is_split == 0 ); + + /* Test 5000 bps (50%) - split evenly */ + fd_vote_commission_split( 5000, 1000, &result ); + FD_TEST( result.voter_portion == 500 ); + FD_TEST( result.staker_portion == 500 ); + FD_TEST( result.is_split == 1 ); + + /* Test 2500 bps (25%) */ + fd_vote_commission_split( 2500, 1000, &result ); + FD_TEST( result.voter_portion == 250 ); + FD_TEST( result.staker_portion == 750 ); + FD_TEST( result.is_split == 1 ); + + /* Test 100 bps (1%) */ + fd_vote_commission_split( 100, 10000, &result ); + FD_TEST( result.voter_portion == 100 ); + FD_TEST( result.staker_portion == 9900 ); + FD_TEST( result.is_split == 1 ); + + /* Test capping: values > 10000 should be capped to 10000 */ + fd_vote_commission_split( 15000, 1000, &result ); + FD_TEST( result.voter_portion == 1000 ); /* Capped to 100% */ + FD_TEST( result.staker_portion == 0 ); + FD_TEST( result.is_split == 0 ); + + /* Test max u16 value - should be capped to 10000 */ + fd_vote_commission_split( USHORT_MAX, 1000, &result ); + FD_TEST( result.voter_portion == 1000 ); /* Capped to 100% */ + FD_TEST( result.staker_portion == 0 ); + FD_TEST( result.is_split == 0 ); + + /* Test precision with larger amounts */ + /* 1234 bps on 10000 lamports = 1234 voter, 8766 staker */ + fd_vote_commission_split( 1234, 10000, &result ); + FD_TEST( result.voter_portion == 1234 ); + FD_TEST( result.staker_portion == 8766 ); + FD_TEST( result.is_split == 1 ); + + /* Test with odd splits that result in truncation */ + /* 3333 bps on 10000 = 3333 voter, 6667 staker */ + fd_vote_commission_split( 3333, 10000, &result ); + FD_TEST( result.voter_portion == 3333 ); + FD_TEST( result.staker_portion == 6667 ); + FD_TEST( result.is_split == 1 ); + + FD_LOG_NOTICE(( "Commission split tests PASSED" )); +} + +/* Test CommissionKind enum */ +static void +test_commission_kind_enum( void ) { + FD_LOG_NOTICE(( "Testing CommissionKind enum..." )); + + /* Verify enum values match Agave */ + FD_TEST( fd_commission_kind_enum_inflation_rewards == 0 ); + FD_TEST( fd_commission_kind_enum_block_revenue == 1 ); + + /* Test enum discrimination */ + fd_commission_kind_t kind; + + kind.discriminant = fd_commission_kind_enum_inflation_rewards; + FD_TEST( fd_commission_kind_is_inflation_rewards( &kind ) ); + FD_TEST( !fd_commission_kind_is_block_revenue( &kind ) ); + + kind.discriminant = fd_commission_kind_enum_block_revenue; + FD_TEST( !fd_commission_kind_is_inflation_rewards( &kind ) ); + FD_TEST( fd_commission_kind_is_block_revenue( &kind ) ); + + FD_LOG_NOTICE(( "CommissionKind enum tests PASSED" )); +} + +/* Test vote instruction enum values */ +static void +test_vote_instruction_enum( void ) { + FD_LOG_NOTICE(( "Testing vote instruction enum indices..." )); + + /* Verify the new instruction indices match Agave */ + FD_TEST( fd_vote_instruction_enum_initialize_account_v2 == 16 ); + FD_TEST( fd_vote_instruction_enum_update_commission_collector == 17 ); + FD_TEST( fd_vote_instruction_enum_update_commission_bps == 18 ); + FD_TEST( fd_vote_instruction_enum_deposit_delegator_rewards == 19 ); + + FD_LOG_NOTICE(( "Vote instruction enum tests PASSED" )); +} + +/* Test conversion from percentage to basis points */ +static void +test_percentage_to_bps_conversion( void ) { + FD_LOG_NOTICE(( "Testing percentage to basis points conversion..." )); + + /* The conversion formula is: bps = percentage * 100 */ + FD_TEST( (ushort)(0 * 100) == 0 ); /* 0% = 0 bps */ + FD_TEST( (ushort)(1 * 100) == 100 ); /* 1% = 100 bps */ + FD_TEST( (ushort)(5 * 100) == 500 ); /* 5% = 500 bps */ + FD_TEST( (ushort)(10 * 100) == 1000 ); /* 10% = 1000 bps */ + FD_TEST( (ushort)(25 * 100) == 2500 ); /* 25% = 2500 bps */ + FD_TEST( (ushort)(50 * 100) == 5000 ); /* 50% = 5000 bps */ + FD_TEST( (ushort)(75 * 100) == 7500 ); /* 75% = 7500 bps */ + FD_TEST( (ushort)(100 * 100) == 10000 ); /* 100% = 10000 bps */ + + FD_LOG_NOTICE(( "Percentage to basis points conversion tests PASSED" )); +} + +int +main( int argc, char ** argv ) { + fd_boot( &argc, &argv ); + + FD_LOG_NOTICE(( "=== commission_rate_in_basis_points Tests ===" )); + + test_commission_split_bps(); + test_commission_kind_enum(); + test_vote_instruction_enum(); + test_percentage_to_bps_conversion(); + + FD_LOG_NOTICE(( "=== All tests PASSED ===" )); + + fd_halt(); + return 0; +} diff --git a/src/flamenco/runtime/tests/test_delay_commission_updates.c b/src/flamenco/runtime/tests/test_delay_commission_updates.c index 76c0dbce451..a62e654ef85 100644 --- a/src/flamenco/runtime/tests/test_delay_commission_updates.c +++ b/src/flamenco/runtime/tests/test_delay_commission_updates.c @@ -236,9 +236,9 @@ create_vote_account( test_env_t * env, uchar commission, ulong epoch_credits_epo fd_vote_states_t * vote_states = fd_bank_vote_states_locking_modify( env->bank ); fd_vote_state_ele_t * ele = fd_vote_states_update( vote_states, &validator_key ); - ele->node_account = authority_key; - ele->commission = commission; - ele->stake = TEST_LAMPORTS; + ele->node_account = authority_key; + ele->commission_bps = (ushort)(commission * 100U); + ele->stake = TEST_LAMPORTS; fd_bank_vote_states_end_locking_modify( env->bank ); fd_wksp_free_laddr( epoch_cred_mem ); @@ -282,18 +282,18 @@ static void set_commission_prev( test_env_t * env, uchar commission ) { fd_vote_states_t * vs = fd_bank_vote_states_prev_modify( env->bank ); fd_vote_state_ele_t * ele = fd_vote_states_update( vs, &validator_key ); - ele->node_account = authority_key; - ele->commission = commission; - ele->stake = TEST_LAMPORTS; + ele->node_account = authority_key; + ele->commission_bps = (ushort)(commission * 100U); + ele->stake = TEST_LAMPORTS; } static void set_commission_prev_prev( test_env_t * env, uchar commission ) { fd_vote_states_t * vs = fd_bank_vote_states_prev_prev_modify( env->bank ); fd_vote_state_ele_t * ele = fd_vote_states_update( vs, &validator_key ); - ele->node_account = authority_key; - ele->commission = commission; - ele->stake = TEST_LAMPORTS; + ele->node_account = authority_key; + ele->commission_bps = (ushort)(commission * 100U); + ele->stake = TEST_LAMPORTS; } /* ============================================================================ diff --git a/src/flamenco/stakes/fd_vote_states.c b/src/flamenco/stakes/fd_vote_states.c index bd6d06f062f..54cb143207a 100644 --- a/src/flamenco/stakes/fd_vote_states.c +++ b/src/flamenco/stakes/fd_vote_states.c @@ -277,34 +277,34 @@ fd_vote_states_update_from_account( fd_vote_states_t * vote_states, } fd_pubkey_t node_account; - uchar commission; + ushort commission_bps; long last_vote_timestamp; ulong last_vote_slot; switch( vsv->discriminant ) { case fd_vote_state_versioned_enum_v0_23_5: node_account = vsv->inner.v0_23_5.node_pubkey; - commission = vsv->inner.v0_23_5.commission; + commission_bps = (ushort)( vsv->inner.v0_23_5.commission * 100 ); last_vote_timestamp = vsv->inner.v0_23_5.last_timestamp.timestamp; last_vote_slot = vsv->inner.v0_23_5.last_timestamp.slot; break; case fd_vote_state_versioned_enum_v1_14_11: node_account = vsv->inner.v1_14_11.node_pubkey; - commission = vsv->inner.v1_14_11.commission; + commission_bps = (ushort)( vsv->inner.v1_14_11.commission * 100 ); last_vote_timestamp = vsv->inner.v1_14_11.last_timestamp.timestamp; last_vote_slot = vsv->inner.v1_14_11.last_timestamp.slot; break; case fd_vote_state_versioned_enum_v3: node_account = vsv->inner.v3.node_pubkey; - commission = vsv->inner.v3.commission; + commission_bps = (ushort)( vsv->inner.v3.commission * 100 ); last_vote_timestamp = vsv->inner.v3.last_timestamp.timestamp; last_vote_slot = vsv->inner.v3.last_timestamp.slot; break; case fd_vote_state_versioned_enum_v4: - /* Commission calculation is deliberate according to this: - https://github.com/anza-xyz/agave/blob/v3.1.1/vote/src/vote_state_view/field_frames.rs#L353 */ + /* For V4 accounts, always read inflation_rewards_commission_bps directly. + This is always in basis points (0-10000). */ node_account = vsv->inner.v4.node_pubkey; - commission = (uchar)fd_ushort_min( vsv->inner.v4.inflation_rewards_commission_bps/100, UCHAR_MAX ); + commission_bps = vsv->inner.v4.inflation_rewards_commission_bps; last_vote_timestamp = vsv->inner.v4.last_timestamp.timestamp; last_vote_slot = vsv->inner.v4.last_timestamp.slot; break; @@ -315,7 +315,7 @@ fd_vote_states_update_from_account( fd_vote_states_t * vote_states, fd_vote_state_ele_t * vote_state = fd_vote_states_update( vote_states, vote_account ); vote_state->node_account = node_account; - vote_state->commission = commission; + vote_state->commission_bps = commission_bps; vote_state->last_vote_timestamp = last_vote_timestamp; vote_state->last_vote_slot = last_vote_slot; diff --git a/src/flamenco/stakes/fd_vote_states.h b/src/flamenco/stakes/fd_vote_states.h index 8b59d28303d..fa5abf8c554 100644 --- a/src/flamenco/stakes/fd_vote_states.h +++ b/src/flamenco/stakes/fd_vote_states.h @@ -121,7 +121,7 @@ struct fd_vote_state_ele { fd_pubkey_t node_account; ulong last_vote_slot; long last_vote_timestamp; - uchar commission; + ushort commission_bps; }; typedef struct fd_vote_state_ele fd_vote_state_ele_t; diff --git a/src/flamenco/stakes/test_vote_states.c b/src/flamenco/stakes/test_vote_states.c index 6deb798e68c..1bbc755500a 100644 --- a/src/flamenco/stakes/test_vote_states.c +++ b/src/flamenco/stakes/test_vote_states.c @@ -52,7 +52,7 @@ int main( int argc, char ** argv ) { fd_vote_state_ele_t * vote_state_ele = fd_vote_states_update( vote_states, &vote_account_0 ); vote_state_ele->node_account = node_account_0; - vote_state_ele->commission = 50; + vote_state_ele->commission_bps = 5000; /* 50% in basis points */ vote_state_ele->last_vote_timestamp = 100L; vote_state_ele->last_vote_slot = 1000UL; vote_state_ele->stake = 10UL; @@ -61,7 +61,7 @@ int main( int argc, char ** argv ) { vote_state_ele = fd_vote_states_update( vote_states, &vote_account_1 ); vote_state_ele->node_account = node_account_0; - vote_state_ele->commission = 51; + vote_state_ele->commission_bps = 5100; /* 51% in basis points */ vote_state_ele->last_vote_timestamp = 100L; vote_state_ele->last_vote_slot = 10000UL; @@ -73,7 +73,7 @@ int main( int argc, char ** argv ) { FD_TEST( memcmp( &vote_state_ele->node_account, &node_account_0, sizeof(fd_pubkey_t) ) == 0 ); FD_TEST( vote_state_ele->last_vote_slot == 1000UL ); FD_TEST( vote_state_ele->last_vote_timestamp == 100L ); - FD_TEST( vote_state_ele->commission == 50 ); + FD_TEST( vote_state_ele->commission_bps == 5000 ); FD_TEST( vote_state_ele->stake == 10UL ); fd_vote_state_ele_t * vote_state_ele_1 = fd_vote_states_query( vote_states, &vote_account_1 ); @@ -82,7 +82,7 @@ int main( int argc, char ** argv ) { FD_TEST( memcmp( &vote_state_ele_1->node_account, &node_account_0, sizeof(fd_pubkey_t) ) == 0 ); FD_TEST( vote_state_ele_1->last_vote_slot == 10000UL ); FD_TEST( vote_state_ele_1->last_vote_timestamp == 100L ); - FD_TEST( vote_state_ele_1->commission == 51 ); + FD_TEST( vote_state_ele_1->commission_bps == 5100 ); fd_vote_states_reset_stakes( vote_states ); diff --git a/src/flamenco/types/fd_types.c b/src/flamenco/types/fd_types.c index 92327b7309c..b54ba981d1a 100644 --- a/src/flamenco/types/fd_types.c +++ b/src/flamenco/types/fd_types.c @@ -4837,6 +4837,108 @@ ulong fd_vote_authorize_checked_with_seed_args_size( fd_vote_authorize_checked_w return size; } +FD_FN_PURE uchar fd_commission_kind_is_inflation_rewards(fd_commission_kind_t const * self) { + return self->discriminant == 0; +} +FD_FN_PURE uchar fd_commission_kind_is_block_revenue(fd_commission_kind_t const * self) { + return self->discriminant == 1; +} +int fd_commission_kind_inner_decode_footprint( uint discriminant, fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { + int err; + switch (discriminant) { + case 0: { + return FD_BINCODE_SUCCESS; + } + case 1: { + return FD_BINCODE_SUCCESS; + } + default: return FD_BINCODE_ERR_ENCODING; + } +} +static int fd_commission_kind_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { + if( ctx->data>=ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; + uint discriminant = 0; + int err = fd_bincode_uint32_decode( &discriminant, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return fd_commission_kind_inner_decode_footprint( discriminant, ctx, total_sz ); +} +int fd_commission_kind_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { + *total_sz += sizeof(fd_commission_kind_t); + void const * start_data = ctx->data; + int err = fd_commission_kind_decode_footprint_inner( ctx, total_sz ); + if( ctx->data>ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; + ctx->data = start_data; + return err; +} +static void fd_commission_kind_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { + fd_commission_kind_t * self = (fd_commission_kind_t *)struct_mem; + fd_bincode_uint32_decode_unsafe( &self->discriminant, ctx ); +} +void * fd_commission_kind_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { + fd_commission_kind_t * self = (fd_commission_kind_t *)mem; + fd_commission_kind_new( self ); + void * alloc_region = (uchar *)mem + sizeof(fd_commission_kind_t); + void * * alloc_mem = &alloc_region; + fd_commission_kind_decode_inner( mem, alloc_mem, ctx ); + return self; +} + +ulong fd_commission_kind_size( fd_commission_kind_t const * self ) { + ulong size = 0; + size += sizeof(uint); + switch (self->discriminant) { + } + return size; +} + +int fd_commission_kind_encode( fd_commission_kind_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err = fd_bincode_uint32_encode( self->discriminant, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return err; +} + +int fd_update_commission_bps_encode( fd_update_commission_bps_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_uint16_encode( self->commission_bps, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_commission_kind_encode( &self->kind, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +static int fd_update_commission_bps_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { + if( ctx->data>=ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; + int err = 0; + err = fd_bincode_uint16_decode_footprint( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + err = fd_commission_kind_decode_footprint_inner( ctx, total_sz ); + if( FD_UNLIKELY( err ) ) return err; + return 0; +} +int fd_update_commission_bps_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { + *total_sz += sizeof(fd_update_commission_bps_t); + void const * start_data = ctx->data; + int err = fd_update_commission_bps_decode_footprint_inner( ctx, total_sz ); + if( ctx->data>ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; + ctx->data = start_data; + return err; +} +static void fd_update_commission_bps_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { + fd_update_commission_bps_t * self = (fd_update_commission_bps_t *)struct_mem; + fd_bincode_uint16_decode_unsafe( &self->commission_bps, ctx ); + fd_commission_kind_decode_inner( &self->kind, alloc_mem, ctx ); +} +void * fd_update_commission_bps_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { + fd_update_commission_bps_t * self = (fd_update_commission_bps_t *)mem; + fd_update_commission_bps_new( self ); + void * alloc_region = (uchar *)mem + sizeof(fd_update_commission_bps_t); + void * * alloc_mem = &alloc_region; + fd_update_commission_bps_decode_inner( mem, alloc_mem, ctx ); + return self; +} +void fd_update_commission_bps_new(fd_update_commission_bps_t * self) { + fd_memset( self, 0, sizeof(fd_update_commission_bps_t) ); + fd_commission_kind_new( &self->kind ); +} FD_FN_PURE uchar fd_vote_instruction_is_initialize_account(fd_vote_instruction_t const * self) { return self->discriminant == 0; } @@ -4885,6 +4987,18 @@ FD_FN_PURE uchar fd_vote_instruction_is_tower_sync(fd_vote_instruction_t const * FD_FN_PURE uchar fd_vote_instruction_is_tower_sync_switch(fd_vote_instruction_t const * self) { return self->discriminant == 15; } +FD_FN_PURE uchar fd_vote_instruction_is_initialize_account_v2(fd_vote_instruction_t const * self) { + return self->discriminant == 16; +} +FD_FN_PURE uchar fd_vote_instruction_is_update_commission_collector(fd_vote_instruction_t const * self) { + return self->discriminant == 17; +} +FD_FN_PURE uchar fd_vote_instruction_is_update_commission_bps(fd_vote_instruction_t const * self) { + return self->discriminant == 18; +} +FD_FN_PURE uchar fd_vote_instruction_is_deposit_delegator_rewards(fd_vote_instruction_t const * self) { + return self->discriminant == 19; +} void fd_vote_instruction_inner_new( fd_vote_instruction_inner_t * self, uint discriminant ); int fd_vote_instruction_inner_decode_footprint( uint discriminant, fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { int err; @@ -4967,6 +5081,24 @@ int fd_vote_instruction_inner_decode_footprint( uint discriminant, fd_bincode_de if( FD_UNLIKELY( err ) ) return err; return FD_BINCODE_SUCCESS; } + case 16: { + return FD_BINCODE_SUCCESS; + } + case 17: { + err = fd_commission_kind_decode_footprint_inner( ctx, total_sz ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } + case 18: { + err = fd_update_commission_bps_decode_footprint_inner( ctx, total_sz ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; + } + case 19: { + err = fd_bincode_uint64_decode_footprint( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + return FD_BINCODE_SUCCESS; + } default: return FD_BINCODE_ERR_ENCODING; } } @@ -5050,6 +5182,21 @@ static void fd_vote_instruction_inner_decode_inner( fd_vote_instruction_inner_t fd_tower_sync_switch_decode_inner( &self->tower_sync_switch, alloc_mem, ctx ); break; } + case 16: { + break; + } + case 17: { + fd_commission_kind_decode_inner( &self->update_commission_collector, alloc_mem, ctx ); + break; + } + case 18: { + fd_update_commission_bps_decode_inner( &self->update_commission_bps, alloc_mem, ctx ); + break; + } + case 19: { + fd_bincode_uint64_decode_unsafe( &self->deposit_delegator_rewards, ctx ); + break; + } } } static void fd_vote_instruction_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { @@ -5128,6 +5275,20 @@ void fd_vote_instruction_inner_new( fd_vote_instruction_inner_t * self, uint dis fd_tower_sync_switch_new( &self->tower_sync_switch ); break; } + case 16: { + break; + } + case 17: { + fd_commission_kind_new( &self->update_commission_collector ); + break; + } + case 18: { + fd_update_commission_bps_new( &self->update_commission_bps ); + break; + } + case 19: { + break; + } default: break; // FD_LOG_ERR(( "unhandled type")); } } @@ -5204,6 +5365,18 @@ ulong fd_vote_instruction_size( fd_vote_instruction_t const * self ) { size += fd_tower_sync_switch_size( &self->inner.tower_sync_switch ); break; } + case 17: { + size += fd_commission_kind_size( &self->inner.update_commission_collector ); + break; + } + case 18: { + size += fd_update_commission_bps_size( &self->inner.update_commission_bps ); + break; + } + case 19: { + size += sizeof(ulong); + break; + } } return size; } @@ -5286,6 +5459,21 @@ int fd_vote_instruction_inner_encode( fd_vote_instruction_inner_t const * self, if( FD_UNLIKELY( err ) ) return err; break; } + case 17: { + err = fd_commission_kind_encode( &self->update_commission_collector, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } + case 18: { + err = fd_update_commission_bps_encode( &self->update_commission_bps, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } + case 19: { + err = fd_bincode_uint64_encode( self->deposit_delegator_rewards, ctx ); + if( FD_UNLIKELY( err ) ) return err; + break; + } } return FD_BINCODE_SUCCESS; } diff --git a/src/flamenco/types/fd_types.h b/src/flamenco/types/fd_types.h index 011283b8ed2..b2ec2f04e2c 100644 --- a/src/flamenco/types/fd_types.h +++ b/src/flamenco/types/fd_types.h @@ -950,6 +950,22 @@ struct fd_vote_authorize_checked_with_seed_args { typedef struct fd_vote_authorize_checked_with_seed_args fd_vote_authorize_checked_with_seed_args_t; #define FD_VOTE_AUTHORIZE_CHECKED_WITH_SEED_ARGS_ALIGN alignof(fd_vote_authorize_checked_with_seed_args_t) +/* https://github.com/anza-xyz/agave/blob/master/sdk/vote-interface/src/instruction.rs */ +struct fd_commission_kind { + uint discriminant; +}; +typedef struct fd_commission_kind fd_commission_kind_t; +#define FD_COMMISSION_KIND_ALIGN alignof(fd_commission_kind_t) + +/* https://github.com/anza-xyz/agave/blob/master/sdk/vote-interface/src/instruction.rs */ +/* Encoded Size: Fixed (6 bytes) */ +struct fd_update_commission_bps { + ushort commission_bps; + fd_commission_kind_t kind; +}; +typedef struct fd_update_commission_bps fd_update_commission_bps_t; +#define FD_UPDATE_COMMISSION_BPS_ALIGN alignof(fd_update_commission_bps_t) + union fd_vote_instruction_inner { fd_vote_init_t initialize_account; fd_vote_authorize_pubkey_t authorize; @@ -966,6 +982,9 @@ union fd_vote_instruction_inner { fd_compact_vote_state_update_switch_t compact_update_vote_state_switch; fd_tower_sync_t tower_sync; fd_tower_sync_switch_t tower_sync_switch; + fd_commission_kind_t update_commission_collector; + fd_update_commission_bps_t update_commission_bps; + ulong deposit_delegator_rewards; }; typedef union fd_vote_instruction_inner fd_vote_instruction_inner_t; @@ -2149,6 +2168,27 @@ static inline ulong fd_vote_authorize_checked_with_seed_args_align( void ) { ret int fd_vote_authorize_checked_with_seed_args_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); void * fd_vote_authorize_checked_with_seed_args_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); +static inline void fd_commission_kind_new_disc( fd_commission_kind_t * self, uint discriminant ) { self->discriminant = discriminant; } +static inline void fd_commission_kind_new( fd_commission_kind_t * self ) { self->discriminant = (uint)ULONG_MAX; } +int fd_commission_kind_encode( fd_commission_kind_t const * self, fd_bincode_encode_ctx_t * ctx ); +ulong fd_commission_kind_size( fd_commission_kind_t const * self ); +static inline ulong fd_commission_kind_align( void ) { return FD_COMMISSION_KIND_ALIGN; } +int fd_commission_kind_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); +void * fd_commission_kind_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); + +FD_FN_PURE uchar fd_commission_kind_is_inflation_rewards( fd_commission_kind_t const * self ); +FD_FN_PURE uchar fd_commission_kind_is_block_revenue( fd_commission_kind_t const * self ); +enum { +fd_commission_kind_enum_inflation_rewards = 0, +fd_commission_kind_enum_block_revenue = 1, +}; +void fd_update_commission_bps_new( fd_update_commission_bps_t * self ); +int fd_update_commission_bps_encode( fd_update_commission_bps_t const * self, fd_bincode_encode_ctx_t * ctx ); +static inline ulong fd_update_commission_bps_size( fd_update_commission_bps_t const * self ) { (void)self; return 6UL; } +static inline ulong fd_update_commission_bps_align( void ) { return FD_UPDATE_COMMISSION_BPS_ALIGN; } +int fd_update_commission_bps_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); +void * fd_update_commission_bps_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); + void fd_vote_instruction_new_disc( fd_vote_instruction_t * self, uint discriminant ); void fd_vote_instruction_new( fd_vote_instruction_t * self ); int fd_vote_instruction_encode( fd_vote_instruction_t const * self, fd_bincode_encode_ctx_t * ctx ); @@ -2173,6 +2213,10 @@ FD_FN_PURE uchar fd_vote_instruction_is_compact_update_vote_state( fd_vote_instr FD_FN_PURE uchar fd_vote_instruction_is_compact_update_vote_state_switch( fd_vote_instruction_t const * self ); FD_FN_PURE uchar fd_vote_instruction_is_tower_sync( fd_vote_instruction_t const * self ); FD_FN_PURE uchar fd_vote_instruction_is_tower_sync_switch( fd_vote_instruction_t const * self ); +FD_FN_PURE uchar fd_vote_instruction_is_initialize_account_v2( fd_vote_instruction_t const * self ); +FD_FN_PURE uchar fd_vote_instruction_is_update_commission_collector( fd_vote_instruction_t const * self ); +FD_FN_PURE uchar fd_vote_instruction_is_update_commission_bps( fd_vote_instruction_t const * self ); +FD_FN_PURE uchar fd_vote_instruction_is_deposit_delegator_rewards( fd_vote_instruction_t const * self ); enum { fd_vote_instruction_enum_initialize_account = 0, fd_vote_instruction_enum_authorize = 1, @@ -2190,6 +2234,10 @@ fd_vote_instruction_enum_compact_update_vote_state = 12, fd_vote_instruction_enum_compact_update_vote_state_switch = 13, fd_vote_instruction_enum_tower_sync = 14, fd_vote_instruction_enum_tower_sync_switch = 15, +fd_vote_instruction_enum_initialize_account_v2 = 16, +fd_vote_instruction_enum_update_commission_collector = 17, +fd_vote_instruction_enum_update_commission_bps = 18, +fd_vote_instruction_enum_deposit_delegator_rewards = 19, }; static inline void fd_system_program_instruction_create_account_new( fd_system_program_instruction_create_account_t * self ) { fd_memset( self, 0, sizeof(fd_system_program_instruction_create_account_t) ); } int fd_system_program_instruction_create_account_encode( fd_system_program_instruction_create_account_t const * self, fd_bincode_encode_ctx_t * ctx ); diff --git a/src/flamenco/types/fd_types.json b/src/flamenco/types/fd_types.json index 8e6326daf82..59d4a9fcf32 100644 --- a/src/flamenco/types/fd_types.json +++ b/src/flamenco/types/fd_types.json @@ -692,6 +692,24 @@ ], "comment": "https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/programs/vote/src/vote_state/mod.rs#L252" }, + { + "name": "commission_kind", + "type": "enum", + "variants": [ + { "name": "inflation_rewards" }, + { "name": "block_revenue" } + ], + "comment": "https://github.com/anza-xyz/agave/blob/master/sdk/vote-interface/src/instruction.rs" + }, + { + "name": "update_commission_bps", + "type": "struct", + "fields": [ + { "name": "commission_bps", "type": "ushort" }, + { "name": "kind", "type": "commission_kind" } + ], + "comment": "https://github.com/anza-xyz/agave/blob/master/sdk/vote-interface/src/instruction.rs" + }, { "name": "vote_instruction", "type": "enum", @@ -711,7 +729,11 @@ { "name": "compact_update_vote_state", "type": "compact_vote_state_update"}, { "name": "compact_update_vote_state_switch", "type": "compact_vote_state_update_switch"}, { "name": "tower_sync", "type": "tower_sync"}, - { "name": "tower_sync_switch", "type": "tower_sync_switch"} + { "name": "tower_sync_switch", "type": "tower_sync_switch"}, + { "name": "initialize_account_v2" }, + { "name": "update_commission_collector", "type": "commission_kind" }, + { "name": "update_commission_bps", "type": "update_commission_bps" }, + { "name": "deposit_delegator_rewards", "type": "ulong" } ], "comment": "https://github.com/firedancer-io/solana/blob/53a4e5d6c58b2ffe89b09304e4437f8ca198dadd/programs/vote/src/vote_instruction.rs#L21" },