Line data Source code
1 : #ifndef HEADER_fd_src_choreo_votor_test_ag_cert_builder_h
2 : #define HEADER_fd_src_choreo_votor_test_ag_cert_builder_h
3 :
4 : /* Certificates are built incrementally in ag_slot_state.c as votes
5 : arrive. These rebuild one from a complete vote list, which tests
6 : need to get a cert in isolation; they are not part of the ag_cert
7 : API. */
8 :
9 : #include "ag_cert.h"
10 : #include "ag_epoch_info.h"
11 : #include "ag_vote.h"
12 :
13 : static inline void
14 : bls_key_from_sec( ag_bls_key_t out,
15 0 : fd_bls_sec_t const * sec ) {
16 0 : fd_bls_pub_t pub[1];
17 0 : fd_bls_sec_to_pub( sec, pub );
18 0 : blst_p1_affine_compress( out, pub );
19 0 : }
20 :
21 : /* epoch_info_build fills epoch_info from an already ranked validator
22 : list. Production ranks in the votor tile (rank_voters). */
23 :
24 : static inline void
25 : epoch_info_build( ag_epoch_info_t * epoch_info,
26 : ag_validator_info_t const * validators,
27 0 : ulong validator_cnt ) {
28 0 : epoch_info->total_stake = 0UL;
29 0 : for( ulong i=0UL; i<validator_cnt; i++ ) {
30 0 : FD_TEST( validators[i].id==i );
31 0 : epoch_info->validators[i] = validators[i];
32 0 : FD_TEST( !fd_bls_pub_de( &epoch_info->pubkeys[i], validators[i].bls_key, sizeof(ag_bls_key_t) ) );
33 0 : epoch_info->total_stake += validators[i].stake;
34 0 : }
35 0 : epoch_info->validator_cnt = validator_cnt;
36 0 : }
37 :
38 : static uchar const test_bls_public_key[ FD_BLS_PUB_COMPRESSED_SZ ] = {0};
39 :
40 : /* sec_sign_fn is the fd_bls_sign_fn of a test that holds the secret
41 : key in memory; ctx points to the fd_bls_sec_t. */
42 :
43 : static inline void
44 : sec_sign_fn( void * ctx,
45 : fd_bls_sig_t * sig,
46 : uchar const * public_key,
47 : uchar const * msg,
48 0 : ulong msg_sz ) {
49 0 : (void)public_key;
50 0 : fd_bls_sec_sign( (fd_bls_sec_t const *)ctx, msg, msg_sz, sig );
51 0 : }
52 :
53 : static inline void
54 : agg_add( fd_bls_agg_t * agg,
55 : ulong rank,
56 0 : fd_bls_sig_t const * sig ) {
57 0 : fd_bls_set_insert( agg->set, rank );
58 0 : blst_p2_add_or_double_affine( &agg->sig, &agg->sig, sig );
59 0 : }
60 :
61 : static inline int
62 0 : agg_is_identity( fd_bls_agg_t const * agg ) {
63 0 : return !!blst_p2_is_inf( &agg->sig );
64 0 : }
65 :
66 : static inline ag_cert_t
67 : cert_build_final( ag_vote_final_t const * votes, ulong vote_cnt, ag_epoch_info_t const * epoch_info );
68 : static inline ag_cert_t
69 : cert_build_fast_final( ag_vote_notar_t const * votes, ulong vote_cnt, ag_epoch_info_t const * epoch_info );
70 : static inline ag_cert_t
71 : cert_build_notar( ag_vote_notar_t const * votes, ulong vote_cnt, ag_epoch_info_t const * epoch_info );
72 : static inline ag_cert_t
73 : cert_build_notar_fallback( ag_vote_notar_t const * votes, ulong vote_cnt, ag_vote_notar_fallback_t const * fallback_votes, ulong fallback_vote_cnt, ag_epoch_info_t const * epoch_info );
74 : static inline ag_cert_t
75 : cert_build_skip( ag_vote_skip_t const * votes, ulong vote_cnt, ag_vote_skip_fallback_t const * fallback_votes, ulong fallback_vote_cnt, ag_epoch_info_t const * epoch_info );
76 :
77 : static inline ag_cert_t
78 : cert_build_final( ag_vote_final_t const * votes,
79 : ulong vote_cnt,
80 0 : ag_epoch_info_t const * epoch_info ) {
81 0 : ag_validator_info_t const * validators = ag_epoch_info_validators( epoch_info );
82 0 : FD_TEST( vote_cnt>0UL );
83 0 : ulong slot = votes[0].slot;
84 0 : ulong stake = 0UL;
85 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
86 0 : FD_TEST( votes[i].slot==slot );
87 0 : stake += validators[ votes[i].rank ].stake;
88 0 : }
89 0 : ag_cert_final_t cert;
90 0 : cert.slot = slot; cert.stake = stake; cert.shred_version = votes[0].shred_version;
91 0 : memset( &cert.agg, 0, sizeof(fd_bls_agg_t) );
92 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg, votes[i].rank, &votes[i].sig );
93 0 : return (ag_cert_t){ .kind = AG_CERT_KIND_FINAL, .final = cert };
94 0 : }
95 :
96 : static inline ag_cert_t
97 : cert_build_fast_final( ag_vote_notar_t const * votes,
98 : ulong vote_cnt,
99 0 : ag_epoch_info_t const * epoch_info ) {
100 0 : ag_cert_notar_t notar = cert_build_notar( votes, vote_cnt, epoch_info ).notar;
101 0 : ag_cert_fast_final_t cert;
102 0 : cert.slot = notar.slot; cert.stake = notar.stake; cert.agg = notar.agg; cert.shred_version = notar.shred_version;
103 0 : memcpy( cert.block_hash, notar.block_hash, sizeof(ag_block_hash_t) );
104 0 : return (ag_cert_t){ .kind = AG_CERT_KIND_FAST_FINAL, .fast_final = cert };
105 0 : }
106 :
107 : static inline ag_cert_t
108 : cert_build_notar( ag_vote_notar_t const * votes,
109 : ulong vote_cnt,
110 0 : ag_epoch_info_t const * epoch_info ) {
111 0 : ag_validator_info_t const * validators = ag_epoch_info_validators( epoch_info );
112 0 : FD_TEST( vote_cnt>0UL );
113 0 : ulong slot = votes[0].slot;
114 0 : ulong stake = 0UL;
115 0 : ag_block_hash_t block_hash;
116 0 : memcpy( block_hash, votes[0].block_hash, sizeof(ag_block_hash_t) );
117 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
118 0 : FD_TEST( votes[i].slot==slot );
119 0 : FD_TEST( !memcmp( votes[i].block_hash, block_hash, sizeof(ag_block_hash_t) ) );
120 0 : stake += validators[ votes[i].rank ].stake;
121 0 : }
122 0 : ag_cert_notar_t cert;
123 0 : cert.slot = slot; cert.stake = stake; cert.shred_version = votes[0].shred_version;
124 0 : memcpy( cert.block_hash, block_hash, sizeof(ag_block_hash_t) );
125 0 : memset( &cert.agg, 0, sizeof(fd_bls_agg_t) );
126 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg, votes[i].rank, &votes[i].sig );
127 0 : return (ag_cert_t){ .kind = AG_CERT_KIND_NOTAR, .notar = cert };
128 0 : }
129 :
130 : static inline ag_cert_t
131 : cert_build_notar_fallback( ag_vote_notar_t const * votes,
132 : ulong vote_cnt,
133 : ag_vote_notar_fallback_t const * fallback_votes,
134 : ulong fallback_vote_cnt,
135 0 : ag_epoch_info_t const * epoch_info ) {
136 0 : ag_validator_info_t const * validators = ag_epoch_info_validators( epoch_info );
137 0 : FD_TEST( vote_cnt>0UL || fallback_vote_cnt>0UL );
138 0 : ulong slot;
139 0 : ag_block_hash_t block_hash;
140 0 : if( vote_cnt>0UL ) { slot = votes[0].slot; memcpy( block_hash, votes[0].block_hash, sizeof(ag_block_hash_t) ); }
141 0 : else { slot = fallback_votes[0].slot; memcpy( block_hash, fallback_votes[0].block_hash, sizeof(ag_block_hash_t) ); }
142 :
143 0 : ulong stake = 0UL;
144 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
145 0 : FD_TEST( votes[i].slot==slot );
146 0 : FD_TEST( !memcmp( votes[i].block_hash, block_hash, sizeof(ag_block_hash_t) ) );
147 0 : stake += validators[ votes[i].rank ].stake;
148 0 : }
149 0 : ulong stake_fallback = 0UL;
150 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) {
151 0 : FD_TEST( fallback_votes[i].slot==slot );
152 0 : FD_TEST( !memcmp( fallback_votes[i].block_hash, block_hash, sizeof(ag_block_hash_t) ) );
153 0 : stake_fallback += validators[ fallback_votes[i].rank ].stake;
154 0 : }
155 :
156 0 : ag_cert_notar_fallback_t cert;
157 0 : cert.slot = slot; cert.shred_version = vote_cnt>0UL ? votes[0].shred_version : fallback_votes[0].shred_version;
158 0 : memcpy( cert.block_hash, block_hash, sizeof(ag_block_hash_t) );
159 0 : memset( &cert.agg_notar, 0, sizeof(fd_bls_agg_t) );
160 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg_notar, votes[i].rank, &votes[i].sig );
161 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_notar ) ) ) {
162 0 : memset( &cert.agg_notar, 0, sizeof(fd_bls_agg_t) );
163 0 : stake = 0UL;
164 0 : }
165 0 : memset( &cert.agg_notar_fallback, 0, sizeof(fd_bls_agg_t) );
166 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) agg_add( &cert.agg_notar_fallback, fallback_votes[i].rank, &fallback_votes[i].sig );
167 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_notar_fallback ) ) ) {
168 0 : memset( &cert.agg_notar_fallback, 0, sizeof(fd_bls_agg_t) );
169 0 : stake_fallback = 0UL;
170 0 : }
171 0 : cert.stake = stake + stake_fallback;
172 0 : return (ag_cert_t){ .kind = AG_CERT_KIND_NOTAR_FALLBACK, .notar_fallback = cert };
173 0 : }
174 :
175 : static inline ag_cert_t
176 : cert_build_skip( ag_vote_skip_t const * votes,
177 : ulong vote_cnt,
178 : ag_vote_skip_fallback_t const * fallback_votes,
179 : ulong fallback_vote_cnt,
180 0 : ag_epoch_info_t const * epoch_info ) {
181 0 : ag_validator_info_t const * validators = ag_epoch_info_validators( epoch_info );
182 0 : FD_TEST( vote_cnt>0UL || fallback_vote_cnt>0UL );
183 0 : ulong slot = vote_cnt>0UL ? votes[0].slot : fallback_votes[0].slot;
184 :
185 0 : ulong stake = 0UL;
186 0 : for( ulong i=0UL; i<vote_cnt; i++ ) {
187 0 : FD_TEST( votes[i].slot==slot );
188 0 : stake += validators[ votes[i].rank ].stake;
189 0 : }
190 0 : ulong stake_fallback = 0UL;
191 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) {
192 0 : FD_TEST( fallback_votes[i].slot==slot );
193 0 : stake_fallback += validators[ fallback_votes[i].rank ].stake;
194 0 : }
195 :
196 0 : ag_cert_skip_t cert;
197 0 : cert.slot = slot; cert.shred_version = vote_cnt>0UL ? votes[0].shred_version : fallback_votes[0].shred_version;
198 0 : memset( &cert.agg_skip, 0, sizeof(fd_bls_agg_t) );
199 0 : for( ulong i=0UL; i<vote_cnt; i++ ) agg_add( &cert.agg_skip, votes[i].rank, &votes[i].sig );
200 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_skip ) ) ) {
201 0 : memset( &cert.agg_skip, 0, sizeof(fd_bls_agg_t) );
202 0 : stake = 0UL;
203 0 : }
204 0 : memset( &cert.agg_skip_fallback, 0, sizeof(fd_bls_agg_t) );
205 0 : for( ulong i=0UL; i<fallback_vote_cnt; i++ ) agg_add( &cert.agg_skip_fallback, fallback_votes[i].rank, &fallback_votes[i].sig );
206 0 : if( FD_UNLIKELY( agg_is_identity( &cert.agg_skip_fallback ) ) ) {
207 0 : memset( &cert.agg_skip_fallback, 0, sizeof(fd_bls_agg_t) );
208 0 : stake_fallback = 0UL;
209 0 : }
210 0 : cert.stake = stake + stake_fallback;
211 0 : return (ag_cert_t){ .kind = AG_CERT_KIND_SKIP, .skip = cert };
212 0 : }
213 :
214 : #endif
|