Line data Source code
1 : #include "fd_tower_file.h"
2 :
3 : #include "../../ballet/ed25519/fd_ed25519.h"
4 :
5 : #define SAVED_TOWER_KIND (1U) /* SavedTowerVersions::Current */
6 : #define LAST_VOTE_KIND (3U) /* VoteTransaction::TowerSync */
7 : #define THRESHOLD_DEPTH (8UL)
8 : #define THRESHOLD_SIZE (2.0/3.0)
9 : #define TOWER_SYNC_MAX (512UL)
10 :
11 0 : #define SIG_OFF FD_TOWER_FILE_SIG_OFF
12 0 : #define DATA_OFF FD_TOWER_FILE_DATA_OFF
13 :
14 0 : #define LOAD( T, dst ) do { \
15 0 : if( FD_UNLIKELY( sizeof(T)>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE; \
16 0 : (dst) = FD_LOAD( T, buf+off ); \
17 0 : off += sizeof(T); \
18 0 : } while(0)
19 :
20 0 : #define SKIP( sz ) do { \
21 0 : if( FD_UNLIKELY( (sz)>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE; \
22 0 : off += (sz); \
23 0 : } while(0)
24 :
25 : int
26 : fd_tower_file_de( uchar const * buf,
27 : ulong buf_sz,
28 : fd_pubkey_t const * identity,
29 0 : fd_tower_file_t * out ) {
30 0 : if( FD_UNLIKELY( buf_sz>FD_TOWER_FILE_MAX ) ) return FD_TOWER_FILE_ERR_SIZE;
31 0 : ulong off = 0UL;
32 :
33 0 : uint kind; LOAD( uint, kind );
34 0 : if( FD_UNLIKELY( kind!=SAVED_TOWER_KIND ) ) return FD_TOWER_FILE_ERR_VERSION;
35 :
36 0 : if( FD_UNLIKELY( buf_sz<DATA_OFF ) ) return FD_TOWER_FILE_ERR_SIZE;
37 0 : uchar const * sig = buf+SIG_OFF;
38 0 : off = SIG_OFF+64UL;
39 0 : ulong data_sz; LOAD( ulong, data_sz );
40 0 : if( FD_UNLIKELY( data_sz!=buf_sz-DATA_OFF ) ) return FD_TOWER_FILE_ERR_SIZE;
41 :
42 0 : fd_sha512_t sha[ 1 ];
43 0 : if( FD_UNLIKELY( FD_ED25519_SUCCESS!=fd_ed25519_verify( buf+DATA_OFF, data_sz, sig, identity->uc, sha ) ) ) return FD_TOWER_FILE_ERR_SIG;
44 :
45 0 : if( FD_UNLIKELY( 32UL>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE;
46 0 : if( FD_UNLIKELY( !fd_memeq( buf+off, identity->uc, 32UL ) ) ) return FD_TOWER_FILE_ERR_IDENTITY;
47 0 : off += 32UL;
48 :
49 0 : ulong threshold_depth; LOAD( ulong, threshold_depth );
50 0 : double threshold_size; LOAD( double, threshold_size );
51 0 : if( FD_UNLIKELY( threshold_depth!=THRESHOLD_DEPTH ) ) return FD_TOWER_FILE_ERR_TOWER;
52 0 : if( FD_UNLIKELY( threshold_size !=THRESHOLD_SIZE ) ) return FD_TOWER_FILE_ERR_TOWER;
53 :
54 0 : SKIP( 32UL ); /* node_pubkey */
55 0 : SKIP( 32UL ); /* authorized_withdrawer */
56 0 : SKIP( 1UL ); /* commission */
57 :
58 0 : ulong votes_cnt; LOAD( ulong, votes_cnt );
59 0 : if( FD_UNLIKELY( !votes_cnt || votes_cnt>FD_TOWER_VOTE_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
60 0 : fd_tower_vote_t votes[ FD_TOWER_VOTE_MAX ];
61 0 : for( ulong i=0UL; i<votes_cnt; i++ ) {
62 0 : ulong slot; LOAD( ulong, slot );
63 0 : uint conf; LOAD( uint, conf );
64 0 : votes[ i ].slot = slot;
65 0 : votes[ i ].conf = conf;
66 0 : }
67 :
68 0 : uchar has_root; LOAD( uchar, has_root );
69 0 : if( FD_UNLIKELY( has_root!=1 ) ) return FD_TOWER_FILE_ERR_TOWER;
70 0 : ulong root; LOAD( ulong, root );
71 0 : if( FD_UNLIKELY( root==ULONG_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
72 :
73 0 : ulong authorized_voters_cnt; LOAD( ulong, authorized_voters_cnt );
74 0 : if( FD_UNLIKELY( authorized_voters_cnt>(buf_sz-off)/40UL ) ) return FD_TOWER_FILE_ERR_SIZE;
75 0 : SKIP( authorized_voters_cnt*40UL );
76 0 : SKIP( 32UL*48UL+8UL ); /* prior_voters buf, idx */
77 0 : uchar prior_voters_empty; LOAD( uchar, prior_voters_empty );
78 0 : if( FD_UNLIKELY( prior_voters_empty>1U ) ) return FD_TOWER_FILE_ERR_TOWER;
79 0 : ulong epoch_credits_cnt; LOAD( ulong, epoch_credits_cnt );
80 0 : if( FD_UNLIKELY( epoch_credits_cnt>(buf_sz-off)/24UL ) ) return FD_TOWER_FILE_ERR_SIZE;
81 0 : SKIP( epoch_credits_cnt*24UL );
82 0 : SKIP( 8UL ); /* last_timestamp slot */
83 0 : SKIP( 8UL ); /* last_timestamp ts */
84 :
85 0 : uint last_vote_kind; LOAD( uint, last_vote_kind );
86 0 : if( FD_UNLIKELY( last_vote_kind!=LAST_VOTE_KIND ) ) return FD_TOWER_FILE_ERR_VERSION;
87 :
88 0 : if( FD_UNLIKELY( off>buf_sz || buf_sz-off<16UL ) ) return FD_TOWER_FILE_ERR_SIZE;
89 0 : ulong sync_sz = buf_sz-off-16UL;
90 0 : fd_compact_tower_sync_serde_t sync;
91 0 : if( FD_UNLIKELY( fd_compact_tower_sync_de( &sync, buf+off, sync_sz ) ) ) return FD_TOWER_FILE_ERR_TOWER;
92 :
93 0 : uchar sync_buf[ TOWER_SYNC_MAX ];
94 0 : ulong canonical_sz;
95 0 : if( FD_UNLIKELY( fd_compact_tower_sync_ser( &sync, sync_buf, sizeof(sync_buf), &canonical_sz ) ) ) return FD_TOWER_FILE_ERR_TOWER;
96 0 : if( FD_UNLIKELY( canonical_sz!=sync_sz || !fd_memeq( sync_buf, buf+off, sync_sz ) ) ) return FD_TOWER_FILE_ERR_SIZE;
97 0 : if( FD_UNLIKELY( sync.root!=root || sync.lockouts_cnt!=votes_cnt ) ) return FD_TOWER_FILE_ERR_TOWER;
98 :
99 0 : fd_tower_vote_t decoded[ FD_TOWER_VOTE_MAX ];
100 0 : ulong decoded_cnt;
101 0 : ulong decoded_root;
102 0 : if( FD_UNLIKELY( fd_compact_tower_sync_to_votes( &sync, decoded, &decoded_cnt, &decoded_root ) ) ) return FD_TOWER_FILE_ERR_TOWER;
103 0 : if( FD_UNLIKELY( decoded_cnt!=votes_cnt || decoded_root!=root ||
104 0 : !fd_memeq( decoded, votes, votes_cnt*sizeof(fd_tower_vote_t) ) ) ) return FD_TOWER_FILE_ERR_TOWER;
105 0 : if( FD_UNLIKELY( votes[ votes_cnt-1UL ].slot==ULONG_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
106 :
107 0 : off += sync_sz;
108 0 : ulong last_timestamp_slot; LOAD( ulong, last_timestamp_slot );
109 0 : long last_timestamp; LOAD( long, last_timestamp );
110 0 : if( FD_UNLIKELY( off!=buf_sz ) ) return FD_TOWER_FILE_ERR_SIZE;
111 :
112 0 : fd_memset( out, 0, sizeof(fd_tower_file_t) );
113 0 : fd_memcpy( out->votes, votes, votes_cnt*sizeof(fd_tower_vote_t) );
114 0 : out->votes_cnt = votes_cnt;
115 0 : out->root = root;
116 0 : out->bank_hash = sync.hash;
117 0 : out->block_id = sync.block_id;
118 0 : out->timestamp_slot = last_timestamp_slot;
119 0 : out->timestamp = last_timestamp;
120 :
121 0 : return FD_TOWER_FILE_SUCCESS;
122 0 : }
123 :
124 : #undef LOAD
125 : #undef SKIP
126 :
127 : ulong
128 : fd_tower_file_ser( fd_compact_tower_sync_serde_t const * sync,
129 : fd_pubkey_t const * identity,
130 0 : uchar buf[ static FD_TOWER_FILE_MAX ] ) {
131 0 : fd_tower_vote_t votes[ FD_TOWER_VOTE_MAX ];
132 0 : ulong votes_cnt;
133 0 : ulong root;
134 0 : FD_TEST( !fd_compact_tower_sync_to_votes( sync, votes, &votes_cnt, &root ) && votes_cnt );
135 0 : ulong last = votes[ votes_cnt-1UL ].slot;
136 0 : long timestamp = fd_long_if( sync->timestamp_option, sync->timestamp, 0L );
137 :
138 0 : ulong off = DATA_OFF;
139 0 : # define PUT( T, v ) do { FD_STORE( T, buf+off, (v) ); off += sizeof(T); } while(0)
140 0 : fd_memcpy( buf+off, identity->uc, 32UL ); off += 32UL;
141 0 : PUT( ulong, THRESHOLD_DEPTH );
142 0 : PUT( double, THRESHOLD_SIZE );
143 0 : fd_memset( buf+off, 0, 65UL ); off += 65UL; /* node_pubkey, authorized_withdrawer, commission */
144 0 : PUT( ulong, votes_cnt );
145 0 : for( ulong i=0UL; i<votes_cnt; i++ ) {
146 0 : PUT( ulong, votes[ i ].slot );
147 0 : PUT( uint, (uint)votes[ i ].conf );
148 0 : }
149 0 : PUT( uchar, root!=ULONG_MAX );
150 0 : if( root!=ULONG_MAX ) PUT( ulong, root );
151 0 : PUT( ulong, 0UL ); /* authorized_voters */
152 0 : fd_memset( buf+off, 0, 32UL*48UL+8UL ); off += 32UL*48UL+8UL; /* prior_voters buf, idx */
153 0 : PUT( uchar, 1 ); /* prior_voters is_empty */
154 0 : PUT( ulong, 0UL ); /* epoch_credits */
155 0 : PUT( ulong, 0UL ); PUT( long, 0L ); /* vote_state last_timestamp */
156 0 : PUT( uint, LAST_VOTE_KIND );
157 0 : ulong sync_sz;
158 0 : FD_TEST( !fd_compact_tower_sync_ser( sync, buf+off, FD_TOWER_FILE_MAX-off, &sync_sz ) );
159 0 : off += sync_sz;
160 0 : PUT( ulong, last ); PUT( long, timestamp ); /* last_timestamp */
161 0 : # undef PUT
162 :
163 0 : FD_STORE( uint, buf, SAVED_TOWER_KIND );
164 0 : FD_STORE( ulong, buf+SIG_OFF+64UL, off-DATA_OFF );
165 0 : return off;
166 0 : }
|