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
112 changes: 92 additions & 20 deletions src/flamenco/rewards/fd_epoch_rewards.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ fd_epoch_rewards_align( void ) {

ulong
fd_epoch_rewards_footprint( ulong stake_account_max ) {
ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );

ulong l = FD_LAYOUT_INIT;
l = FD_LAYOUT_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
l = FD_LAYOUT_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() * FD_REWARDS_MAX_PARTITIONS );
return FD_LAYOUT_FINI( l, fd_epoch_rewards_align() );
}
Expand All @@ -37,6 +40,13 @@ fd_epoch_rewards_new( void * shmem, ulong stake_account_max ) {
return NULL;
}

ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
if( FD_UNLIKELY( !fd_epoch_stake_reward_map_new( map, chain_cnt_est, 0UL ) ) ) {
FD_LOG_WARNING(( "bad map" ));
return NULL;
}

for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_new( dlist ) ) ) {
Expand All @@ -52,8 +62,14 @@ fd_epoch_rewards_new( void * shmem, ulong stake_account_max ) {

memset( epoch_rewards, 0, sizeof(fd_epoch_rewards_t) );

epoch_rewards->magic = FD_EPOCH_REWARDS_MAGIC;
epoch_rewards->stake_account_max_ = stake_account_max;
FD_COMPILER_MFENCE();
epoch_rewards->magic = FD_EPOCH_REWARDS_MAGIC;
FD_COMPILER_MFENCE();

epoch_rewards->stake_account_max = stake_account_max;

epoch_rewards->pool_offset = (ulong)pool - (ulong)shmem;
epoch_rewards->map_offset = (ulong)map - (ulong)shmem;

return shmem;
}
Expand All @@ -72,14 +88,21 @@ fd_epoch_rewards_join( void * shmem ) {

FD_SCRATCH_ALLOC_INIT( l, shmem );
fd_epoch_rewards_t * epoch_rewards = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
ulong stake_account_max = epoch_rewards->stake_account_max_;
ulong stake_account_max = epoch_rewards->stake_account_max;

void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( stake_account_max ) );
if( FD_UNLIKELY( !fd_epoch_stake_reward_pool_join( pool ) ) ) {
FD_LOG_WARNING(( "bad pool" ));
return NULL;
}

ulong chain_cnt_est = fd_epoch_stake_reward_map_chain_cnt_est( stake_account_max );
void * map = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( chain_cnt_est ) );
if( FD_UNLIKELY( !fd_epoch_stake_reward_map_join( map ) ) ) {
FD_LOG_WARNING(( "bad map" ));
return NULL;
}

for( ulong i=0UL; i<FD_REWARDS_MAX_PARTITIONS; i++ ) {
void * dlist = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
if( FD_UNLIKELY( !fd_epoch_stake_reward_dlist_join( dlist ) ) ) {
Expand All @@ -88,7 +111,7 @@ fd_epoch_rewards_join( void * shmem ) {
}
}

if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() ) != (ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_epoch_rewards_align() )!=(ulong)shmem+fd_epoch_rewards_footprint( stake_account_max ) ) ) {
FD_LOG_WARNING(( "bad footprint" ));
return NULL;
}
Expand Down Expand Up @@ -132,14 +155,15 @@ fd_epoch_rewards_delete( void * epoch_rewards_shmem ) {

fd_epoch_stake_reward_dlist_t *
fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong idx ) {
if( FD_UNLIKELY( idx >= epoch_rewards->num_partitions_ ) ) {
FD_LOG_WARNING(( "idx: %lu is greater than num_partitions: %lu", idx, epoch_rewards->num_partitions_ ));
if( FD_UNLIKELY( idx >= epoch_rewards->num_partitions ) ) {
FD_LOG_WARNING(( "idx: %lu is greater than num_partitions: %lu", idx, epoch_rewards->num_partitions ));
return NULL;
}

FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max ) );
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_map_align(), fd_epoch_stake_reward_map_footprint( fd_epoch_stake_reward_map_chain_cnt_est( epoch_rewards->stake_account_max ) ) );
for( ulong i=0UL; i<idx; i++ ) {
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_dlist_align(), fd_epoch_stake_reward_dlist_footprint() );
}
Expand All @@ -155,20 +179,68 @@ fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards,

