Line data Source code
1 : #include "../../../../disco/topo/fd_topo.h"
2 : #include "../../../../flamenco/runtime/fd_system_ids_pp.h"
3 :
4 0 : #define BENCHG_TRANSACTION_MODE_SMALL 0
5 0 : #define BENCHG_TRANSACTION_MODE_LARGE 1
6 0 : #define BENCHG_TRANSACTION_MODE_TRANSFER 2
7 :
8 : typedef struct {
9 : fd_rng_t rng[ 1 ];
10 : fd_sha512_t sha[ 1 ];
11 :
12 : ulong sender_idx;
13 : ulong lamport_idx;
14 : int changed_blockhash;
15 :
16 : int has_recent_blockhash;
17 : uchar recent_blockhash[ 32 ];
18 : uchar staged_blockhash[ 32 ];
19 :
20 : int transaction_mode;
21 : float contending_fraction;
22 : float cu_price_spread;
23 :
24 : ulong acct_cnt;
25 : fd_pubkey_t * acct_public_keys;
26 : fd_pubkey_t * acct_private_keys;
27 :
28 : ulong benchg_cnt;
29 : ulong benchg_idx;
30 :
31 : fd_wksp_t * mem;
32 : ulong out_chunk0;
33 : ulong out_wmark;
34 : ulong out_chunk;
35 : } fd_benchg_ctx_t;
36 :
37 : FD_FN_CONST static inline ulong
38 0 : scratch_align( void ) {
39 0 : return alignof( fd_benchg_ctx_t );
40 0 : }
41 :
42 : FD_FN_PURE static inline ulong
43 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
44 0 : (void)tile;
45 0 : ulong l = FD_LAYOUT_INIT;
46 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_benchg_ctx_t ), sizeof( fd_benchg_ctx_t ) );
47 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
48 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
49 0 : return FD_LAYOUT_FINI( l, scratch_align() );
50 0 : }
51 :
52 : static const uchar HARDCODED_PUBKEY[32] = { 0x0e,0xd2,0x90,0x05,0x83,0xd1,0x7c,0xc4,0x22,0x8c,0x10,0x75,0x84,0x18,0x71,0xa1, \
53 : 0x96,0xbe,0x46,0xc4,0xce,0xcd,0x5d,0xc0,0xae,0x7e,0xa9,0x61,0x4b,0x8a,0xdf,0x41 };
54 :
55 : static const uchar HARDCODED_SIG[64] = { 0xdb,0x89,0x2c,0xaa,0x90,0x1f,0x80,0xcf,0xde,0x32,0x09,0xbf,0xce,0x58,0xda,0x9e, \
56 : 0xd6,0xa1,0x8c,0x0f,0x74,0xfa,0x31,0x09,0x07,0x33,0xab,0x46,0xf9,0xde,0x60,0x3c, \
57 : 0x22,0x20,0xc6,0x7e,0xeb,0x9b,0xce,0x12,0x3a,0xd5,0x34,0xb8,0x1c,0x80,0x49,0x8a, \
58 : 0xb1,0x1e,0xbb,0xed,0xb2,0x24,0xf0,0x19,0x4b,0x85,0x3b,0x55,0x4b,0x41,0xbe,0x0a };
59 :
60 : typedef struct __attribute__((packed)) {
61 : uchar sig_cnt; /* = 1 */
62 : uchar signature[64];
63 : uchar _sig_cnt; /* also 1 */
64 : uchar ro_signed_cnt; /* ??? */
65 : uchar ro_unsigned_cnt; /* ??? */
66 : uchar acct_addr_cnt; /* = ??? */
67 : uchar fee_payer[32];
68 : } single_signer_hdr_t;
69 :
70 : typedef struct __attribute__((packed)) {
71 : uchar sig_cnt; /* = 1 */
72 : uchar signature[64];
73 : uchar _sig_cnt; /* also 1 */
74 : uchar ro_signed_cnt; /* = 0 */
75 : uchar ro_unsigned_cnt; /* = 1 . Compute Budget Program */
76 : uchar acct_addr_cnt; /* = 2 */
77 : uchar fee_payer[32];
78 : uchar compute_budget_program[32]; /* = {COMPUTE_BUDGET_PROG_ID} */
79 : uchar recent_blockhash[32];
80 : uchar instr_cnt; /* = 2 */
81 : /* Start of instruction */
82 : struct __attribute__((packed)) {
83 : uchar prog_id; /* = 1 */
84 : uchar acct_cnt; /* = 0 */
85 : uchar data_sz; /* = 9 */
86 : uchar set_cu_price; /* = 3 */
87 : ulong micro_lamports_per_cu; /* Prefereably less than 10k or so */
88 : } _1;
89 : /* Start of second instruction */
90 : struct __attribute__((packed)) {
91 : uchar prog_id; /* = 1 */
92 : uchar acct_cnt; /* = 0 */
93 : uchar data_sz; /* = 5 */
94 : uchar set_cu_limit; /* = 2 */
95 : uint cus; /* = 300 */
96 : } _2;
97 : } small_noop_t;
98 :
99 : typedef struct __attribute__((packed)) {
100 : uchar sig_cnt; /* = 1 */
101 : uchar signature[64];
102 : uchar _sig_cnt; /* also 1 */
103 : uchar ro_signed_cnt; /* = 0 */
104 : uchar ro_unsigned_cnt; /* = 2 . Compute Budget Program, Ed25519SV */
105 : uchar acct_addr_cnt; /* = 3 */
106 : uchar fee_payer[32];
107 : uchar compute_budget_program[32]; /* = {COMPUTE_BUDGET_PROG_ID} */
108 : uchar ed25519_sv_program[32]; /* = { ED25519_SV } */
109 : uchar recent_blockhash[32];
110 : uchar instr_cnt; /* = 2 */
111 : /* Start of instruction */
112 : struct __attribute__((packed)) {
113 : uchar prog_id; /* = 1 */
114 : uchar acct_cnt; /* = 0 */
115 : uchar data_sz; /* = 9 */
116 : uchar set_cu_price; /* = 3 */
117 : ulong micro_lamports_per_cu; /* Prefereably less than 10k or so */
118 : } _1;
119 : /* Start of second instruction */
120 : struct __attribute__((packed)) {
121 : uchar prog_id; /* = 2 */
122 : uchar acct_cnt; /* = 0 */
123 : uchar data_sz_0; /* = 0xFA */
124 : uchar data_sz_1; /* = 0x07 */
125 : /* Offsets the follow count from here */
126 : uchar signature_cnt; /* = 1 */
127 : uchar _padding; /* ignored, set to 0 */
128 : ushort signature_off; /* = 56 */
129 : ushort signature_ix_idx; /* = 0 */
130 : ushort pubkey_off; /* = 24 */
131 : ushort pubkey_ix_idx; /* = 0 */
132 : ushort data_off; /* = 120 */
133 : ushort data_sz; /* = 1 */
134 : ushort data_ix_idx; /* = 0 */
135 : ulong _padding2; /* Set to anything */
136 : uchar hardcoded_pubkey[32];
137 : uchar hardcoded_sig[64];
138 : uchar message; /* = 0 */
139 : uchar _padding3[897]; /* Set to anything */
140 : } _2;
141 : } large_noop_t;
142 :
143 : typedef struct __attribute__((packed)) {
144 : uchar sig_cnt; /* = 1 */
145 : uchar signature[64];
146 : uchar _sig_cnt; /* also 1 */
147 : uchar ro_signed_cnt; /* = 0 */
148 : uchar ro_unsigned_cnt; /* = 1 . System program */
149 : uchar acct_addr_cnt; /* = 3 */
150 : uchar fee_payer[32];
151 : uchar transfer_dest[32];
152 : uchar system_program[32]; /* = { 0 0 ...} */
153 : uchar recent_blockhash[32];
154 : uchar instr_cnt; /* = 1 */
155 : /* Start of instruction */
156 : struct __attribute__((packed)) {
157 : uchar prog_id; /* = 2 */
158 : uchar acct_cnt; /* = 2 */
159 : uchar from_acct; /* = 0 */
160 : uchar to_acct; /* = 1 */
161 : uchar data_sz; /* = 9 */
162 : uchar transfer; /* = 2 */
163 : ulong lamports; /* variable */
164 : } _1;
165 : } transfer_t;
166 :
167 :
168 : FD_STATIC_ASSERT( sizeof(large_noop_t)==1232UL, txn );
169 :
170 : static inline void
171 : after_credit( fd_benchg_ctx_t * ctx,
172 : fd_stem_context_t * stem,
173 : int * opt_poll_in,
174 0 : int * charge_busy ) {
175 0 : (void)opt_poll_in;
176 :
177 0 : if( FD_UNLIKELY( !ctx->has_recent_blockhash ) ) return;
178 :
179 0 : *charge_busy = 1;
180 :
181 0 : int is_contending = fd_rng_float_c( ctx->rng ) < ctx->contending_fraction;
182 0 : ulong sender_idx = fd_ulong_if( is_contending, 0UL, ctx->sender_idx );
183 :
184 0 : float norm = 4.0f + fd_rng_float_norm( ctx->rng );
185 0 : if( FD_UNLIKELY( norm<0.0f ) ) norm = 0.0f;
186 0 : ulong cu_price_spread = (ulong)(ctx->cu_price_spread * norm);
187 :
188 0 : void * _txn = fd_chunk_to_laddr( ctx->mem, ctx->out_chunk );
189 :
190 0 : ulong transaction_size = 0UL;
191 0 : uchar * recent_blockhash = NULL;
192 :
193 0 : switch( ctx->transaction_mode ) {
194 0 : case BENCHG_TRANSACTION_MODE_SMALL:
195 0 : {
196 0 : small_noop_t * txn = (small_noop_t *)_txn;
197 :
198 0 : txn->sig_cnt = 1;
199 0 : txn->_sig_cnt = 1;
200 0 : txn->ro_signed_cnt = 0;
201 0 : txn->ro_unsigned_cnt = 1;
202 0 : txn->acct_addr_cnt = 2;
203 0 : memcpy( txn->compute_budget_program, (uchar const[32]) { COMPUTE_BUDGET_PROG_ID }, 32UL );
204 0 : txn->instr_cnt = 2;
205 0 : txn->_1.prog_id = 1;
206 0 : txn->_1.acct_cnt = 0;
207 0 : txn->_1.data_sz = 9;
208 0 : txn->_1.set_cu_price = 3;
209 0 : txn->_2.prog_id = 1;
210 0 : txn->_2.acct_cnt = 0;
211 0 : txn->_2.data_sz = 5;
212 0 : txn->_2.set_cu_limit = 2;
213 0 : txn->_2.cus = 300;
214 :
215 : /* Variable */
216 0 : txn->_1.micro_lamports_per_cu = ctx->lamport_idx; /* Unique per transaction so they aren't duplicates */
217 0 : txn->_1.micro_lamports_per_cu += fd_ulong_if( is_contending, 1000000UL, 0UL ); /* +300 lamports */
218 0 : txn->_1.micro_lamports_per_cu += cu_price_spread;
219 :
220 0 : transaction_size = sizeof(small_noop_t);
221 0 : recent_blockhash = txn->recent_blockhash;
222 0 : }
223 0 : break;
224 :
225 0 : case BENCHG_TRANSACTION_MODE_LARGE:
226 0 : {
227 0 : large_noop_t * txn = (large_noop_t *)_txn;
228 :
229 0 : txn->sig_cnt = 1;
230 0 : txn->_sig_cnt = 1;
231 0 : txn->ro_signed_cnt = 0;
232 0 : txn->ro_unsigned_cnt = 2;
233 0 : txn->acct_addr_cnt = 3;
234 0 : memcpy( txn->compute_budget_program, (uchar const[32]) { COMPUTE_BUDGET_PROG_ID }, 32UL );
235 0 : memcpy( txn->ed25519_sv_program, (uchar const[32]) { ED25519_SV_PROG_ID }, 32UL );
236 0 : txn->instr_cnt = 2;
237 :
238 0 : txn->_1.prog_id = 1;
239 0 : txn->_1.acct_cnt = 0;
240 0 : txn->_1.data_sz = 9;
241 0 : txn->_1.set_cu_price = 3;
242 0 : txn->_1.micro_lamports_per_cu = 0UL;
243 0 : txn->_1.micro_lamports_per_cu += cu_price_spread;
244 0 : txn->_1.micro_lamports_per_cu += fd_ulong_if( is_contending, 43000UL, 0UL ); /* +4 lamports/csu */
245 :
246 :
247 0 : txn->_2.prog_id = 2;
248 0 : txn->_2.acct_cnt = 0;
249 0 : txn->_2.data_sz_0 = 0xFA;
250 0 : txn->_2.data_sz_1 = 0x07;
251 :
252 0 : txn->_2.signature_cnt = 1;
253 0 : txn->_2._padding = 0;
254 0 : txn->_2.signature_off = 56;
255 0 : txn->_2.signature_ix_idx= 0;
256 0 : txn->_2.pubkey_off = 24;
257 0 : txn->_2.pubkey_ix_idx = 0;
258 0 : memcpy( txn->_2.hardcoded_pubkey, HARDCODED_PUBKEY, 32UL );
259 0 : memcpy( txn->_2.hardcoded_sig, HARDCODED_SIG, 64UL );
260 0 : txn->_2.message = 0;
261 :
262 0 : txn->_2._padding2 = ctx->lamport_idx * ctx->acct_cnt + ctx->sender_idx; /* Unique per transaction so they aren't duplicates */
263 :
264 0 : transaction_size = sizeof(large_noop_t);
265 0 : recent_blockhash = txn->recent_blockhash;
266 0 : }
267 0 : break;
268 :
269 0 : case BENCHG_TRANSACTION_MODE_TRANSFER:
270 0 : {
271 0 : transfer_t * txn = (transfer_t *)_txn;
272 :
273 0 : txn->sig_cnt = 1;
274 0 : txn->_sig_cnt = 1;
275 0 : txn->ro_signed_cnt = 0;
276 0 : txn->ro_unsigned_cnt = 1;
277 0 : txn->acct_addr_cnt = 3;
278 0 : memcpy( txn->transfer_dest, ctx->acct_public_keys[ sender_idx ].uc, 32UL );
279 0 : for( ulong j=0UL; j<32UL; j++ ) txn->transfer_dest[ j ] ^= 0xFF;
280 0 : memcpy( txn->system_program, (uchar const[32]) { SYS_PROG_ID }, 32UL );
281 0 : txn->instr_cnt = 1;
282 :
283 0 : txn->_1.prog_id = 2;
284 0 : txn->_1.acct_cnt = 2;
285 0 : txn->_1.from_acct = 0;
286 0 : txn->_1.to_acct = 1;
287 0 : txn->_1.data_sz = 9;
288 0 : txn->_1.transfer = 2;
289 :
290 0 : txn->_1.lamports = ctx->lamport_idx;
291 :
292 0 : transaction_size = sizeof(transfer_t);
293 0 : recent_blockhash = txn->recent_blockhash;
294 0 : }
295 0 : break;
296 :
297 0 : default:
298 0 : FD_LOG_ERR(( "Unkown transaction mode %i", ctx->transaction_mode ));
299 0 : break;
300 0 : }
301 :
302 0 : single_signer_hdr_t * txnh = (single_signer_hdr_t *)_txn;
303 0 : fd_memcpy( txnh->fee_payer, ctx->acct_public_keys[ sender_idx ].uc, 32UL );
304 0 : fd_memcpy( recent_blockhash, ctx->recent_blockhash, 32UL );
305 :
306 0 : fd_ed25519_sign( txnh->signature,
307 0 : &(txnh->_sig_cnt),
308 0 : transaction_size-65UL,
309 0 : ctx->acct_public_keys[ sender_idx ].uc,
310 0 : ctx->acct_private_keys[ sender_idx ].uc,
311 0 : ctx->sha );
312 :
313 0 : fd_stem_publish( stem, 0UL, 0UL, ctx->out_chunk, transaction_size, 0UL, 0UL, 0UL );
314 0 : ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, transaction_size, ctx->out_chunk0, ctx->out_wmark );
315 :
316 0 : ctx->sender_idx = (ctx->sender_idx + 1UL) % ctx->acct_cnt;
317 0 : if( FD_UNLIKELY( !ctx->sender_idx ) ) {
318 0 : if( FD_UNLIKELY( ctx->changed_blockhash ) ) {
319 0 : ctx->lamport_idx = 1UL+ctx->benchg_idx;
320 0 : ctx->changed_blockhash = 0;
321 0 : fd_memcpy( ctx->recent_blockhash, ctx->staged_blockhash, 32UL );
322 0 : } else {
323 : /* Increments of the number of generators so there are never
324 : duplicate transactions generated. */
325 0 : ctx->lamport_idx += ctx->benchg_cnt;
326 0 : }
327 0 : }
328 0 : }
329 :
330 : static inline void
331 : during_frag( fd_benchg_ctx_t * ctx,
332 : ulong in_idx FD_PARAM_UNUSED,
333 : ulong seq FD_PARAM_UNUSED,
334 : ulong sig FD_PARAM_UNUSED,
335 : ulong chunk,
336 : ulong sz FD_PARAM_UNUSED,
337 0 : ulong ctl FD_PARAM_UNUSED ) {
338 0 : if( FD_UNLIKELY( !ctx->has_recent_blockhash ) ) {
339 0 : fd_memcpy( ctx->recent_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL );
340 0 : ctx->has_recent_blockhash = 1;
341 0 : ctx->changed_blockhash = 0;
342 0 : } else {
343 0 : if( FD_UNLIKELY( !memcmp( ctx->recent_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL ) ) ) return;
344 :
345 0 : fd_memcpy( ctx->staged_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL );
346 0 : ctx->changed_blockhash = 1;
347 0 : }
348 0 : }
349 :
350 : static void
351 : unprivileged_init( fd_topo_t * topo,
352 0 : fd_topo_tile_t * tile ) {
353 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
354 :
355 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
356 0 : fd_benchg_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_benchg_ctx_t ), sizeof( fd_benchg_ctx_t ) );
357 0 : ctx->acct_public_keys = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
358 0 : ctx->acct_private_keys = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
359 :
360 0 : FD_TEST( fd_rng_join( fd_rng_new( ctx->rng, (uint)tile->kind_id, 0UL ) ) );
361 0 : FD_TEST( fd_sha512_join( fd_sha512_new( ctx->sha ) ) );
362 :
363 0 : ctx->acct_cnt = tile->benchg.accounts_cnt;
364 0 : ctx->transaction_mode = tile->benchg.mode;
365 0 : ctx->contending_fraction = tile->benchg.contending_fraction;
366 0 : ctx->cu_price_spread = tile->benchg.cu_price_spread;
367 :
368 0 : for( ulong i=0UL; i<ctx->acct_cnt; i++ ) {
369 0 : fd_memset( ctx->acct_private_keys[ i ].uc, 0, 32UL );
370 0 : FD_STORE( ulong, ctx->acct_private_keys[ i ].uc, i );
371 0 : fd_ed25519_public_from_private( ctx->acct_public_keys[ i ].uc, ctx->acct_private_keys[ i ].uc , ctx->sha );
372 0 : }
373 :
374 0 : ctx->has_recent_blockhash = 0;
375 :
376 0 : ctx->sender_idx = 0UL;
377 0 : ctx->lamport_idx = 1UL+tile->kind_id;
378 0 : ctx->changed_blockhash = 0;
379 :
380 0 : ctx->benchg_cnt = fd_topo_tile_name_cnt( topo, "benchg" );
381 0 : ctx->benchg_idx = tile->kind_id;
382 :
383 0 : ctx->mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
384 0 : ctx->out_chunk0 = fd_dcache_compact_chunk0( ctx->mem, topo->links[ tile->out_link_id[ 0 ] ].dcache );
385 0 : ctx->out_wmark = fd_dcache_compact_wmark ( ctx->mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu );
386 0 : ctx->out_chunk = ctx->out_chunk0;
387 :
388 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
389 0 : if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
390 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
391 0 : }
392 :
393 0 : #define STEM_BURST (1UL)
394 :
395 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_benchg_ctx_t
396 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_benchg_ctx_t)
397 :
398 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
399 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
400 :
401 : #include "../../../../disco/stem/fd_stem.c"
402 :
403 : fd_topo_run_tile_t fd_tile_benchg = {
404 : .name = "benchg",
405 : .scratch_align = scratch_align,
406 : .scratch_footprint = scratch_footprint,
407 : .unprivileged_init = unprivileged_init,
408 : .run = stem_run,
409 : };
|