LCOV - code coverage report
Current view: top level - app/shared_dev/commands - txn.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 142 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 8 0.0 %

          Line data    Source code
       1             : #include "../../shared/fd_config.h"
       2             : #include "../../shared/fd_action.h"
       3             : 
       4             : #include "../../platform/fd_sys_util.h"
       5             : #include "../../platform/fd_net_util.h"
       6             : #include "../../shared/commands/ready.h"
       7             : #include "../../../ballet/base64/fd_base64.h"
       8             : #include "../../../waltz/quic/fd_quic.h"
       9             : #include "../../../waltz/quic/tests/fd_quic_test_helpers.h"
      10             : #include "../../../waltz/tls/test_tls_helper.h"
      11             : #include "../../../util/net/fd_ip4.h"
      12             : 
      13             : #include <errno.h>
      14             : #include <sys/random.h>
      15             : #include <linux/capability.h>
      16             : 
      17             : FD_IMPORT_BINARY(sample_transaction, "src/waltz/quic/tests/quic_txn.bin");
      18             : 
      19             : static int g_conn_hs_complete = 0;
      20             : static int g_conn_final = 0;
      21             : static ulong g_stream_notify = 0UL;
      22             : 
      23             : #define MAX_TXN_COUNT 128
      24             : 
      25             : void
      26             : txn_cmd_perm( args_t *         args FD_PARAM_UNUSED,
      27             :               fd_cap_chk_t *   chk,
      28           0 :               config_t const * config ) {
      29           0 :   if( FD_UNLIKELY( config->development.netns.enabled ) )
      30           0 :     fd_cap_chk_cap( chk, "txn", CAP_SYS_ADMIN, "enter a network namespace by calling `setns(2)`" );
      31           0 : }
      32             : 
      33             : void
      34             : txn_cmd_args( int *    pargc,
      35             :               char *** pargv,
      36           0 :               args_t * args ) {
      37           0 :   args->txn.payload_base64 = fd_env_strip_cmdline_cstr( pargc, pargv, "--payload-base64-encoded", NULL, NULL );
      38           0 :   args->txn.count = fd_env_strip_cmdline_ulong( pargc, pargv, "--count", NULL, 1 );
      39           0 :   if( FD_UNLIKELY( !args->txn.count || args->txn.count > MAX_TXN_COUNT ) )
      40           0 :     FD_LOG_ERR(( "count must be between 1 and %d", MAX_TXN_COUNT ));
      41             : 
      42           0 :   args->txn.dst_ip = fd_env_strip_cmdline_cstr( pargc, pargv, "--dst-ip", NULL, 0 );
      43           0 :   args->txn.dst_port = fd_env_strip_cmdline_ushort( pargc, pargv, "--dst-port", NULL, 0 );
      44           0 : }
      45             : 
      46             : static ulong
      47           0 : cb_now( void * context ) {
      48           0 :   (void)context;
      49           0 :   return (ulong)fd_log_wallclock();
      50           0 : }
      51             : 
      52             : static void
      53             : cb_conn_hs_complete( fd_quic_conn_t * conn,
      54           0 :                      void *           quic_ctx ) {
      55           0 :   (void)conn;
      56           0 :   (void)quic_ctx;
      57           0 :   g_conn_hs_complete = 1;
      58           0 : }
      59             : 
      60             : static void
      61             : cb_conn_final( fd_quic_conn_t * conn,
      62           0 :                void *           quic_ctx ) {
      63           0 :   (void)conn;
      64           0 :   (void)quic_ctx;
      65           0 :   g_conn_final = 1;
      66           0 : }
      67             : 
      68             : static void
      69             : cb_stream_notify( fd_quic_stream_t * stream,
      70             :                   void *             stream_ctx,
      71           0 :                   int                notify_type ) {
      72           0 :   (void)stream;
      73           0 :   (void)stream_ctx;
      74           0 :   (void)notify_type;
      75           0 :   g_stream_notify += 1;
      76           0 : }
      77             : 
      78             : static void
      79             : send_quic_transactions( fd_quic_t *         quic,
      80             :                         fd_quic_udpsock_t * udpsock,
      81             :                         ulong               count,
      82             :                         uint                dst_ip,
      83             :                         ushort              dst_port,
      84           0 :                         fd_aio_pkt_info_t * pkt ) {
      85           0 :   fd_quic_set_aio_net_tx( quic, udpsock->aio );
      86           0 :   FD_TEST( fd_quic_init( quic ) );
      87             : 
      88           0 :   quic->cb.now              = cb_now;
      89           0 :   quic->cb.conn_final       = cb_conn_final;
      90           0 :   quic->cb.conn_hs_complete = cb_conn_hs_complete;
      91           0 :   quic->cb.stream_notify    = cb_stream_notify;
      92             : 
      93           0 :   fd_quic_conn_t * conn = fd_quic_connect( quic, dst_ip, dst_port, 0U, (ushort)udpsock->listen_port );
      94           0 :   while ( FD_LIKELY( !( g_conn_hs_complete || g_conn_final ) ) ) {
      95           0 :     fd_quic_service( quic );
      96           0 :     fd_quic_udpsock_service( udpsock );
      97           0 :   }
      98           0 :   FD_TEST( conn );
      99           0 :   if( FD_UNLIKELY( conn->state != FD_QUIC_CONN_STATE_ACTIVE ) )
     100           0 :     FD_LOG_ERR(( "unable to connect to QUIC endpoint at "FD_IP4_ADDR_FMT":%hu, is it running? state is %u", FD_IP4_ADDR_FMT_ARGS(dst_ip), dst_port, conn->state ));
     101             : 
     102           0 :   ulong sent = 0;
     103           0 :   while( sent < count && !g_conn_final ) {
     104           0 :     fd_quic_stream_t * stream = fd_quic_conn_new_stream( conn );
     105           0 :     if( FD_UNLIKELY( !stream ) ) {
     106           0 :       fd_quic_service( quic );
     107           0 :       fd_quic_udpsock_service( udpsock );
     108           0 :       continue;
     109           0 :     }
     110             : 
     111           0 :     fd_aio_pkt_info_t * chunk = pkt + sent;
     112           0 :     int res = fd_quic_stream_send( stream, chunk->buf, chunk->buf_sz, 1 );
     113           0 :     if( FD_UNLIKELY( res != FD_QUIC_SUCCESS ) ) FD_LOG_ERR(( "fd_quic_stream_send failed (%d)", res ));
     114           0 :     sent += 1UL;
     115             : 
     116           0 :     fd_quic_service( quic );
     117           0 :     fd_quic_udpsock_service( udpsock );
     118           0 :   }
     119             : 
     120           0 :   while( FD_LIKELY( g_stream_notify!=count && !g_conn_final ) ) {
     121           0 :     fd_quic_service( quic );
     122           0 :     fd_quic_udpsock_service( udpsock );
     123           0 :   }
     124             : 
     125             :   /* close and wait for connection to complete */
     126           0 :   if( !g_conn_final ) {
     127           0 :     fd_quic_conn_close( conn, 0 );
     128           0 :     while( !g_conn_final ) {
     129           0 :       fd_quic_service( quic );
     130           0 :       fd_quic_udpsock_service( udpsock );
     131           0 :     }
     132           0 :   }
     133             : 
     134           0 :   fd_quic_fini( quic );
     135           0 : }
     136             : 
     137             : void
     138             : txn_cmd_fn( args_t *   args,
     139           0 :             config_t * config ) {
     140           0 :   if( FD_UNLIKELY( config->development.netns.enabled ) ) {
     141           0 :     if( FD_UNLIKELY( -1==fd_net_util_netns_enter( config->development.netns.interface1, NULL ) ) )
     142           0 :       FD_LOG_ERR(( "failed to enter network namespace `%s` (%i-%s)", config->development.netns.interface1, errno, fd_io_strerror( errno ) ));
     143           0 :   }
     144             : 
     145             :   /* wait until validator is ready to receive txns before sending */
     146           0 :   ready_cmd_fn( args, config );
     147             : 
     148           0 :   fd_quic_limits_t quic_limits = {
     149           0 :     .conn_cnt           =  1UL,
     150           0 :     .handshake_cnt      =  1UL,
     151           0 :     .conn_id_cnt        =  4UL,
     152           0 :     .stream_id_cnt      =  64UL,
     153           0 :     .inflight_frame_cnt =  64UL,
     154           0 :     .tx_buf_sz          =  fd_ulong_pow2_up( FD_TXN_MTU ),
     155           0 :     .stream_pool_cnt    =  16UL
     156           0 :   };
     157           0 :   ulong quic_footprint = fd_quic_footprint( &quic_limits );
     158           0 :   FD_TEST( quic_footprint );
     159             : 
     160           0 :   fd_wksp_t * wksp = fd_wksp_new_anonymous( FD_SHMEM_NORMAL_PAGE_SZ,
     161           0 :                                             1UL << 10,
     162           0 :                                             fd_shmem_cpu_idx( 0 ),
     163           0 :                                             "wksp",
     164           0 :                                             0UL );
     165           0 :   FD_TEST( wksp );
     166           0 :   void * mem = fd_wksp_alloc_laddr( wksp, fd_quic_align(), quic_footprint, 1UL );
     167           0 :   fd_quic_t * quic = fd_quic_join( fd_quic_new( mem, &quic_limits ) );
     168           0 :   FD_TEST( quic );
     169             : 
     170             :   /* Signer */
     171           0 :   fd_rng_t _rng[1]; fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, 0U, 0UL ) );
     172           0 :   fd_tls_test_sign_ctx_t * sign_ctx = fd_wksp_alloc_laddr( wksp, alignof(fd_tls_test_sign_ctx_t), sizeof(fd_tls_test_sign_ctx_t), 1UL );
     173           0 :   fd_tls_test_sign_ctx( sign_ctx, rng );
     174             : 
     175           0 :   fd_memcpy( quic->config.identity_public_key, sign_ctx->public_key, 32UL );
     176           0 :   quic->config.sign_ctx = sign_ctx;
     177           0 :   quic->config.sign     = fd_tls_test_sign_sign;
     178             : 
     179           0 :   fd_quic_udpsock_t _udpsock;
     180           0 :   fd_quic_udpsock_t * udpsock = fd_quic_client_create_udpsock( &_udpsock, wksp, fd_quic_get_aio_net_rx( quic ), 0 );
     181           0 :   FD_TEST( udpsock == &_udpsock );
     182             : 
     183           0 :   fd_quic_config_t * client_cfg = &quic->config;
     184           0 :   client_cfg->role = FD_QUIC_ROLE_CLIENT;
     185           0 :   client_cfg->idle_timeout = 200UL * 1000UL * 1000UL; /* 5000 millis */
     186           0 :   client_cfg->initial_rx_max_stream_data = 0; /* doesn't receive */
     187             : 
     188           0 :   fd_aio_pkt_info_t pkt[ MAX_TXN_COUNT ];
     189             : 
     190           0 :   if( FD_LIKELY( !args->txn.payload_base64 ) ) {
     191           0 :     FD_LOG_INFO(( "Transaction payload not specified, using hardcoded sample payload" ));
     192           0 :     for( ulong i=0; i<args->txn.count; i++ ) {
     193           0 :       pkt[ i ].buf    = (void * )sample_transaction;
     194           0 :       pkt[ i ].buf_sz = (ushort )sample_transaction_sz;
     195           0 :     }
     196           0 :   } else {
     197           0 :     ulong payload_b64_sz = strlen( args->txn.payload_base64 );
     198             : 
     199           0 :     static uchar buf[ 1UL << 15UL ];
     200           0 :     if( FD_UNLIKELY( FD_BASE64_DEC_SZ( payload_b64_sz ) > sizeof(buf) ) )
     201           0 :       FD_LOG_ERR(( "Input payload is too large (max %lu bytes)", sizeof(buf) ));
     202             : 
     203           0 :     long buf_sz = fd_base64_decode( buf, args->txn.payload_base64, payload_b64_sz );
     204           0 :     if( FD_UNLIKELY( buf_sz<0L ) ) FD_LOG_ERR(( "bad payload input `%s`", args->txn.payload_base64 ));
     205             : 
     206           0 :     for( ulong i=0; i<args->txn.count; i++ ) {
     207           0 :       pkt[ i ].buf    = (void * )buf;
     208           0 :       pkt[ i ].buf_sz = (ushort )buf_sz;
     209           0 :     }
     210           0 :   }
     211             : 
     212           0 :   uint dst_ip = config->net.ip_addr;
     213           0 :   if( FD_UNLIKELY( args->txn.dst_ip ) )
     214           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( args->txn.dst_ip, &dst_ip  ) ) ) FD_LOG_ERR(( "invalid --dst-ip" ));
     215             : 
     216           0 :   ushort dst_port = config->tiles.quic.quic_transaction_listen_port;
     217           0 :   if( FD_UNLIKELY( args->txn.dst_port ) ) dst_port = args->txn.dst_port;
     218             : 
     219           0 :   FD_LOG_NOTICE(( "sending %lu transactions to "FD_IP4_ADDR_FMT":%hu", args->txn.count, FD_IP4_ADDR_FMT_ARGS(dst_ip), dst_port ));
     220             : 
     221           0 :   send_quic_transactions( quic, udpsock, args->txn.count, dst_ip, dst_port, pkt );
     222           0 :   fd_sys_util_exit_group( 0 );
     223           0 : }
     224             : 
     225             : action_t fd_action_txn = {
     226             :   .name = "txn",
     227             :   .args = txn_cmd_args,
     228             :   .fn   = txn_cmd_fn,
     229             :   .perm = txn_cmd_perm,
     230             :   .description = "Send a transaction to an fddev instance"
     231             : };

Generated by: LCOV version 1.14