Line data Source code
1 : #include "fd_genesis_parse.h"
2 : #include "../runtime/fd_runtime_const.h"
3 : #include "../../util/bits/fd_bits.h"
4 :
5 : #include <stddef.h>
6 :
7 : FD_STATIC_ASSERT( alignof(fd_genesis_t)<=FD_GENESIS_ALIGN, fd_genesis_align );
8 : FD_STATIC_ASSERT( offsetof(fd_genesis_t, account)==sizeof(fd_genesis_t), fd_genesis_footprint );
9 :
10 : ulong
11 0 : fd_genesis_align( void ) {
12 0 : return FD_GENESIS_ALIGN;
13 0 : }
14 :
15 : ulong
16 0 : fd_genesis_footprint( ulong account_max ) {
17 0 : return FD_GENESIS_FOOTPRINT( account_max );
18 0 : }
19 :
20 : fd_genesis_t *
21 : fd_genesis_new( void * mem,
22 0 : ulong account_max ) {
23 0 : if( FD_UNLIKELY( !mem ) ) {
24 0 : FD_LOG_WARNING(( "NULL mem" ));
25 0 : return NULL;
26 0 : }
27 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_GENESIS_ALIGN ) ) ) {
28 0 : FD_LOG_WARNING(( "misaligned mem" ));
29 0 : return NULL;
30 0 : }
31 0 : fd_genesis_t * genesis = (fd_genesis_t *)mem;
32 0 : memset( genesis, 0, sizeof(fd_genesis_t) );
33 0 : genesis->account_max = account_max;
34 0 : return genesis;
35 0 : }
36 :
37 : fd_genesis_t *
38 : fd_genesis_parse( fd_genesis_t * genesis,
39 : uchar const * bin,
40 0 : ulong bin_sz ) {
41 : /* Zero out top part of descriptor which is sufficient to fully
42 : initialize fd_genesis_t (assuming no struct reordering). The
43 : account_max capacity set by fd_genesis_new lives after builtin and
44 : is preserved. */
45 0 : memset( genesis, 0, offsetof(fd_genesis_t, builtin) );
46 :
47 0 : uchar const * _payload = bin;
48 0 : ulong const _payload_sz = bin_sz;
49 0 : ulong _i = 0UL;
50 :
51 0 : # define CHECK( cond ) { if( FD_UNLIKELY( !(cond) ) ) { return NULL; } }
52 0 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
53 0 : # define INC( n ) (_i += (ulong)(n))
54 0 : # define CUR_OFFSET ((ushort)_i)
55 0 : # define CURSOR (_payload+_i)
56 :
57 0 : CHECK_LEFT( 8UL ); genesis->creation_time = FD_LOAD( ulong, CURSOR ); INC( 8UL );
58 :
59 0 : CHECK_LEFT( 8UL ); genesis->account_cnt = FD_LOAD( ulong, CURSOR ); INC( 8UL );
60 0 : if( FD_UNLIKELY( genesis->account_cnt>genesis->account_max ) ) {
61 0 : FD_LOG_WARNING(( "genesis account count %lu exceeds account table capacity %lu (a %lu byte blob holds at most %lu accounts; malformed genesis?)",
62 0 : genesis->account_cnt, genesis->account_max, bin_sz, fd_genesis_account_max( bin_sz ) ));
63 0 : return NULL;
64 0 : }
65 0 : for( ulong i=0UL; i<genesis->account_cnt; i++ ) {
66 0 : fd_genesis_account_off_t * account = &genesis->account[ i ];
67 :
68 0 : account->pubkey_off = _i;
69 0 : CHECK_LEFT( 32UL ); INC( 32UL ); /* pubkey */
70 0 : CHECK_LEFT( 8UL ); INC( 8UL ); /* lamports */
71 0 : CHECK_LEFT( 8UL ); ulong data_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
72 0 : if( FD_UNLIKELY( data_len>FD_RUNTIME_ACC_SZ_MAX ) ) {
73 0 : FD_LOG_WARNING(( "genesis builtin account data length %lu exceeds max size %lu", data_len, FD_RUNTIME_ACC_SZ_MAX ));
74 0 : return NULL;
75 0 : }
76 0 : CHECK_LEFT( data_len ); INC( data_len ); /* data */
77 :
78 0 : account->owner_off = _i;
79 0 : CHECK_LEFT( 32UL ); INC( 32UL ); /* owner */
80 0 : CHECK_LEFT( 1UL ); CHECK( FD_LOAD( uchar, CURSOR )<=1U ); INC( 1UL ); /* executable */
81 0 : CHECK_LEFT( 8UL ); INC( 8UL ); /* rent epoch */
82 0 : }
83 :
84 0 : CHECK_LEFT( 8UL ); genesis->builtin_cnt = FD_LOAD( ulong, CURSOR ); INC( 8UL );
85 0 : if( FD_UNLIKELY( genesis->builtin_cnt>FD_GENESIS_BUILTIN_MAX_COUNT ) ) {
86 0 : FD_LOG_WARNING(( "genesis builtin count %lu exceeds max %lu", genesis->builtin_cnt, FD_GENESIS_BUILTIN_MAX_COUNT ));
87 0 : return NULL;
88 0 : }
89 0 : for( ulong i=0UL; i<genesis->builtin_cnt; i++ ) {
90 0 : fd_genesis_builtin_off_t * account = &genesis->builtin[ i ];
91 :
92 0 : account->data_len_off = _i;
93 0 : CHECK_LEFT( 8UL ); ulong data_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
94 0 : if( FD_UNLIKELY( data_len>FD_RUNTIME_ACC_SZ_MAX ) ) {
95 0 : FD_LOG_WARNING(( "genesis builtin account data length %lu exceeds supported max size %lu", data_len, FD_RUNTIME_ACC_SZ_MAX ));
96 0 : return NULL;
97 0 : }
98 0 : CHECK_LEFT( data_len ); INC( data_len ); /* data */
99 :
100 0 : account->pubkey_off = _i;
101 0 : CHECK_LEFT( 32UL ); INC( 32UL ); /* pubkey */
102 0 : }
103 :
104 0 : CHECK_LEFT( 8UL ); ulong rewards_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
105 0 : for( ulong i=0UL; i<rewards_len; i++ ) {
106 0 : CHECK_LEFT( 32UL ); INC( 32UL ); /* pubkey */
107 0 : CHECK_LEFT( 8UL ); INC( 8UL ); /* lamports */
108 0 : CHECK_LEFT( 8UL ); ulong dlen = FD_LOAD( ulong, CURSOR ); INC( 8UL ); /* dlen */
109 0 : CHECK_LEFT( dlen ); INC( dlen ); /* data */
110 0 : CHECK_LEFT( 32UL ); INC( 32UL ); /* owner */
111 0 : CHECK_LEFT( 1UL ); CHECK( FD_LOAD( uchar, CURSOR )<=1U ); INC( 1UL ); /* executable */
112 0 : CHECK_LEFT( 8UL ); INC( 8UL ); /* rent epoch */
113 0 : }
114 :
115 0 : CHECK_LEFT( 8UL ); genesis->poh.ticks_per_slot = FD_LOAD( ulong, CURSOR ); INC( 8UL );
116 0 : if( FD_UNLIKELY( !genesis->poh.ticks_per_slot ) ) {
117 0 : FD_LOG_WARNING(( "genesis ticks_per_slot must be non-zero" ));
118 0 : return NULL;
119 0 : }
120 :
121 0 : CHECK_LEFT( sizeof(ulong) ); INC( sizeof(ulong) ); /* unused */
122 :
123 0 : CHECK_LEFT( 8UL ); genesis->poh.tick_duration_secs = FD_LOAD( ulong, CURSOR ); INC( 8UL );
124 0 : CHECK_LEFT( 4UL ); genesis->poh.tick_duration_ns = FD_LOAD( uint, CURSOR ); INC( 4UL );
125 0 : CHECK_LEFT( 1UL ); int has_target_tick_count = FD_LOAD( uchar, CURSOR ); INC( 1UL );
126 0 : CHECK( has_target_tick_count<=1 );
127 0 : if( has_target_tick_count ) { CHECK_LEFT( 8UL ); genesis->poh.target_tick_count = FD_LOAD( ulong, CURSOR ); INC( 8UL ); }
128 0 : else genesis->poh.target_tick_count = 0UL;
129 0 : CHECK_LEFT( 1UL ); int has_hashes_per_tick = FD_LOAD( uchar, CURSOR ); INC( 1UL );
130 0 : CHECK( has_hashes_per_tick<=1 );
131 0 : if( has_hashes_per_tick ) { CHECK_LEFT( 8UL ); genesis->poh.hashes_per_tick = FD_LOAD( ulong, CURSOR ); INC( 8UL ); }
132 0 : else genesis->poh.hashes_per_tick = 0UL;
133 :
134 0 : CHECK_LEFT( sizeof(ulong) ); INC( sizeof(ulong) ); /* backward compat v23 */
135 :
136 0 : CHECK_LEFT( 8UL ); genesis->fee_rate_governor.target_lamports_per_signature = FD_LOAD( ulong, CURSOR ); INC( 8UL );
137 0 : CHECK_LEFT( 8UL ); genesis->fee_rate_governor.target_signatures_per_slot = FD_LOAD( ulong, CURSOR ); INC( 8UL );
138 0 : CHECK_LEFT( 8UL ); genesis->fee_rate_governor.min_lamports_per_signature = FD_LOAD( ulong, CURSOR ); INC( 8UL );
139 0 : CHECK_LEFT( 8UL ); genesis->fee_rate_governor.max_lamports_per_signature = FD_LOAD( ulong, CURSOR ); INC( 8UL );
140 0 : CHECK_LEFT( 1UL ); genesis->fee_rate_governor.burn_percent = FD_LOAD( uchar, CURSOR ); INC( 1UL );
141 :
142 0 : CHECK_LEFT( 8UL ); genesis->rent.lamports_per_uint8_year = FD_LOAD( ulong, CURSOR ); INC( 8UL );
143 0 : CHECK_LEFT( 8UL ); genesis->rent.exemption_threshold = FD_LOAD( double, CURSOR ); INC( 8UL );
144 0 : CHECK_LEFT( 1UL ); genesis->rent.burn_percent = FD_LOAD( uchar, CURSOR ); INC( 1UL );
145 :
146 0 : CHECK_LEFT( 8UL ); genesis->inflation.initial = FD_LOAD( double, CURSOR ); INC( 8UL );
147 0 : CHECK_LEFT( 8UL ); genesis->inflation.terminal = FD_LOAD( double, CURSOR ); INC( 8UL );
148 0 : CHECK_LEFT( 8UL ); genesis->inflation.taper = FD_LOAD( double, CURSOR ); INC( 8UL );
149 0 : CHECK_LEFT( 8UL ); genesis->inflation.foundation = FD_LOAD( double, CURSOR ); INC( 8UL );
150 0 : CHECK_LEFT( 8UL ); genesis->inflation.foundation_term = FD_LOAD( double, CURSOR ); INC( 8UL );
151 0 : CHECK_LEFT( 8UL ); INC( 8UL ); /* unused */
152 :
153 0 : CHECK_LEFT( 8UL ); genesis->epoch_schedule.slots_per_epoch = FD_LOAD( ulong, CURSOR ); INC( 8UL );
154 0 : if( FD_UNLIKELY( genesis->epoch_schedule.slots_per_epoch>FD_RUNTIME_SLOTS_PER_EPOCH ) ) {
155 0 : FD_LOG_WARNING(( "genesis slots_per_epoch %lu exceeds supported max %lu", genesis->epoch_schedule.slots_per_epoch, FD_RUNTIME_SLOTS_PER_EPOCH ));
156 0 : return NULL;
157 0 : }
158 0 : CHECK_LEFT( 8UL ); genesis->epoch_schedule.leader_schedule_slot_offset = FD_LOAD( ulong, CURSOR ); INC( 8UL );
159 0 : CHECK_LEFT( 1UL ); genesis->epoch_schedule.warmup = FD_LOAD( uchar, CURSOR ); INC( 1UL );
160 0 : CHECK( genesis->epoch_schedule.warmup<=1U );
161 0 : CHECK_LEFT( 8UL ); genesis->epoch_schedule.first_normal_epoch = FD_LOAD( ulong, CURSOR ); INC( 8UL );
162 0 : CHECK_LEFT( 8UL ); genesis->epoch_schedule.first_normal_slot = FD_LOAD( ulong, CURSOR ); INC( 8UL );
163 :
164 0 : CHECK_LEFT( 4UL ); genesis->cluster_type = FD_LOAD( uint, CURSOR ); INC( 4UL );
165 :
166 0 : # undef CHECK
167 0 : # undef CHECK_LEFT
168 0 : # undef INC
169 0 : # undef CUR_OFFSET
170 0 : # undef CURSOR
171 :
172 0 : if( _i!=_payload_sz ) {
173 0 : FD_LOG_WARNING(( "genesis blob has %lu trailing unrecognized bytes. Perhaps this Firedancer build is too old?", _payload_sz-_i ));
174 0 : return NULL;
175 0 : }
176 :
177 0 : return genesis;
178 0 : }
179 :
180 : fd_genesis_account_t *
181 : fd_genesis_account( fd_genesis_t const * genesis,
182 : uchar const * bin,
183 : fd_genesis_account_t * out,
184 0 : ulong idx ) {
185 0 : fd_genesis_account_off_t const * off = &genesis->account[ idx ];
186 0 : out->pubkey = FD_LOAD( fd_pubkey_t, bin+off->pubkey_off );
187 0 : out->lamports = FD_LOAD( ulong, bin+off->pubkey_off+32UL );
188 0 : out->data_len = (uint)FD_LOAD( ulong, bin+off->pubkey_off+40UL );
189 0 : out->data = bin+off->pubkey_off+48UL;
190 0 : memcpy( out->owner.uc, bin+off->owner_off, sizeof(fd_pubkey_t) );
191 0 : out->executable = !!bin[ off->owner_off+32UL ];
192 0 : return out;
193 0 : }
194 :
195 : fd_genesis_builtin_t *
196 : fd_genesis_builtin( fd_genesis_t const * genesis,
197 : uchar const * bin,
198 : fd_genesis_builtin_t * out,
199 0 : ulong idx ) {
200 0 : fd_genesis_builtin_off_t const * off = &genesis->builtin[ idx ];
201 0 : out->pubkey = FD_LOAD( fd_pubkey_t, bin+off->pubkey_off );
202 0 : out->data_len = FD_LOAD( ulong, bin+off->data_len_off );
203 0 : out->data = bin+off->data_len_off+8UL;
204 0 : return out;
205 0 : }
|