LCOV - code coverage report
Current view: top level - ballet/txn - fd_txn_build.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 196 278 70.5 %
Date: 2026-08-14 04:54:57 Functions: 13 18 72.2 %

          Line data    Source code
       1             : #include "fd_txn_build.h"
       2             : #include "fd_txn.h"
       3             : #include "fd_compact_u16.h"
       4             : #include "../../flamenco/runtime/fd_system_ids_pp.h"
       5             : 
       6             : FD_STATIC_ASSERT( FD_TXN_ACCT_CAT_PIN       > FD_TXN_ACCT_CAT_ALL, flags );
       7             : FD_STATIC_ASSERT( FD_TXN_ACCT_CAT_FEE_PAYER > FD_TXN_ACCT_CAT_ALL, flags );
       8             : 
       9             : /* Implementation */
      10             : 
      11             : fd_txn_builder_t *
      12             : fd_txn_builder_new( fd_txn_builder_t * mem,
      13         105 :                     ulong              seed ) {
      14             : 
      15             :   /* Sanity check */
      16         105 :   if( FD_UNLIKELY(
      17         105 :       !mem ||
      18         105 :       !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_builder_t) ) ) ) {
      19           0 :     return NULL;
      20           0 :   }
      21             : 
      22         105 :   fd_txn_builder_t * builder = mem;
      23         105 :   memset( builder, 0, sizeof(fd_txn_builder_t) );
      24         105 :   builder->alut_i = UCHAR_MAX; /* sentinel: no ALUT open */
      25         105 :   FD_TEST( fd_txn_b_addr_map_new( &builder->map, FD_TXN_B_ADDR_CHAIN_CNT, seed ) );
      26             : 
      27         105 :   return builder;
      28         105 : }
      29             : 
      30             : void *
      31         105 : fd_txn_builder_delete( fd_txn_builder_t * builder ) {
      32         105 :   FD_TEST( fd_txn_b_addr_map_delete( &builder->map ) );
      33         105 :   return builder;
      34         105 : }
      35             : 
      36             : static ulong
      37             : fd_txn_b_acct_acquire( fd_txn_builder_t *     builder,
      38         348 :                        fd_acct_addr_t const * acct_addr ) {
      39             : 
      40         348 :   ulong idx = fd_txn_b_addr_map_idx_query( &builder->map, acct_addr, ULONG_MAX, builder->acct );
      41         348 :   if( idx!=ULONG_MAX ) return idx;
      42             : 
      43         324 :   if( FD_UNLIKELY( builder->acct_cnt >= FD_TXN_ACCT_ADDR_MAX ) ) return ULONG_MAX;
      44         324 :   idx = builder->acct_cnt;
      45         324 :   fd_txn_b_acct_t * acct = &builder->acct[ idx ];
      46         324 :   acct->key = *acct_addr;
      47         324 :   builder->acct_map[ idx ] = (uchar)idx;
      48         324 :   builder->acct_rev[ idx ] = (uchar)idx;
      49         324 :   builder->acct_cnt++;
      50             : 
      51         324 :   fd_txn_b_addr_map_idx_insert( &builder->map, idx, builder->acct );
      52         324 :   return idx;
      53         324 : }
      54             : 
      55             : fd_txn_builder_t *
      56             : fd_txn_builder_fee_payer_set( fd_txn_builder_t * builder,
      57         105 :                               void const *       fee_payer ) {
      58         105 :   if( FD_UNLIKELY( builder->fee_payer_set ) ) return NULL;
      59         105 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, fee_payer );
      60         105 :   ulong acct_idx = fd_txn_b_acct_acquire( builder, &addr );
      61         105 :   if( FD_UNLIKELY( acct_idx==ULONG_MAX ) ) return NULL;
      62         105 :   fd_txn_b_acct_t * acct = &builder->acct[ acct_idx ];
      63         105 :   acct->cat &= (uchar)~FD_TXN_ACCT_CAT_ALL;
      64         105 :   acct->cat |= FD_TXN_ACCT_CAT_WRITABLE_SIGNER | FD_TXN_ACCT_CAT_FEE_PAYER;
      65         105 :   builder->fee_payer_acct = (uchar)acct_idx;
      66         105 :   builder->fee_payer_set  = 1;
      67         105 :   return builder;
      68         105 : }
      69             : 
      70             : static uint
      71             : fd_txn_b_acct_cat_promote( uint prev_cat,
      72         243 :                            uint req_cat ) {
      73         243 :   int const req_signer   = ( (req_cat & FD_TXN_ACCT_CAT_SIGNER  ) == FD_TXN_ACCT_CAT_SIGNER   );
      74         243 :   int const req_writable = ( (req_cat & FD_TXN_ACCT_CAT_WRITABLE) == FD_TXN_ACCT_CAT_WRITABLE );
      75         243 :   int const is_signer    = !!( prev_cat & FD_TXN_ACCT_CAT_SIGNER   ) || req_signer;
      76         243 :   int const is_writable  = !!( prev_cat & FD_TXN_ACCT_CAT_WRITABLE ) || req_writable;
      77         243 :   uint      new_raw     = is_signer
      78         243 :                         ? ( is_writable ? FD_TXN_ACCT_CAT_WRITABLE_SIGNER        : FD_TXN_ACCT_CAT_READONLY_SIGNER )
      79         243 :                         : ( is_writable ? FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM : FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM );
      80             : 
      81         243 :   return (prev_cat & ~((uint)FD_TXN_ACCT_CAT_ALL)) | new_raw;
      82         243 : }
      83             : 
      84             : fd_txn_builder_t *
      85             : fd_txn_builder_instr_open( fd_txn_builder_t * builder,
      86             :                            void const *       program_id,
      87             :                            void const *       data,
      88         105 :                            ulong              data_sz ) {
      89             : 
      90         105 :   if( FD_UNLIKELY( builder->alut_set ) ) return NULL;
      91             : 
      92             :   /* Program account */
      93             : 
      94         105 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, program_id );
      95         105 :   ulong program_acct_idx = fd_txn_b_acct_acquire( builder, &addr );
      96         105 :   if( FD_UNLIKELY( program_acct_idx==ULONG_MAX ) ) return NULL;
      97         105 :   fd_txn_b_acct_t * program_acct = &builder->acct[ program_acct_idx ];
      98         105 :   program_acct->cat = (uchar)fd_txn_b_acct_cat_promote( program_acct->cat, FD_TXN_ACCT_CAT_NONE );
      99         105 :   program_acct->cat |= FD_TXN_ACCT_CAT_PIN;
     100             : 
     101             :   /* Instruction data */
     102             : 
     103         105 :   ulong data_off = builder->data_bump_sz;
     104         105 :   ulong data_end = data_off + data_sz;
     105         105 :   if( FD_UNLIKELY( data_end>FD_TXN_B_DATA_BUMP_MAX ) ) return NULL;
     106         105 :   uchar * saved_data = builder->data_bump + data_off;
     107         105 :   fd_memcpy( saved_data, data, data_sz );
     108         105 :   builder->data_bump_sz = (ushort)( (ulong)builder->data_bump_sz + data_sz );
     109             : 
     110             :   /* Instruction */
     111             : 
     112         105 :   if( FD_UNLIKELY( builder->instr_cnt >= FD_TXN_INSTR_MAX ) ) return NULL;
     113         105 :   fd_txn_b_instr_t * instr = &builder->instr[ builder->instr_cnt++ ];
     114         105 :   instr->program_id     = (uchar)program_acct_idx;
     115         105 :   instr->instr_acct0    = builder->instr_acct_cnt;
     116         105 :   instr->instr_acct_cnt = 0;
     117         105 :   instr->data_off       = (ushort)data_off;
     118         105 :   instr->data_sz        = (ushort)data_sz;
     119             : 
     120         105 :   return builder;
     121         105 : }
     122             : 
     123             : fd_txn_builder_t *
     124             : fd_txn_builder_instr_account_push(
     125             :     fd_txn_builder_t * builder,
     126             :     void const *       acct_addr,
     127             :     uint               acct_cat
     128         138 : ) {
     129         138 :   if( FD_UNLIKELY( builder->instr_cnt==0 ) ) return NULL;
     130         138 :   fd_txn_b_instr_t * instr = &builder->instr[ builder->instr_cnt-1 ];
     131             : 
     132             :   /* Transaction Account */
     133             : 
     134         138 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, acct_addr );
     135         138 :   ulong acct_idx = fd_txn_b_acct_acquire( builder, &addr );
     136         138 :   if( FD_UNLIKELY( acct_idx==ULONG_MAX ) ) return NULL;
     137         138 :   fd_txn_b_acct_t * acct = &builder->acct[ acct_idx ];
     138             : 
     139             :   /* Instruction Account */
     140             : 
     141         138 :   if( FD_UNLIKELY( instr->instr_acct_cnt   >= FD_TXN_ACCT_ADDR_MAX ) ) return NULL;
     142         138 :   if( FD_UNLIKELY( builder->instr_acct_cnt >= FD_TXN_ACCT_ADDR_MAX ) ) return NULL;
     143         138 :   ulong instr_acct_idx =  builder->instr_acct_cnt++;
     144         138 :   ulong exp_instr_acct_idx = (ulong)instr->instr_acct0 + (instr->instr_acct_cnt++);
     145         138 :   FD_TEST( instr_acct_idx==exp_instr_acct_idx );
     146         138 :   builder->instr_acct[ instr_acct_idx ] = (uchar)acct_idx;
     147             : 
     148             :   /* Promote access category */
     149             : 
     150         138 :   acct->cat = (uchar)fd_txn_b_acct_cat_promote( acct->cat, acct_cat );
     151             : 
     152         138 :   return builder;
     153         138 : }
     154             : 
     155             : void
     156         105 : fd_txn_builder_instr_close( fd_txn_builder_t * builder ) {
     157         105 :   (void)builder;
     158         105 : }
     159             : 
     160             : fd_txn_builder_t *
     161             : fd_txn_builder_nonce_set( fd_txn_builder_t * builder,
     162             :                           void const *       nonce_account,
     163           0 :                           void const *       nonce_authority ) {
     164             :   /* The advance nonce instruction must be the first instruction in the
     165             :      transaction, so reject if any instruction was already opened. */
     166           0 :   if( FD_UNLIKELY( builder->instr_cnt!=0 ) ) return NULL;
     167             : 
     168           0 :   static fd_acct_addr_t const system_prog_id        = { .b = { SYS_PROG_ID               } };
     169           0 :   static fd_acct_addr_t const recent_blockhashes_id = { .b = { SYSVAR_RECENT_BLKHASH_ID } };
     170           0 :   uchar const data[4] = { 0x04, 0x00, 0x00, 0x00 };
     171           0 :   if( FD_UNLIKELY( !fd_txn_builder_instr_open(
     172           0 :       builder, &system_prog_id, data, sizeof(data) ) ) ) return NULL;
     173           0 :   if( FD_UNLIKELY( !fd_txn_builder_instr_account_push(
     174           0 :       builder, nonce_account, FD_TXN_ACCT_CAT_WRITABLE ) ) ) return NULL;
     175           0 :   if( FD_UNLIKELY( !fd_txn_builder_instr_account_push(
     176           0 :       builder, &recent_blockhashes_id, FD_TXN_ACCT_CAT_NONE ) ) ) return NULL;
     177           0 :   if( FD_UNLIKELY( !fd_txn_builder_instr_account_push(
     178           0 :       builder, nonce_authority, FD_TXN_ACCT_CAT_SIGNER ) ) ) return NULL;
     179           0 :   fd_txn_builder_instr_close( builder );
     180           0 :   return builder;
     181           0 : }
     182             : 
     183             : fd_txn_builder_t *
     184             : fd_txn_builder_alut_open( fd_txn_builder_t * builder,
     185           0 :                           void const *       alut_addr ) {
     186             :   /* The builder only serializes a single ALUT, so reject a second open. */
     187           0 :   if( FD_UNLIKELY( builder->alut_i!=UCHAR_MAX ) ) return NULL;
     188           0 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, alut_addr );
     189           0 :   ulong alut_i = fd_txn_b_acct_acquire( builder, &addr );
     190           0 :   if( FD_UNLIKELY( alut_i==ULONG_MAX ) ) return NULL;
     191           0 :   fd_txn_b_acct_t * alut_acct = &builder->acct[ alut_i ];
     192           0 :   alut_acct->cat = (uchar)fd_txn_b_acct_cat_promote( alut_acct->cat, FD_TXN_ACCT_CAT_NONE );
     193           0 :   alut_acct->cat |= FD_TXN_ACCT_CAT_PIN; /* ALUT itself cannot be in ALUT */
     194           0 :   builder->alut_i     = (uchar)alut_i;
     195           0 :   return builder;
     196           0 : }
     197             : 
     198             : void
     199             : fd_txn_builder_alut_address_push(
     200             :     fd_txn_builder_t * builder,
     201             :     void const *       acct_addr,
     202             :     uint const         alut_j
     203           0 : ) {
     204           0 :   uint const alut_i = builder->alut_i;
     205             : 
     206             :   /* Requires an opened ALUT.  alut_j is serialized as a u8. */
     207           0 :   if( FD_UNLIKELY( alut_i==UCHAR_MAX ) ) return;
     208           0 :   if( FD_UNLIKELY( alut_j>UCHAR_MAX  ) ) return;
     209             : 
     210           0 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, acct_addr );
     211           0 :   ulong const acct_idx = fd_txn_b_addr_map_idx_query(
     212           0 :       &builder->map, &addr, ULONG_MAX, builder->acct );
     213           0 :   if( FD_UNLIKELY( acct_idx==ULONG_MAX ) ) return;
     214             : 
     215             :   /* Can account be demoted? */
     216             : 
     217           0 :   fd_txn_b_acct_t * acct = &builder->acct[ acct_idx ];
     218           0 :   if( FD_UNLIKELY( acct->cat & FD_TXN_ACCT_CAT_IS_PIN ) ) return;
     219             : 
     220             :   /* Already demoted to an ALUT?  Ignore subsequent calls. */
     221             : 
     222           0 :   if( FD_UNLIKELY( acct->cat & FD_TXN_ACCT_CAT_ALT ) ) return;
     223             : 
     224             :   /* Demote account to ALUT */
     225             : 
     226           0 :   if( acct->cat & FD_TXN_ACCT_CAT_WRITABLE ) {
     227           0 :     acct->cat = FD_TXN_ACCT_CAT_WRITABLE_ALT;
     228           0 :   } else {
     229           0 :     acct->cat = FD_TXN_ACCT_CAT_READONLY_ALT;
     230           0 :   }
     231           0 :   acct->alut_i = (uchar)alut_i;
     232           0 :   acct->alut_j =        alut_j;
     233             : 
     234           0 :   builder->alut_set = 1;
     235           0 : }
     236             : 
     237             : void
     238           0 : fd_txn_builder_alut_close( fd_txn_builder_t * builder ) {
     239           0 :   (void)builder;
     240           0 : }
     241             : 
     242             : static inline uint
     243         648 : fd_txn_b_acct_prio( fd_txn_b_acct_t const * acct ) {
     244         648 :   uint const cat = acct->cat;
     245         648 :   return (cat & FD_TXN_ACCT_CAT_FEE_PAYER) ? 0U : (uint)( fd_uint_find_lsb( cat & FD_TXN_ACCT_CAT_ALL )+1 );
     246         648 : }
     247             : 
     248         840 : #define FD_TXN_B_ACCT_PRIO_CNT 7UL
     249             : 
     250             : /* fd_txn_b_bake prepares a transaction for building.  For now, only
     251             :    sorts accounts. */
     252             : 
     253             : static void
     254             : fd_txn_b_bake( fd_txn_builder_t * builder,
     255         105 :                ulong              cnt[ FD_TXN_B_ACCT_PRIO_CNT ] ) {
     256         105 :   ulong const acct_cnt = builder->acct_cnt;
     257             : 
     258         105 :   fd_memset( cnt, 0, FD_TXN_B_ACCT_PRIO_CNT*sizeof(ulong) );
     259         429 :   for( ulong i=0UL; i<acct_cnt; i++ ) cnt[ fd_txn_b_acct_prio( &builder->acct[ builder->acct_map[ i ] ] ) ]++;
     260             : 
     261         105 :   ulong off[ FD_TXN_B_ACCT_PRIO_CNT ];
     262         105 :   off[ 0 ] = 0UL;
     263         735 :   for( ulong i=1UL; i<FD_TXN_B_ACCT_PRIO_CNT; i++ ) off[ i ] = off[ i-1UL ] + cnt[ i-1UL ];
     264             : 
     265         105 :   uchar scratch[ FD_TXN_ACCT_ADDR_MAX ];
     266         429 :   for( ulong i=0UL; i<acct_cnt; i++ ) {
     267         324 :     uchar const acct_i = builder->acct_map[ i ];
     268         324 :     scratch[ off[ fd_txn_b_acct_prio( &builder->acct[ acct_i ] ) ]++ ] = acct_i;
     269         324 :   }
     270             : 
     271         105 :   fd_memcpy( builder->acct_map, scratch, acct_cnt );
     272         429 :   for( ulong i=0UL; i<acct_cnt; i++ ) builder->acct_rev[ builder->acct_map[ i ] ] = (uchar)i;
     273         105 : }
     274             : 
     275             : static inline uchar *
     276             : fd_txn_b_cu16_write( uchar * out,
     277             :                      uchar * end,
     278         420 :                      ulong   val ) {
     279         420 :   if( FD_UNLIKELY( val>USHORT_MAX ) ) return NULL;
     280         420 :   ulong enc_sz = 1UL + ( val>0x7FUL ) + ( val>0x3FFFUL );
     281         420 :   if( FD_UNLIKELY( out+enc_sz>end ) ) return NULL;
     282         420 :   out += fd_cu16_enc( (ushort)val, out );
     283         420 :   return out;
     284         420 : }
     285             : 
     286             : __attribute__((always_inline)) static inline uint
     287             : fd_txn_build_core( fd_txn_builder_t *        builder,
     288         105 :                    uchar                     out_[ FD_TXN_MTU_V0 ] ) {
     289         324 : #define ACCT( i ) (&builder->acct[ builder->acct_map[ i ] ])
     290             : 
     291         105 :   ulong cnt[ FD_TXN_B_ACCT_PRIO_CNT ];
     292         105 :   fd_txn_b_bake( builder, cnt );
     293             : 
     294         105 :   uchar *       out      = out_;
     295         105 :   uchar * const end      = out + FD_TXN_MTU_V0;
     296             : 
     297         105 :   ulong const rw_sig_cnt = cnt[ 0 ] + cnt[ 1 ];
     298         105 :   ulong const ro_sig_cnt = cnt[ 2 ];
     299         105 :   ulong const rw_uns_cnt = cnt[ 3 ];
     300         105 :   ulong const ro_uns_cnt = cnt[ 4 ];
     301         105 :   ulong const rw_alt_cnt = cnt[ 5 ];
     302         105 :   ulong const ro_alt_cnt = cnt[ 6 ];
     303             : 
     304         105 :   ulong const sig_cnt = rw_sig_cnt + ro_sig_cnt;
     305         105 :   ulong const imm_cnt = sig_cnt + rw_uns_cnt + ro_uns_cnt;
     306         105 :   ulong const alt_cnt = rw_alt_cnt + ro_alt_cnt;
     307             : 
     308         105 :   if( FD_UNLIKELY( sig_cnt > FD_TXN_SIG_MAX ) ) return 0;
     309         105 :   if( FD_UNLIKELY( !builder->fee_payer_set ) ) return 0;
     310         105 :   if( FD_UNLIKELY( builder->acct_rev[ builder->fee_payer_acct ]!=0U ) ) return 0;
     311             : 
     312         105 :   out[0] = (uchar)sig_cnt;
     313         105 :   out++;
     314         105 :   fd_memset( out, 0, sig_cnt*FD_TXN_SIGNATURE_SZ );
     315         105 :   out += sig_cnt*FD_TXN_SIGNATURE_SZ;
     316         105 :   if( FD_UNLIKELY( out>end ) ) return 0;
     317             : 
     318         105 :   if( alt_cnt ) {
     319           0 :     if( FD_UNLIKELY( out>=end ) ) return 0;
     320           0 :     out[0] = 0x80; /* txn v0 */
     321           0 :     out++;
     322           0 :   }
     323             : 
     324         105 :   if( FD_UNLIKELY( out+3>end ) ) return 0;
     325         105 :   out[0] = (uchar)sig_cnt;
     326         105 :   out[1] = (uchar)ro_sig_cnt;
     327         105 :   out[2] = (uchar)ro_uns_cnt;
     328         105 :   out += 3;
     329             : 
     330         105 :   out = fd_txn_b_cu16_write( out, end, imm_cnt );
     331         105 :   if( FD_UNLIKELY( !out ) ) return 0;
     332             : 
     333         105 :   ulong addr_tbl_sz = imm_cnt*FD_TXN_ACCT_ADDR_SZ;
     334         105 :   if( FD_UNLIKELY( out+addr_tbl_sz>end ) ) return 0;
     335         429 :   for( ulong i=0UL; i<imm_cnt; i++ ) {
     336         324 :     fd_txn_b_acct_t * acct = ACCT( i );
     337         324 :     fd_memcpy( out, &acct->key, FD_TXN_ACCT_ADDR_SZ );
     338         324 :     out += FD_TXN_ACCT_ADDR_SZ;
     339         324 :   }
     340             : 
     341         105 :   if( FD_UNLIKELY( out+FD_TXN_ACCT_ADDR_SZ>end ) ) return 0;
     342         105 :   fd_memcpy( out, &builder->recent_blockhash, FD_TXN_ACCT_ADDR_SZ );
     343         105 :   out += FD_TXN_ACCT_ADDR_SZ;
     344             : 
     345         105 :   if( FD_UNLIKELY( out>=end ) ) return 0;
     346         105 :   ulong const instr_cnt = builder->instr_cnt;
     347         105 :   out = fd_txn_b_cu16_write( out, end, instr_cnt );
     348         105 :   if( FD_UNLIKELY( !out ) ) return 0;
     349             : 
     350         210 :   for( ulong j=0UL; j<instr_cnt; j++ ) {
     351         105 :     fd_txn_b_instr_t * instr = &builder->instr[ j ];
     352         105 :     ulong const instr_acct_cnt = instr->instr_acct_cnt;
     353             : 
     354         105 :     if( FD_UNLIKELY( out+1>end ) ) return 0;
     355         105 :     out[0] = builder->acct_rev[ instr->program_id ];
     356         105 :     out++;
     357             : 
     358         105 :     out = fd_txn_b_cu16_write( out, end, instr_acct_cnt );
     359         105 :     if( FD_UNLIKELY( !out ) ) return 0;
     360             : 
     361         105 :     if( FD_UNLIKELY( out+instr_acct_cnt>end ) ) return 0;
     362         243 :     for( ulong k=0UL; k<instr_acct_cnt; k++ ) {
     363         138 :       ulong const acct_idx = builder->acct_rev[ builder->instr_acct[ instr->instr_acct0 + k ] ];
     364         138 :       out[0] = (uchar)acct_idx;
     365         138 :       out++;
     366         138 :     }
     367             : 
     368         105 :     ulong const data_sz = instr->data_sz;
     369         105 :     out = fd_txn_b_cu16_write( out, end, data_sz );
     370         105 :     if( FD_UNLIKELY( !out ) ) return 0;
     371             : 
     372         105 :     if( FD_UNLIKELY( out+data_sz>end ) ) return 0;
     373         105 :     fd_memcpy( out, &builder->data_bump[ instr->data_off ], data_sz );
     374         105 :     out += data_sz;
     375         105 :   }
     376             : 
     377         105 :   if( alt_cnt ) {
     378           0 :     out = fd_txn_b_cu16_write( out, end, 1UL );
     379           0 :     if( FD_UNLIKELY( !out ) ) return 0;
     380             : 
     381           0 :     fd_txn_b_acct_t * alut_acct = &builder->acct[ builder->alut_i ];
     382           0 :     if( FD_UNLIKELY( out+FD_TXN_ACCT_ADDR_SZ>end ) ) return 0;
     383           0 :     fd_memcpy( out, &alut_acct->key, FD_TXN_ACCT_ADDR_SZ );
     384           0 :     out += FD_TXN_ACCT_ADDR_SZ;
     385             : 
     386           0 :     out = fd_txn_b_cu16_write( out, end, rw_alt_cnt );
     387           0 :     if( FD_UNLIKELY( !out ) ) return 0;
     388           0 :     if( FD_UNLIKELY( out+rw_alt_cnt>end ) ) return 0;
     389           0 :     for( ulong j=imm_cnt; j<imm_cnt+rw_alt_cnt; j++ ) {
     390           0 :       if( FD_UNLIKELY( ACCT( j )->alut_j>255U ) ) return 0;
     391           0 :       out[0] = (uchar)ACCT( j )->alut_j;
     392           0 :       out++;
     393           0 :     }
     394             : 
     395           0 :     out = fd_txn_b_cu16_write( out, end, ro_alt_cnt );
     396           0 :     if( FD_UNLIKELY( !out ) ) return 0;
     397           0 :     if( FD_UNLIKELY( out+ro_alt_cnt>end ) ) return 0;
     398           0 :     for( ulong j=imm_cnt+rw_alt_cnt; j<imm_cnt+alt_cnt; j++ ) {
     399           0 :       if( FD_UNLIKELY( ACCT( j )->alut_j>255U ) ) return 0;
     400           0 :       out[0] = (uchar)ACCT( j )->alut_j;
     401           0 :       out++;
     402           0 :     }
     403           0 :   }
     404             : 
     405         105 : #undef ACCT
     406         105 :   return (uint)( out - out_ );
     407         105 : }
     408             : 
     409             : uint
     410             : fd_txn_build_raw( fd_txn_builder_t * builder,
     411           0 :                   uchar              out[ FD_TXN_MTU_V0 ] ) {
     412           0 :   return fd_txn_build_core( builder, out );
     413           0 : }
     414             : 
     415             : uint
     416             : fd_txn_build( fd_txn_builder_t *  builder,
     417             :               uchar               out[ FD_TXN_MTU_V0 ],
     418             :               fd_txn_t * restrict out_txn,
     419         105 :               ushort *            opt_out_txn_t_sz ) {
     420         105 :   uint payload_sz = fd_txn_build_core( builder, out );
     421         105 :   if( FD_UNLIKELY( !payload_sz ) ) return 0U;
     422             : 
     423         105 :   ulong txn_t_sz = fd_txn_parse( out, payload_sz, out_txn, NULL );
     424         105 :   if( FD_UNLIKELY( !txn_t_sz ) ) return 0U;
     425         105 :   if( opt_out_txn_t_sz ) *opt_out_txn_t_sz = (ushort)txn_t_sz;
     426         105 :   return payload_sz;
     427         105 : }

Generated by: LCOV version 1.14