Line data Source code
1 : #include "fd_shredder.h"
2 : #include "../../ballet/shred/fd_shred.h"
3 :
4 : void *
5 : fd_shredder_new( void * mem,
6 : fd_shredder_sign_fn * signer,
7 : void * signer_ctx,
8 39 : ushort shred_version ) {
9 39 : fd_shredder_t * shredder = (fd_shredder_t *)mem;
10 :
11 39 : if( FD_UNLIKELY( !mem ) ) {
12 0 : FD_LOG_WARNING(( "NULL shredder memory" ));
13 0 : return NULL;
14 0 : }
15 :
16 39 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_shredder_align() ) ) ) {
17 0 : FD_LOG_WARNING(( "misaligned shredder memory" ));
18 0 : return NULL;
19 0 : }
20 :
21 39 : shredder->shred_version = shred_version;
22 39 : shredder->entry_batch = NULL;
23 39 : shredder->sz = 0UL;
24 39 : shredder->offset = 0UL;
25 :
26 39 : fd_memset( &(shredder->meta), 0, sizeof(fd_entry_batch_meta_t) );
27 39 : shredder->slot = ULONG_MAX;
28 39 : shredder->data_idx_offset = 0UL;
29 39 : shredder->parity_idx_offset = 0UL;
30 :
31 39 : shredder->signer = signer;
32 39 : shredder->signer_ctx = signer_ctx;
33 :
34 39 : FD_COMPILER_MFENCE();
35 39 : FD_VOLATILE( shredder->magic ) = FD_SHREDDER_MAGIC;
36 39 : FD_COMPILER_MFENCE();
37 :
38 39 : return (void *)shredder;
39 39 : }
40 :
41 : fd_shredder_t *
42 39 : fd_shredder_join( void * mem ) {
43 39 : if( FD_UNLIKELY( !mem ) ) {
44 0 : FD_LOG_WARNING(( "NULL shredder memory" ));
45 0 : return NULL;
46 0 : }
47 :
48 39 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_shredder_align() ) ) ) {
49 0 : FD_LOG_WARNING(( "misaligned shredder memory" ));
50 0 : return NULL;
51 0 : }
52 :
53 39 : fd_shredder_t * shredder = (fd_shredder_t *)mem;
54 :
55 39 : if( FD_UNLIKELY( shredder->magic!=FD_SHREDDER_MAGIC ) ) {
56 0 : FD_LOG_WARNING(( "bad magic" ));
57 0 : return NULL;
58 0 : }
59 :
60 39 : return shredder;
61 39 : }
62 :
63 : void *
64 0 : fd_shredder_leave( fd_shredder_t * shredder ) {
65 0 : return (void *)shredder;
66 0 : }
67 :
68 : void *
69 0 : fd_shredder_delete( void * mem ) {
70 0 : fd_shredder_t * shredder = (fd_shredder_t *)mem;
71 :
72 0 : if( FD_UNLIKELY( shredder->magic!=FD_SHREDDER_MAGIC ) ) {
73 0 : FD_LOG_WARNING(( "bad magic" ));
74 0 : return NULL;
75 0 : }
76 :
77 0 : FD_COMPILER_MFENCE();
78 0 : FD_VOLATILE( shredder->magic ) = 0UL;
79 0 : FD_COMPILER_MFENCE();
80 :
81 0 : return (void *)shredder;
82 0 : }
83 :
84 :
85 : fd_shredder_t *
86 : fd_shredder_skip_batch( fd_shredder_t * shredder,
87 : ulong entry_batch_sz,
88 180 : ulong slot ) {
89 :
90 180 : if( FD_UNLIKELY( entry_batch_sz==0UL ) ) return NULL;
91 :
92 180 : if( FD_UNLIKELY( slot != shredder->slot ) ) {
93 45 : shredder->data_idx_offset = 0UL;
94 45 : shredder->parity_idx_offset = 0UL;
95 45 : }
96 :
97 180 : ulong data_shred_cnt = fd_shredder_count_data_shreds( entry_batch_sz );
98 180 : ulong parity_shred_cnt = fd_shredder_count_parity_shreds( entry_batch_sz );
99 :
100 180 : shredder->data_idx_offset += data_shred_cnt;
101 180 : shredder->parity_idx_offset += parity_shred_cnt;
102 180 : shredder->slot = slot;
103 :
104 180 : return shredder;
105 180 : }
106 :
107 :
108 : fd_shredder_t *
109 : fd_shredder_init_batch( fd_shredder_t * shredder,
110 : void const * entry_batch,
111 : ulong entry_batch_sz,
112 : ulong slot,
113 330393 : fd_entry_batch_meta_t const * metadata ) {
114 :
115 330393 : if( FD_UNLIKELY( entry_batch_sz==0UL ) ) return NULL; /* FIXME: should this warn? Silently expand it to 1 byte? */
116 :
117 330393 : shredder->entry_batch = entry_batch;
118 330393 : shredder->sz = entry_batch_sz;
119 330393 : shredder->offset = 0UL;
120 :
121 330393 : if( FD_UNLIKELY( slot != shredder->slot ) ) {
122 300054 : shredder->data_idx_offset = 0UL;
123 300054 : shredder->parity_idx_offset = 0UL;
124 300054 : }
125 :
126 330393 : shredder->slot = slot;
127 330393 : shredder->meta = *metadata;
128 :
129 330393 : return shredder;
130 330393 : }
131 :
132 :
133 : fd_fec_set_t *
134 : fd_shredder_next_fec_set( fd_shredder_t * shredder,
135 1781271 : fd_fec_set_t * result ) {
136 1781271 : uchar const * entry_batch = shredder->entry_batch;
137 1781271 : ulong offset = shredder->offset;
138 1781271 : ulong entry_sz = shredder->sz;
139 :
140 1781271 : uchar * * data_shreds = result->data_shreds;
141 1781271 : uchar * * parity_shreds = result->parity_shreds;
142 :
143 1781271 : fd_ed25519_sig_t __attribute__((aligned(32UL))) root_signature;
144 :
145 1781271 : if( FD_UNLIKELY( (offset==entry_sz) ) ) return NULL;
146 :
147 : /* Compute how many data and parity shreds to generate */
148 :
149 1481274 : ulong entry_bytes_remaining = entry_sz - offset;
150 : /* how many total payload bytes in this FEC set? */
151 1481274 : ulong chunk_size = fd_ulong_if( entry_bytes_remaining>=2UL*FD_SHREDDER_NORMAL_FEC_SET_PAYLOAD_SZ,
152 1481274 : FD_SHREDDER_NORMAL_FEC_SET_PAYLOAD_SZ,
153 1481274 : entry_bytes_remaining );
154 1481274 : ulong data_shred_cnt = fd_shredder_count_data_shreds( chunk_size );
155 1481274 : ulong parity_shred_cnt = fd_shredder_count_parity_shreds( chunk_size );
156 : /* Our notion of tree depth counts the root, while the shred version
157 : doesn't. */
158 1481274 : ulong tree_depth = fd_bmtree_depth( data_shred_cnt+parity_shred_cnt )-1UL;
159 1481274 : ulong data_shred_payload_sz = 1115UL - 20UL*tree_depth;
160 1481274 : ulong parity_shred_payload_sz = data_shred_payload_sz + 0x58UL - 0x40UL;
161 1481274 : ulong data_merkle_sz = parity_shred_payload_sz;
162 1481274 : ulong parity_merkle_sz = parity_shred_payload_sz + 0x59UL - 0x40UL;
163 :
164 1481274 : ulong last_in_batch = (chunk_size+offset==entry_sz);
165 1481274 : int block_complete = shredder->meta.block_complete;
166 :
167 1481274 : fd_reedsol_t * reedsol = fd_reedsol_encode_init( shredder->reedsol, parity_shred_payload_sz );
168 :
169 :
170 : /* Write headers and copy the data shred payload */
171 1481274 : ulong flags_for_last = ((last_in_batch & (ulong)block_complete)<<7) | (last_in_batch<<6);
172 51759288 : for( ulong i=0UL; i<data_shred_cnt; i++ ) {
173 50278014 : fd_shred_t * shred = (fd_shred_t *)data_shreds[ i ];
174 : /* Size in bytes of the payload section of this data shred,
175 : excluding any zero-padding */
176 50278014 : ulong shred_payload_sz = fd_ulong_min( entry_sz-offset, data_shred_payload_sz );
177 :
178 50278014 : shred->variant = fd_shred_variant( FD_SHRED_TYPE_MERKLE_DATA, (uchar)tree_depth );
179 50278014 : shred->slot = shredder->slot;
180 50278014 : shred->idx = (uint )(shredder->data_idx_offset + i);
181 50278014 : shred->version = (ushort)(shredder->shred_version);
182 50278014 : shred->fec_set_idx = (uint )(shredder->data_idx_offset);
183 50278014 : shred->data.parent_off = (ushort)(shredder->meta.parent_offset);
184 50278014 : shred->data.flags = (uchar )(fd_ulong_if( i==data_shred_cnt-1UL, flags_for_last, 0UL ) | (shredder->meta.reference_tick & 0x3FUL));
185 50278014 : shred->data.size = (ushort)(FD_SHRED_DATA_HEADER_SZ + shred_payload_sz);
186 :
187 50278014 : uchar * payload = fd_memcpy( data_shreds[ i ] + FD_SHRED_DATA_HEADER_SZ , entry_batch+offset, shred_payload_sz );
188 50278014 : offset += shred_payload_sz;
189 :
190 : /* Write zero-padding, likely to be a no-op */
191 50278014 : fd_memset( payload+shred_payload_sz, 0, data_shred_payload_sz-shred_payload_sz );
192 :
193 : /* Set the last bytes of the signature field to the Merkle tree
194 : prefix so we can use the faster batch sha256 API to compute the
195 : Merkle tree */
196 50278014 : fd_memcpy( shred->signature + 64UL - 26UL, "\x00SOLANA_MERKLE_SHREDS_LEAF", 26UL );
197 :
198 : /* Prepare to generate parity data: data shred starts right after
199 : signature and goes until start of Merkle proof. */
200 50278014 : fd_reedsol_encode_add_data_shred( reedsol, ((uchar*)shred) + sizeof(fd_ed25519_sig_t) );
201 50278014 : }
202 :
203 52646958 : for( ulong j=0UL; j<parity_shred_cnt; j++ ) {
204 51165684 : fd_shred_t * shred = (fd_shred_t *)parity_shreds[ j ];
205 :
206 51165684 : shred->variant = fd_shred_variant( FD_SHRED_TYPE_MERKLE_CODE, (uchar)tree_depth );
207 51165684 : shred->slot = shredder->slot;
208 51165684 : shred->idx = (uint )(shredder->parity_idx_offset + j);
209 51165684 : shred->version = (ushort)(shredder->shred_version);
210 51165684 : shred->fec_set_idx = (uint )(shredder->data_idx_offset);
211 51165684 : shred->code.data_cnt = (ushort)(data_shred_cnt);
212 51165684 : shred->code.code_cnt = (ushort)(parity_shred_cnt);
213 51165684 : shred->code.idx = (ushort)(j);
214 :
215 51165684 : fd_memcpy( shred->signature + 64UL - 26UL, "\x00SOLANA_MERKLE_SHREDS_LEAF", 26UL );
216 :
217 : /* Prepare to generate parity data: parity info starts right after
218 : signature and goes until start of Merkle proof. */
219 51165684 : fd_reedsol_encode_add_parity_shred( reedsol, parity_shreds[ j ] + FD_SHRED_CODE_HEADER_SZ );
220 51165684 : }
221 :
222 : /* Generate parity data */
223 1481274 : fd_reedsol_encode_fini( reedsol );
224 :
225 : /* Generate Merkle leaves */
226 1481274 : fd_sha256_batch_t * sha256 = fd_sha256_batch_init( shredder->sha256 );
227 1481274 : fd_bmtree_node_t * leaves = shredder->bmtree_leaves;
228 :
229 51759288 : for( ulong i=0UL; i<data_shred_cnt; i++ )
230 50278014 : fd_sha256_batch_add( sha256, data_shreds[i]+sizeof(fd_ed25519_sig_t)-26UL, data_merkle_sz+26UL, leaves[i].hash );
231 52646958 : for( ulong j=0UL; j<parity_shred_cnt; j++ )
232 51165684 : fd_sha256_batch_add( sha256, parity_shreds[j]+sizeof(fd_ed25519_sig_t)-26UL, parity_merkle_sz+26UL, leaves[j+data_shred_cnt].hash );
233 1481274 : fd_sha256_batch_fini( sha256 );
234 :
235 :
236 : /* Generate Merkle Proofs */
237 1481274 : fd_bmtree_commit_t * bmtree = fd_bmtree_commit_init( shredder->_bmtree_footprint, FD_SHRED_MERKLE_NODE_SZ, FD_BMTREE_LONG_PREFIX_SZ, tree_depth+1UL );
238 1481274 : fd_bmtree_commit_append( bmtree, leaves, data_shred_cnt+parity_shred_cnt );
239 1481274 : uchar * root = fd_bmtree_commit_fini( bmtree );
240 :
241 : /* Sign Merkle Root */
242 1481274 : shredder->signer( shredder->signer_ctx, root_signature, root );
243 :
244 : /* Write signature and Merkle proof */
245 51759288 : for( ulong i=0UL; i<data_shred_cnt; i++ ) {
246 50278014 : fd_shred_t * shred = (fd_shred_t *)data_shreds[ i ];
247 50278014 : fd_memcpy( shred->signature, root_signature, FD_ED25519_SIG_SZ );
248 :
249 50278014 : uchar * merkle = data_shreds[ i ] + fd_shred_merkle_off( shred );
250 50278014 : fd_bmtree_get_proof( bmtree, merkle, i );
251 50278014 : }
252 :
253 52646958 : for( ulong j=0UL; j<parity_shred_cnt; j++ ) {
254 51165684 : fd_shred_t * shred = (fd_shred_t *)parity_shreds[ j ];
255 :
256 51165684 : fd_memcpy( shred->signature, root_signature, FD_ED25519_SIG_SZ );
257 :
258 51165684 : uchar * merkle = parity_shreds[ j ] + fd_shred_merkle_off( shred );
259 51165684 : fd_bmtree_get_proof( bmtree, merkle, data_shred_cnt+j );
260 51165684 : }
261 :
262 1481274 : shredder->offset = offset;
263 1481274 : shredder->data_idx_offset += data_shred_cnt;
264 1481274 : shredder->parity_idx_offset += parity_shred_cnt;
265 :
266 1481274 : result->data_shred_cnt = data_shred_cnt;
267 1481274 : result->parity_shred_cnt = parity_shred_cnt;
268 :
269 1481274 : return result;
270 1781271 : }
271 :
272 330387 : fd_shredder_t * fd_shredder_fini_batch( fd_shredder_t * shredder ) {
273 330387 : shredder->entry_batch = NULL;
274 330387 : shredder->sz = 0UL;
275 330387 : shredder->offset = 0UL;
276 :
277 330387 : return shredder;
278 330387 : }
|