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