fd_epoch_stake_reward_t *
fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards ) {
if( FD_UNLIKELY( !epoch_rewards ) ) {
FD_LOG_WARNING(( "NULL epoch_rewards" ));
return NULL;
}
return fd_epoch_stake_reward_pool_join( (uchar *)epoch_rewards + epoch_rewards->pool_offset );
}

FD_SCRATCH_ALLOC_INIT( l, epoch_rewards );
FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_rewards_align(), sizeof(fd_epoch_rewards_t) );
void * pool = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_stake_reward_pool_align(), fd_epoch_stake_reward_pool_footprint( epoch_rewards->stake_account_max_ ) );
fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_stake_reward_pool_join( pool );
if( FD_UNLIKELY( !stake_reward_pool ) ) {
FD_LOG_WARNING(( "bad stake_reward_pool" ));
return NULL;
fd_epoch_stake_reward_map_t *
fd_epoch_rewards_get_stake_reward_map( fd_epoch_rewards_t const * epoch_rewards ) {
return fd_epoch_stake_reward_map_join( (uchar *)epoch_rewards + epoch_rewards->map_offset );
}

void
fd_epoch_rewards_insert( fd_epoch_rewards_t * epoch_rewards,
fd_pubkey_t const * pubkey,
ulong credits,
ulong lamports ) {
fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
fd_epoch_stake_reward_map_t * stake_reward_map = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );
FD_TEST( stake_reward_pool );
FD_TEST( stake_reward_map );

FD_TEST( !fd_epoch_stake_reward_map_ele_query( stake_reward_map, pubkey, NULL, stake_reward_pool ) );

fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_pool_ele_acquire( stake_reward_pool );

stake_reward->stake_pubkey = *pubkey;
stake_reward->credits_observed = credits;
stake_reward->lamports = lamports;

fd_epoch_stake_reward_map_ele_insert( stake_reward_map, stake_reward, stake_reward_pool );

epoch_rewards->total_stake_rewards += lamports;
epoch_rewards->stake_rewards_cnt++;

}

void
fd_epoch_rewards_hash_all( fd_epoch_rewards_t * epoch_rewards,
fd_hash_t const * parent_blockhash,
ulong num_partitions ) {

fd_epoch_stake_reward_t * stake_reward_pool = fd_epoch_rewards_get_stake_reward_pool( epoch_rewards );
fd_epoch_stake_reward_map_t * stake_reward_map = fd_epoch_rewards_get_stake_reward_map( epoch_rewards );

epoch_rewards->num_partitions = num_partitions;

for( fd_epoch_stake_reward_map_iter_t iter = fd_epoch_stake_reward_map_iter_init( stake_reward_map, stake_reward_pool );
!fd_epoch_stake_reward_map_iter_done( iter, stake_reward_map, stake_reward_pool );
iter = fd_epoch_stake_reward_map_iter_next( iter, stake_reward_map, stake_reward_pool ) ) {

fd_epoch_stake_reward_t * stake_reward = fd_epoch_stake_reward_map_iter_ele( iter, stake_reward_map, stake_reward_pool );

fd_siphash13_t sip[1] = {0};
fd_siphash13_t * hasher = fd_siphash13_init( sip, 0UL, 0UL );
hasher = fd_siphash13_append( hasher, parent_blockhash->hash, sizeof(fd_hash_t) );
fd_siphash13_append( hasher, (uchar const *)stake_reward->stake_pubkey.uc, sizeof(fd_pubkey_t) );
ulong hash64 = fd_siphash13_fini( hasher );

/* Now get the correct dlist based on the hash. */
ulong partition_index = (ulong)((uint128)num_partitions * (uint128) hash64 / ((uint128)ULONG_MAX + 1));

fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );

fd_epoch_stake_reward_dlist_ele_push_tail( partition_dlist, stake_reward, stake_reward_pool );
}
return stake_reward_pool;
}

