Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/disco/gui/fd_gui_tile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ] );

Expand Down
6 changes: 3 additions & 3 deletions src/discof/restore/utils/fd_ssload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 8 additions & 0 deletions src/flamenco/features/fd_features_generated.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
5 changes: 3 additions & 2 deletions src/flamenco/features/fd_features_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ];
Expand Down Expand Up @@ -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;
};
};
3 changes: 2 additions & 1 deletion src/flamenco/features/feature_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
]
59 changes: 33 additions & 26 deletions src/flamenco/rewards/fd_rewards.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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;
Expand All @@ -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 */
Expand All @@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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 );
Expand Down
2 changes: 2 additions & 0 deletions src/flamenco/runtime/Local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
133 changes: 133 additions & 0 deletions src/flamenco/runtime/program/fd_vote_program.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 ));
}

Expand Down
2 changes: 1 addition & 1 deletion src/flamenco/runtime/tests/fd_dump_pb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
Loading
Loading