Line data Source code
1 : #ifndef HEADER_fd_src_discof_replay_fd_exec_h 2 : #define HEADER_fd_src_discof_replay_fd_exec_h 3 : 4 : #include "../../flamenco/fd_flamenco_base.h" 5 : #include "../../flamenco/stakes/fd_stakes.h" 6 : #include "../../flamenco/runtime/fd_runtime.h" 7 : #include "../../flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h" 8 : #include "../../discof/restore/utils/fd_ssmsg.h" 9 : 10 : /* FIXME: SIMD-0180 - set the correct epochs */ 11 0 : #define FD_SIMD0180_ACTIVE_EPOCH_TESTNET (829) 12 0 : #define FD_SIMD0180_ACTIVE_EPOCH_MAINNET (841) 13 : 14 : /* Replay tile msg link formatting. The following take a pointer into 15 : a dcache region and formats it as a specific message type. */ 16 : 17 : static inline ulong 18 : generate_stake_weight_msg( ulong epoch, 19 : fd_epoch_schedule_t const * epoch_schedule, 20 : fd_vote_states_t const * epoch_stakes, 21 0 : ulong * stake_weight_msg_out ) { 22 0 : fd_stake_weight_msg_t * stake_weight_msg = (fd_stake_weight_msg_t *)fd_type_pun( stake_weight_msg_out ); 23 0 : fd_vote_stake_weight_t * stake_weights = stake_weight_msg->weights; 24 : 25 0 : stake_weight_msg->epoch = epoch; 26 0 : stake_weight_msg->start_slot = fd_epoch_slot0( epoch_schedule, epoch ); 27 0 : stake_weight_msg->slot_cnt = epoch_schedule->slots_per_epoch; 28 0 : stake_weight_msg->excluded_stake = 0UL; 29 0 : stake_weight_msg->vote_keyed_lsched = 1UL; 30 : 31 : /* FIXME: SIMD-0180 - hack to (de)activate in testnet vs mainnet. 32 : This code can be removed once the feature is active. */ 33 0 : if( (1==epoch_schedule->warmup && epoch<FD_SIMD0180_ACTIVE_EPOCH_TESTNET) || 34 0 : (0==epoch_schedule->warmup && epoch<FD_SIMD0180_ACTIVE_EPOCH_MAINNET) ) { 35 0 : stake_weight_msg->vote_keyed_lsched = 0UL; 36 0 : } 37 : 38 : /* epoch_stakes from manifest are already filtered (stake>0), but not sorted */ 39 0 : fd_vote_states_iter_t iter_[1]; 40 0 : ulong idx = 0UL; 41 0 : for( fd_vote_states_iter_t * iter = fd_vote_states_iter_init( iter_, epoch_stakes ); !fd_vote_states_iter_done( iter ); fd_vote_states_iter_next( iter ) ) { 42 0 : fd_vote_state_ele_t * vote_state = fd_vote_states_iter_ele( iter ); 43 0 : if( FD_UNLIKELY( !vote_state->stake ) ) continue; 44 : 45 0 : stake_weights[ idx ].stake = vote_state->stake; 46 0 : memcpy( stake_weights[ idx ].id_key.uc, &vote_state->node_account, sizeof(fd_pubkey_t) ); 47 0 : memcpy( stake_weights[ idx ].vote_key.uc, &vote_state->vote_account, sizeof(fd_pubkey_t) ); 48 0 : idx++; 49 0 : } 50 0 : stake_weight_msg->staked_cnt = idx; 51 0 : sort_vote_weights_by_stake_vote_inplace( stake_weights, idx ); 52 : 53 0 : return fd_stake_weight_msg_sz( idx ); 54 0 : } 55 : 56 : static inline ulong 57 : generate_stake_weight_msg_manifest( ulong epoch, 58 : fd_epoch_schedule_t const * epoch_schedule, 59 : fd_snapshot_manifest_epoch_stakes_t const * epoch_stakes, 60 0 : ulong * stake_weight_msg_out ) { 61 0 : fd_stake_weight_msg_t * stake_weight_msg = (fd_stake_weight_msg_t *)fd_type_pun( stake_weight_msg_out ); 62 0 : fd_vote_stake_weight_t * stake_weights = stake_weight_msg->weights; 63 : 64 0 : stake_weight_msg->epoch = epoch; 65 0 : stake_weight_msg->staked_cnt = epoch_stakes->vote_stakes_len; 66 0 : stake_weight_msg->start_slot = fd_epoch_slot0( epoch_schedule, epoch ); 67 0 : stake_weight_msg->slot_cnt = epoch_schedule->slots_per_epoch; 68 0 : stake_weight_msg->excluded_stake = 0UL; 69 0 : stake_weight_msg->vote_keyed_lsched = 1UL; 70 : 71 : /* FIXME: SIMD-0180 - hack to (de)activate in testnet vs mainnet. 72 : This code can be removed once the feature is active. */ 73 0 : { 74 0 : if( ( 1==epoch_schedule->warmup && epoch<FD_SIMD0180_ACTIVE_EPOCH_TESTNET ) 75 0 : || ( 0==epoch_schedule->warmup && epoch<FD_SIMD0180_ACTIVE_EPOCH_MAINNET ) ) { 76 0 : stake_weight_msg->vote_keyed_lsched = 0UL; 77 0 : } 78 0 : } 79 : 80 : /* epoch_stakes from manifest are already filtered (stake>0), but not sorted */ 81 0 : for( ulong i=0UL; i<epoch_stakes->vote_stakes_len; i++ ) { 82 0 : stake_weights[ i ].stake = epoch_stakes->vote_stakes[ i ].stake; 83 0 : memcpy( stake_weights[ i ].id_key.uc, epoch_stakes->vote_stakes[ i ].identity, sizeof(fd_pubkey_t) ); 84 0 : memcpy( stake_weights[ i ].vote_key.uc, epoch_stakes->vote_stakes[ i ].vote, sizeof(fd_pubkey_t) ); 85 0 : } 86 0 : sort_vote_weights_by_stake_vote_inplace( stake_weights, epoch_stakes->vote_stakes_len); 87 : 88 0 : return fd_stake_weight_msg_sz( epoch_stakes->vote_stakes_len ); 89 0 : } 90 : 91 : /* Execution tracking helpers */ 92 : 93 : struct fd_slice_exec { 94 : uchar * buf; /* Pointer to the memory region sized for max sz of a block. */ 95 : ulong wmark; /* Offset into slice where previous bytes have been executed, and following bytes have not. Will be on a transaction or microblock boundary. */ 96 : ulong sz; /* Total bytes this slice occupies in mbatch memory. New slices are placed at this offset */ 97 : ulong mblks_rem; /* Number of microblocks remaining in the current batch iteration. */ 98 : ulong txns_rem; /* Number of txns remaining in current microblock iteration. */ 99 : 100 : ulong last_mblk_off; /* Stored offset to the last microblock header seen. Updated during block execution. */ 101 : int last_batch; /* Signifies last batch execution. */ 102 : }; 103 : typedef struct fd_slice_exec fd_slice_exec_t; 104 : 105 : /* Note the current usage of slice_exec is that it is embedded directly 106 : in replay_tile_ctx_t, so there's no need for (_new) currently. */ 107 : 108 : fd_slice_exec_t * 109 : fd_slice_exec_join( void * slmem ); 110 : 111 : void 112 : fd_slice_exec_txn_parse( fd_slice_exec_t * slice_exec_ctx, 113 : fd_txn_p_t * txn_p_out ); 114 : 115 : void 116 : fd_slice_exec_microblock_parse( fd_slice_exec_t * slice_exec_ctx ); 117 : 118 : void 119 : fd_slice_exec_reset( fd_slice_exec_t * slice_exec_ctx ); 120 : 121 : void 122 : fd_slice_exec_begin( fd_slice_exec_t * slice_exec_ctx, 123 : ulong slice_sz, 124 : int last_batch ); 125 : 126 : static inline void 127 0 : fd_slice_exec_skip_slice( fd_slice_exec_t * slice_exec_ctx ) { 128 0 : slice_exec_ctx->mblks_rem = 0UL; 129 0 : slice_exec_ctx->txns_rem = 0UL; 130 0 : } 131 : 132 : static inline int 133 0 : fd_slice_exec_txn_ready( fd_slice_exec_t const * slice_exec_ctx ) { 134 0 : return slice_exec_ctx->txns_rem > 0UL; 135 0 : } 136 : 137 : static inline int 138 0 : fd_slice_exec_microblock_ready( fd_slice_exec_t const * slice_exec_ctx ) { 139 0 : return slice_exec_ctx->txns_rem == 0 && slice_exec_ctx->mblks_rem > 0UL; 140 0 : } 141 : 142 : static inline int 143 0 : fd_slice_exec_slice_ready( fd_slice_exec_t const * slice_exec_ctx ) { 144 0 : return slice_exec_ctx->txns_rem == 0 && slice_exec_ctx->mblks_rem == 0UL; 145 0 : } 146 : 147 : static inline int 148 0 : fd_slice_exec_slot_complete( fd_slice_exec_t const * slice_exec_ctx ) { 149 0 : return slice_exec_ctx->last_batch && slice_exec_ctx->mblks_rem == 0 && slice_exec_ctx->txns_rem == 0; 150 0 : } 151 : 152 : /* Exec tile msg link formatting. The following take a pointer into 153 : a dcache region and formats it as a specific message type. */ 154 : 155 : /* definition of the public/readable workspace */ 156 0 : #define EXEC_NEW_TXN_SIG (0x777777UL) 157 : 158 0 : #define FD_WRITER_BOOT_SIG (0xAABB0011UL) 159 : #define FD_WRITER_SLOT_SIG (0xBBBB1122UL) 160 0 : #define FD_WRITER_TXN_SIG (0xBBCC2233UL) 161 : 162 : #define FD_EXEC_STATE_NOT_BOOTED (0xFFFFFFFFUL) 163 : #define FD_EXEC_STATE_BOOTED (1<<1UL ) 164 : 165 : #define FD_EXEC_ID_SENTINEL (UINT_MAX ) 166 : 167 : /**********************************************************************/ 168 : 169 : /* fd_exec_txn_msg_t is the message that is sent from the replay tile to 170 : the exec tile. This represents all of the information that is needed 171 : to identify and execute a transaction against a bank. An idx to the 172 : bank in the bank pool must be sent over because the key of the bank 173 : will change as FEC sets are processed. */ 174 : 175 : struct fd_exec_txn_msg { 176 : ulong bank_idx; 177 : fd_txn_p_t txn; 178 : }; 179 : typedef struct fd_exec_txn_msg fd_exec_txn_msg_t; 180 : 181 : /* fd_exec_writer_boot_msg_t is the message sent from the exec tile to 182 : the writer tile on boot. This message contains the offset of the 183 : txn_ctx in the tile's exec spad. */ 184 : 185 : struct fd_exec_writer_boot_msg { 186 : uint txn_ctx_offset; 187 : }; 188 : typedef struct fd_exec_writer_boot_msg fd_exec_writer_boot_msg_t; 189 : FD_STATIC_ASSERT( sizeof(fd_exec_writer_boot_msg_t)<=FD_EXEC_WRITER_MTU, exec_writer_msg_mtu ); 190 : 191 : /* fd_exec_writer_txn_msg is the message sent from the exec tile to the 192 : writer tile after a transaction has been executed. This message 193 : contains the id of the exec tile that executed the transaction. */ 194 : 195 : struct fd_exec_writer_txn_msg { 196 : uchar exec_tile_id; 197 : }; 198 : typedef struct fd_exec_writer_txn_msg fd_exec_writer_txn_msg_t; 199 : FD_STATIC_ASSERT( sizeof(fd_exec_writer_txn_msg_t)<=FD_EXEC_WRITER_MTU, exec_writer_msg_mtu ); 200 : 201 : /* Writer->Replay message APIs ****************************************/ 202 : 203 : /* fd_writer_replay_txn_finalized_msg_t is the message sent from 204 : writer tile to replay tile, notifying the replay tile that a txn has 205 : been finalized. */ 206 : 207 : struct __attribute__((packed)) fd_writer_replay_txn_finalized_msg { 208 : int exec_tile_id; 209 : }; 210 : typedef struct fd_writer_replay_txn_finalized_msg fd_writer_replay_txn_finalized_msg_t; 211 : 212 : #endif /* HEADER_fd_src_discof_replay_fd_exec_h */