int
Expand Down Expand Up @@ -202,7 +274,7 @@ fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards,
ulong hash64 = fd_siphash13_fini( hasher );

/* Now get the correct dlist based on the hash. */
ulong partition_index = (ulong)((uint128)epoch_rewards->num_partitions_ * (uint128) hash64 / ((uint128)ULONG_MAX + 1));
ulong partition_index = (ulong)((uint128)epoch_rewards->num_partitions * (uint128) hash64 / ((uint128)ULONG_MAX + 1));

fd_epoch_stake_reward_dlist_t * partition_dlist = fd_epoch_rewards_get_partition_index( epoch_rewards, partition_index );
if( FD_UNLIKELY( !partition_dlist ) ) {
Expand Down
131 changes: 50 additions & 81 deletions src/flamenco/rewards/fd_epoch_rewards.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,15 @@ FD_STATIC_ASSERT( FD_REWARDS_MAX_PARTITIONS <= FD_RUNTIME_SLOTS_PER_EPOCH / MAX_
#define FD_EPOCH_REWARDS_MAGIC (0x122400081001UL)

struct fd_epoch_stake_reward {
ulong prev;
ulong next;
ulong parent;
fd_pubkey_t stake_pubkey;
ulong credits_observed;
ulong lamports;
/* Internal pointers for pool, dlist, and map. */
ulong prev;
ulong next;
ulong parent;
ulong next_;
ulong nexta;
};
typedef struct fd_epoch_stake_reward fd_epoch_stake_reward_t;

Expand All @@ -78,30 +81,47 @@ typedef struct fd_epoch_stake_reward fd_epoch_stake_reward_t;

#define DLIST_NAME fd_epoch_stake_reward_dlist
#define DLIST_ELE_T fd_epoch_stake_reward_t
#define DLIST_NEXT nexta
#include "../../util/tmpl/fd_dlist.c"

#define MAP_NAME fd_epoch_stake_reward_map
#define MAP_KEY_T fd_pubkey_t
#define MAP_ELE_T fd_epoch_stake_reward_t
#define MAP_KEY stake_pubkey
#define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
#define MAP_KEY_HASH(key,seed) (fd_hash( seed, key, sizeof(fd_pubkey_t) ))
#define MAP_NEXT next_
#include "../../util/tmpl/fd_map_chain.c"

struct fd_epoch_rewards {
ulong magic;

/* Data representing the partitioned stake rewards */
int is_active_;
ulong stake_account_max_;
ulong starting_block_height_;
ulong num_partitions_;
ulong partitions_lengths_[FD_REWARDS_MAX_PARTITIONS];
int is_active;
ulong stake_account_max;
ulong starting_block_height;
ulong num_partitions;
ulong partitions_lengths[FD_REWARDS_MAX_PARTITIONS];

/* Result of total rewards distribution */

/* Total rewards for the epoch (including both vote rewards and stake
rewards) */
ulong total_rewards_;
ulong total_rewards;
/* total rewards points calculated for the current epoch, where points
equals the sum of (delegated stake * credits observed) for all
delegations */
ulong distributed_rewards_;
ulong distributed_rewards;
/* Stake rewards that still need to be distributed, grouped by
partition */
uint128 total_points_;
uint128 total_points;

ulong total_stake_rewards;
ulong stake_rewards_cnt;

/* Internal pointers for pool, dlist, and map. */
ulong pool_offset;
ulong map_offset;

/* This will be followed by a pool of fd_epoch_stake_reward_t. This
pool will be sized out to FD_BANKS_MAX_STAKE_ACCOUNTS. */
Expand Down Expand Up @@ -159,6 +179,12 @@ fd_epoch_rewards_get_partition_index( fd_epoch_rewards_t const * epoch_rewards,
fd_epoch_stake_reward_t *
fd_epoch_rewards_get_stake_reward_pool( fd_epoch_rewards_t const * epoch_rewards );

/* fd_epoch_rewards_get_stake_reward_map returns a pointer to the map
of stake rewards. */

fd_epoch_stake_reward_map_t *
fd_epoch_rewards_get_stake_reward_map( fd_epoch_rewards_t const * epoch_rewards );

/* fd_epoch_rewards_hash_and_insert determines the hash partition that
the stake pubkey belongs in and stores the pubkey along with the
total amount of credits and lamports. */
Expand All @@ -170,83 +196,26 @@ fd_epoch_rewards_hash_and_insert( fd_epoch_rewards_t * epoch_rewards,
ulong credits,
ulong lamports );

void
fd_epoch_rewards_insert( fd_epoch_rewards_t * epoch_rewards,
fd_pubkey_t const * pubkey,
ulong credits,
ulong lamports );

void
fd_epoch_rewards_hash_all( fd_epoch_rewards_t * epoch_rewards,
fd_hash_t const * parent_blockhash,
ulong num_partitions );

/* fd_epoch_rewards_get_distribution_partition_index determines the
hash partition that the current block belongs in. */

ulong
fd_epoch_rewards_get_distribution_partition_index( fd_epoch_rewards_t const * epoch_rewards, ulong curr_block_height );

/* Simple inline mutator functions */

static void FD_FN_UNUSED
fd_epoch_rewards_set_active( fd_epoch_rewards_t * epoch_rewards, int is_active ) {
epoch_rewards->is_active_ = is_active;
}

static void FD_FN_UNUSED
fd_epoch_rewards_set_starting_block_height( fd_epoch_rewards_t * epoch_rewards, ulong block_height ) {
epoch_rewards->starting_block_height_ = block_height;
}

static void FD_FN_UNUSED
fd_epoch_rewards_set_num_partitions( fd_epoch_rewards_t * epoch_rewards, ulong num_partitions ) {
if( FD_UNLIKELY( num_partitions>FD_REWARDS_MAX_PARTITIONS ) ) {
FD_LOG_WARNING(( "num_partitions: %lu is greater than FD_REWARDS_MAX_PARTITIONS: %lu", num_partitions, FD_REWARDS_MAX_PARTITIONS ));
return;
}
epoch_rewards->num_partitions_ = num_partitions;
}

static void FD_FN_UNUSED
fd_epoch_rewards_set_distributed_rewards( fd_epoch_rewards_t * epoch_rewards, ulong distributed_rewards ) {
epoch_rewards->distributed_rewards_ = distributed_rewards;
}

static void FD_FN_UNUSED
fd_epoch_rewards_set_total_rewards( fd_epoch_rewards_t * epoch_rewards, ulong total_rewards ) {
epoch_rewards->total_rewards_ = total_rewards;
}

static void FD_FN_UNUSED
fd_epoch_rewards_set_total_points( fd_epoch_rewards_t * epoch_rewards, uint128 total_points ) {
epoch_rewards->total_points_ = total_points;
}

/* Simple inline accessor functions */

static int FD_FN_UNUSED
fd_epoch_rewards_is_active( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->is_active_;
}

static ulong FD_FN_UNUSED
fd_epoch_rewards_get_num_partitions( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->num_partitions_;
}

static ulong FD_FN_UNUSED
fd_epoch_rewards_get_starting_block_height( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->starting_block_height_;
}

static ulong FD_FN_UNUSED
static inline ulong
fd_epoch_rewards_get_exclusive_ending_block_height( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->starting_block_height_ + epoch_rewards->num_partitions_;
}

static ulong FD_FN_UNUSED
fd_epoch_rewards_get_distributed_rewards( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->distributed_rewards_;
}

static uint128 FD_FN_UNUSED
fd_epoch_rewards_get_total_points( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->total_points_;
}

static ulong FD_FN_UNUSED
fd_epoch_rewards_get_total_rewards( fd_epoch_rewards_t const * epoch_rewards ) {
return epoch_rewards->total_rewards_;
return epoch_rewards->starting_block_height + epoch_rewards->num_partitions;
}

FD_PROTOTYPES_END
Expand Down
Loading
Loading