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