Line data Source code
1 : #include "fd_ssmanifest_writer.h"
2 : #include "../../flamenco/runtime/fd_system_ids.h"
3 : #include "../../flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h"
4 : #include "../../flamenco/runtime/program/vote/fd_vote_state_versioned.h"
5 : #include "../../ballet/bls/fd_bls.h"
6 :
7 : #define SORT_NAME sort_epoch_vote_by_node
8 0 : #define SORT_KEY_T fd_ssmanifest_epoch_vote_t
9 0 : #define SORT_BEFORE(a,b) (0>memcmp( (a).node.uc, (b).node.uc, sizeof(fd_pubkey_t) ))
10 : #include "../../util/tmpl/fd_sort.c"
11 :
12 0 : #define STATE_BLOCKHASH_QUEUE 1
13 0 : #define STATE_HASHES 2
14 0 : #define STATE_HARD_FORKS 3
15 0 : #define STATE_COUNTERS 4
16 0 : #define STATE_VOTE_ACCOUNTS 5
17 0 : #define STATE_STAKE_DELEGATION 6
18 0 : #define STATE_STAKE_EPOCH 7
19 0 : #define STATE_STAKE_HISTORY 8
20 0 : #define STATE_BANK_TRAILER 9
21 0 : #define STATE_ACCOUNT_STORAGE_ENTRY 10
22 0 : #define STATE_BANK_HASH_INFO 11
23 0 : #define STATE_EPOCH_STAKES 12
24 0 : #define STATE_EPOCH_STAKES_STAKES 13
25 0 : #define STATE_EPOCH_STAKES_EPOCH 14
26 0 : #define STATE_EPOCH_STAKE_HISTORY 15
27 0 : #define STATE_EPOCH_TOTAL_STAKE 16
28 0 : #define STATE_NODE_VOTE_ACCOUNTS 17
29 0 : #define STATE_AUTH_VOTER 18
30 0 : #define STATE_LTHASH 19
31 0 : #define STATE_BLOCK_ID 20
32 0 : #define STATE_DONE 21
33 0 : #define STATE_INIT STATE_BLOCKHASH_QUEUE
34 :
35 : /* Epoch stakes entries are keyed max(E-3,0)..E+1, as agave retains.
36 : Key E+1 is the t-1 set with credits, E the t-2 set, E-1..E-3 the
37 : t-3..t-5 sets. */
38 :
39 : static inline ulong
40 : epoch_stakes_key( fd_bank_t const * bank,
41 0 : ulong epoch_idx ) {
42 0 : ulong epoch = bank->f.epoch;
43 0 : return ( epoch>3UL ? epoch-3UL : 0UL ) + epoch_idx;
44 0 : }
45 :
46 : static inline int
47 : epoch_stakes_iter_kind( fd_bank_t const * bank,
48 0 : ulong epoch_idx ) {
49 0 : return (int)( bank->f.epoch + 2UL - epoch_stakes_key( bank, epoch_idx ) );
50 0 : }
51 :
52 : static fd_epoch_credits_t const *
53 : find_epoch_credits( fd_bank_t * bank,
54 0 : fd_pubkey_t const * pubkey ) {
55 0 : ulong epoch_credits_len;
56 0 : fd_epoch_credits_t const * epoch_credits_arr = fd_epoch_credits_store_peek( fd_bank_epoch_credits( bank ), bank->epoch_credits_fork_id, &epoch_credits_len );
57 0 : for( ulong i=0UL; i<epoch_credits_len; i++ ) {
58 0 : fd_epoch_credits_t const * epoch_credits = &epoch_credits_arr[ i ];
59 0 : if( fd_memeq( epoch_credits->pubkey, pubkey, sizeof(fd_pubkey_t) ) ) return epoch_credits;
60 0 : }
61 0 : return NULL;
62 0 : }
63 :
64 : /* Size estimate */
65 :
66 : #define ENCODE_FN static ulong manifest_estimate( fd_ssmanifest_writer_t * enc )
67 0 : #define PREP ulong sz = 0UL;
68 0 : #define PUSH_VAL(t,n) do { sz += sizeof(t); (void)(n); } while(0)
69 0 : #define RET_EXPR sz
70 : #include "fd_ssmanifest_encoder.c"
71 :
72 : fd_ssmanifest_writer_t *
73 : fd_ssmanifest_writer_init( fd_ssmanifest_writer_t * enc,
74 : fd_bank_t * bank,
75 : fd_pubkey_t const * leader,
76 : fd_accdb_t * accdb,
77 : fd_accdb_fork_id_t accdb_fork_id,
78 0 : uchar * acc_data ) {
79 0 : enc->state = STATE_BLOCKHASH_QUEUE;
80 0 : enc->bank = bank;
81 0 : enc->leader = *leader;
82 0 : enc->epoch_idx = 0;
83 0 : enc->epoch_cnt = 0;
84 0 : enc->vote_cnt = 0;
85 0 : enc->vote_idx = 0;
86 0 : enc->total_stake = 0UL;
87 :
88 0 : fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
89 0 : ulong fork_id = bank->vote_stakes_fork_id;
90 0 : ulong epoch_cnt = fd_ulong_min( bank->f.epoch, 3UL ) + 2UL;
91 0 : for( ulong epoch_idx=0UL; epoch_idx<epoch_cnt; epoch_idx++ ) {
92 0 : fd_ssmanifest_epoch_map_t * map = &enc->epoch_map[ epoch_idx ];
93 0 : ulong epoch_key = epoch_stakes_key( bank, epoch_idx );
94 0 : int iter_kind = epoch_stakes_iter_kind( bank, epoch_idx );
95 :
96 : /* Agave only reads the maps of the previous, current and next
97 : epoch. Older sets keep empty maps. */
98 0 : map->vote_cnt = 0UL;
99 0 : map->node_cnt = 0UL;
100 0 : if( iter_kind>FD_VOTE_STAKES_ITER_T_3 ) continue;
101 :
102 0 : for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, iter_kind, enc->vote_stakes_iter_mem );
103 0 : !fd_vote_stakes_iter_done( vote_stakes, fork_id, iter_kind, iter );
104 0 : fd_vote_stakes_iter_next( vote_stakes, fork_id, iter_kind, iter ) ) {
105 0 : fd_ssmanifest_epoch_vote_t * ele = &map->vote[ map->vote_cnt ];
106 0 : fd_vote_stakes_ele_t vs_ele[1];
107 0 : fd_vote_stakes_iter_ele( vote_stakes, fork_id, iter_kind, iter, vs_ele );
108 0 : ele->vote = vs_ele->pubkey;
109 0 : ele->node = vs_ele->node_account;
110 0 : ele->stake = vs_ele->stake;
111 :
112 0 : ulong lamports;
113 0 : int executable;
114 0 : uchar owner[ 32UL ];
115 0 : ulong data_len;
116 0 : fd_accdb_read_one_nocache( accdb, accdb_fork_id, ele->vote.uc, &lamports, &executable, owner, acc_data, &data_len );
117 0 : if( FD_UNLIKELY( !lamports ||
118 0 : !fd_vsv_is_correct_size_owner_and_init( owner, acc_data, data_len ) ||
119 0 : fd_vote_account_authorized_voter( acc_data, data_len, epoch_key, &ele->voter ) ) ) {
120 0 : continue;
121 0 : }
122 0 : map->vote_cnt++;
123 0 : }
124 :
125 0 : sort_epoch_vote_by_node_inplace( map->vote, map->vote_cnt );
126 0 : for( ulong i=0UL; i<map->vote_cnt; i++ ) {
127 0 : int new_node = ( i==0UL ) || !fd_memeq( map->vote[ i ].node.uc, map->vote[ i-1UL ].node.uc, sizeof(fd_pubkey_t) );
128 0 : if( new_node ) {
129 0 : map->node_cnt++;
130 0 : }
131 0 : }
132 0 : }
133 :
134 0 : enc->serialized_sz = 0UL;
135 0 : for(;;) {
136 0 : ulong chunk = manifest_estimate( enc );
137 0 : if( FD_UNLIKELY( !chunk ) ) break;
138 0 : enc->serialized_sz += chunk;
139 0 : }
140 0 : return enc;
141 0 : }
142 :
143 : /* Actual encoder */
144 :
145 : __attribute__((cold,noreturn))
146 : static void fail( fd_ssmanifest_writer_t const * enc,
147 : ulong buf_sz,
148 0 : ulong line_nr ) {
149 0 : FD_LOG_ERR(( "buffer overflow (state=%u, buf_sz=%lu, line_nr=%lu)", enc->state, buf_sz, line_nr ));
150 0 : }
151 :
152 : #define ENCODE_FN \
153 : ulong \
154 : fd_snap_manifest_serialize( fd_ssmanifest_writer_t * enc, \
155 : uchar out_buf[ FD_SSMANIFEST_BUF_MIN ], \
156 : ulong buf_sz )
157 : #define PREP \
158 0 : uchar * p = out_buf; \
159 0 : uchar * p1 = out_buf+buf_sz;
160 : #define PUSH_VAL( t, n ) \
161 0 : FD_STORE( t, __extension__({ \
162 0 : /* compile time bounds check elide */ \
163 0 : if( FD_UNLIKELY( p+sizeof(t) > p1 ) ) fail( enc, buf_sz, __LINE__ ); \
164 0 : uchar * ret = p; \
165 0 : p += sizeof(t); \
166 0 : ret; \
167 0 : }), (n) )
168 0 : #define RET_EXPR (ulong)( p - out_buf )
169 : #include "fd_ssmanifest_encoder.c"
|