LCOV - code coverage report
Current view: top level - ballet/txn - fd_txn_build.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 278 0.0 %
Date: 2026-06-29 05:51:35 Functions: 0 18 0.0 %

          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           0 :                     ulong              seed ) {
      14             : 
      15             :   /* Sanity check */
      16           0 :   if( FD_UNLIKELY(
      17           0 :       !mem ||
      18           0 :       !fd_ulong_is_aligned( (ulong)mem, alignof(fd_txn_builder_t) ) ) ) {
      19           0 :     return NULL;
      20           0 :   }
      21             : 
      22           0 :   fd_txn_builder_t * builder = mem;
      23           0 :   memset( builder, 0, sizeof(fd_txn_builder_t) );
      24           0 :   builder->alut_i = UCHAR_MAX; /* sentinel: no ALUT open */
      25           0 :   FD_TEST( fd_txn_b_addr_map_new( &builder->map, FD_TXN_B_ADDR_CHAIN_CNT, seed ) );
      26             : 
      27           0 :   return builder;
      28           0 : }
      29             : 
      30             : void *
      31           0 : fd_txn_builder_delete( fd_txn_builder_t * builder ) {
      32           0 :   FD_TEST( fd_txn_b_addr_map_delete( &builder->map ) );
      33           0 :   return builder;
      34           0 : }
      35             : 
      36             : static ulong
      37             : fd_txn_b_acct_acquire( fd_txn_builder_t *     builder,
      38           0 :                        fd_acct_addr_t const * acct_addr ) {
      39             : 
      40           0 :   ulong idx = fd_txn_b_addr_map_idx_query( &builder->map, acct_addr, ULONG_MAX, builder->acct );
      41           0 :   if( idx!=ULONG_MAX ) return idx;
      42             : 
      43           0 :   if( FD_UNLIKELY( builder->acct_cnt >= FD_TXN_ACCT_ADDR_MAX ) ) return ULONG_MAX;
      44           0 :   idx = builder->acct_cnt;
      45           0 :   fd_txn_b_acct_t * acct = &builder->acct[ idx ];
      46           0 :   acct->key = *acct_addr;
      47           0 :   builder->acct_map[ idx ] = (uchar)idx;
      48           0 :   builder->acct_rev[ idx ] = (uchar)idx;
      49           0 :   builder->acct_cnt++;
      50             : 
      51           0 :   fd_txn_b_addr_map_idx_insert( &builder->map, idx, builder->acct );
      52           0 :   return idx;
      53           0 : }
      54             : 
      55             : fd_txn_builder_t *
      56             : fd_txn_builder_fee_payer_set( fd_txn_builder_t * builder,
      57           0 :                               void const *       fee_payer ) {
      58           0 :   if( FD_UNLIKELY( builder->fee_payer_set ) ) return NULL;
      59           0 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, fee_payer );
      60           0 :   ulong acct_idx = fd_txn_b_acct_acquire( builder, &addr );
      61           0 :   if( FD_UNLIKELY( acct_idx==ULONG_MAX ) ) return NULL;
      62           0 :   fd_txn_b_acct_t * acct = &builder->acct[ acct_idx ];
      63           0 :   acct->cat &= (uchar)~FD_TXN_ACCT_CAT_ALL;
      64           0 :   acct->cat |= FD_TXN_ACCT_CAT_WRITABLE_SIGNER | FD_TXN_ACCT_CAT_FEE_PAYER;
      65           0 :   builder->fee_payer_acct = (uchar)acct_idx;
      66           0 :   builder->fee_payer_set  = 1;
      67           0 :   return builder;
      68           0 : }
      69             : 
      70             : static uint
      71             : fd_txn_b_acct_cat_promote( uint prev_cat,
      72           0 :                            uint req_cat ) {
      73           0 :   int const req_signer   = ( (req_cat & FD_TXN_ACCT_CAT_SIGNER  ) == FD_TXN_ACCT_CAT_SIGNER   );
      74           0 :   int const req_writable = ( (req_cat & FD_TXN_ACCT_CAT_WRITABLE) == FD_TXN_ACCT_CAT_WRITABLE );
      75           0 :   int const is_signer    = !!( prev_cat & FD_TXN_ACCT_CAT_SIGNER   ) || req_signer;
      76           0 :   int const is_writable  = !!( prev_cat & FD_TXN_ACCT_CAT_WRITABLE ) || req_writable;
      77           0 :   uint      new_raw     = is_signer
      78           0 :                         ? ( is_writable ? FD_TXN_ACCT_CAT_WRITABLE_SIGNER        : FD_TXN_ACCT_CAT_READONLY_SIGNER )
      79           0 :                         : ( is_writable ? FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM : FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM );
      80             : 
      81           0 :   return (prev_cat & ~((uint)FD_TXN_ACCT_CAT_ALL)) | new_raw;
      82           0 : }
      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           0 :                            ulong              data_sz ) {
      89             : 
      90           0 :   if( FD_UNLIKELY( builder->alut_set ) ) return NULL;
      91             : 
      92             :   /* Program account */
      93             : 
      94           0 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, program_id );
      95           0 :   ulong program_acct_idx = fd_txn_b_acct_acquire( builder, &addr );
      96           0 :   if( FD_UNLIKELY( program_acct_idx==ULONG_MAX ) ) return NULL;
      97           0 :   fd_txn_b_acct_t * program_acct = &builder->acct[ program_acct_idx ];
      98           0 :   program_acct->cat = (uchar)fd_txn_b_acct_cat_promote( program_acct->cat, FD_TXN_ACCT_CAT_NONE );
      99           0 :   program_acct->cat |= FD_TXN_ACCT_CAT_PIN;
     100             : 
     101             :   /* Instruction data */
     102             : 
     103           0 :   ulong data_off = builder->data_bump_sz;
     104           0 :   ulong data_end = data_off + data_sz;
     105           0 :   if( FD_UNLIKELY( data_end>FD_TXN_B_DATA_BUMP_MAX ) ) return NULL;
     106           0 :   uchar * saved_data = builder->data_bump + data_off;
     107           0 :   fd_memcpy( saved_data, data, data_sz );
     108           0 :   builder->data_bump_sz = (ushort)( (ulong)builder->data_bump_sz + data_sz );
     109             : 
     110             :   /* Instruction */
     111             : 
     112           0 :   if( FD_UNLIKELY( builder->instr_cnt >= FD_TXN_INSTR_MAX ) ) return NULL;
     113           0 :   fd_txn_b_instr_t * instr = &builder->instr[ builder->instr_cnt++ ];
     114           0 :   instr->program_id     = (uchar)program_acct_idx;
     115           0 :   instr->instr_acct0    = builder->instr_acct_cnt;
     116           0 :   instr->instr_acct_cnt = 0;
     117           0 :   instr->data_off       = (ushort)data_off;
     118           0 :   instr->data_sz        = (ushort)data_sz;
     119             : 
     120           0 :   return builder;
     121           0 : }
     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           0 : ) {
     129           0 :   if( FD_UNLIKELY( builder->instr_cnt==0 ) ) return NULL;
     130           0 :   fd_txn_b_instr_t * instr = &builder->instr[ builder->instr_cnt-1 ];
     131             : 
     132             :   /* Transaction Account */
     133             : 
     134           0 :   fd_acct_addr_t addr = FD_LOAD( fd_acct_addr_t, acct_addr );
     135           0 :   ulong acct_idx = fd_txn_b_acct_acquire( builder, &addr );
     136           0 :   if( FD_UNLIKELY( acct_idx==ULONG_MAX ) ) return NULL;
     137           0 :   fd_txn_b_acct_t * acct = &builder->acct[ acct_idx ];
     138             : 
     139             :   /* Instruction Account */
     140             : 
     141           0 :   if( FD_UNLIKELY( instr->instr_acct_cnt   >= FD_TXN_ACCT_ADDR_MAX ) ) return NULL;
     142           0 :   if( FD_UNLIKELY( builder->instr_acct_cnt >= FD_TXN_ACCT_ADDR_MAX ) ) return NULL;
     143           0 :   ulong instr_acct_idx =  builder->instr_acct_cnt++;
     144           0 :   ulong exp_instr_acct_idx = (ulong)instr->instr_acct0 + (instr->instr_acct_cnt++);
     145           0 :   FD_TEST( instr_acct_idx==exp_instr_acct_idx );
     146           0 :   builder->instr_acct[ instr_acct_idx ] = (uchar)acct_idx;
     147             : 
     148             :   /* Promote access category */
     149             : 
     150           0 :   acct->cat = (uchar)fd_txn_b_acct_cat_promote( acct->cat, acct_cat );
     151             : 
     152           0 :   return builder;
     153           0 : }
     154             : 
     155             : void
     156           0 : fd_txn_builder_instr_close( fd_txn_builder_t * builder ) {
     157           0 :   (void)builder;
     158           0 : }
     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           0 : fd_txn_b_acct_prio( fd_txn_b_acct_t const * acct ) {
     244           0 :   uint const cat = acct->cat;
     245           0 :   return (cat & FD_TXN_ACCT_CAT_FEE_PAYER) ? 0U : (uint)( fd_uint_find_lsb( cat & FD_TXN_ACCT_CAT_ALL )+1 );
     246           0 : }
     247             : 
     248           0 : #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           0 :                ulong              cnt[ FD_TXN_B_ACCT_PRIO_CNT ] ) {
     256           0 :   ulong const acct_cnt = builder->acct_cnt;
     257             : 
     258           0 :   fd_memset( cnt, 0, FD_TXN_B_ACCT_PRIO_CNT*sizeof(ulong) );
     259           0 :   for( ulong i=0UL; i<acct_cnt; i++ ) cnt[ fd_txn_b_acct_prio( &builder->acct[ builder->acct_map[ i ] ] ) ]++;
     260             : 
     261           0 :   ulong off[ FD_TXN_B_ACCT_PRIO_CNT ];
     262           0 :   off[ 0 ] = 0UL;
     263           0 :   for( ulong i=1UL; i<FD_TXN_B_ACCT_PRIO_CNT; i++ ) off[ i ] = off[ i-1UL ] + cnt[ i-1UL ];
     264             : 
     265           0 :   uchar scratch[ FD_TXN_ACCT_ADDR_MAX ];
     266           0 :   for( ulong i=0UL; i<acct_cnt; i++ ) {
     267           0 :     uchar const acct_i = builder->acct_map[ i ];
     268           0 :     scratch[ off[ fd_txn_b_acct_prio( &builder->acct[ acct_i ] ) ]++ ] = acct_i;
     269           0 :   }
     270             : 
     271           0 :   fd_memcpy( builder->acct_map, scratch, acct_cnt );
     272           0 :   for( ulong i=0UL; i<acct_cnt; i++ ) builder->acct_rev[ builder->acct_map[ i ] ] = (uchar)i;
     273           0 : }
     274             : 
     275             : static inline uchar *
     276             : fd_txn_b_cu16_write( uchar * out,
     277             :                      uchar * end,
     278           0 :                      ulong   val ) {
     279           0 :   if( FD_UNLIKELY( val>USHORT_MAX ) ) return NULL;
     280           0 :   ulong enc_sz = 1UL + ( val>0x7FUL ) + ( val>0x3FFFUL );
     281           0 :   if( FD_UNLIKELY( out+enc_sz>end ) ) return NULL;
     282           0 :   out += fd_cu16_enc( (ushort)val, out );
     283           0 :   return out;
     284           0 : }
     285             : 
     286             : __attribute__((always_inline)) static inline uint
     287             : fd_txn_build_core( fd_txn_builder_t *        builder,
     288           0 :                    uchar                     out_[ FD_TXN_MTU ] ) {
     289           0 : #define ACCT( i ) (&builder->acct[ builder->acct_map[ i ] ])
     290             : 
     291           0 :   ulong cnt[ FD_TXN_B_ACCT_PRIO_CNT ];
     292           0 :   fd_txn_b_bake( builder, cnt );
     293             : 
     294           0 :   uchar *       out      = out_;
     295           0 :   uchar * const end      = out + FD_TXN_MTU;
     296             : 
     297           0 :   ulong const rw_sig_cnt = cnt[ 0 ] + cnt[ 1 ];
     298           0 :   ulong const ro_sig_cnt = cnt[ 2 ];
     299           0 :   ulong const rw_uns_cnt = cnt[ 3 ];
     300           0 :   ulong const ro_uns_cnt = cnt[ 4 ];
     301           0 :   ulong const rw_alt_cnt = cnt[ 5 ];
     302           0 :   ulong const ro_alt_cnt = cnt[ 6 ];
     303             : 
     304           0 :   ulong const sig_cnt = rw_sig_cnt + ro_sig_cnt;
     305           0 :   ulong const imm_cnt = sig_cnt + rw_uns_cnt + ro_uns_cnt;
     306           0 :   ulong const alt_cnt = rw_alt_cnt + ro_alt_cnt;
     307             : 
     308           0 :   if( FD_UNLIKELY( sig_cnt > FD_TXN_SIG_MAX ) ) return 0;
     309           0 :   if( FD_UNLIKELY( !builder->fee_payer_set ) ) return 0;
     310           0 :   if( FD_UNLIKELY( builder->acct_rev[ builder->fee_payer_acct ]!=0U ) ) return 0;
     311             : 
     312           0 :   out[0] = (uchar)sig_cnt;
     313           0 :   out++;
     314           0 :   fd_memset( out, 0, sig_cnt*FD_TXN_SIGNATURE_SZ );
     315           0 :   out += sig_cnt*FD_TXN_SIGNATURE_SZ;
     316           0 :   if( FD_UNLIKELY( out>end ) ) return 0;
     317             : 
     318           0 :   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           0 :   if( FD_UNLIKELY( out+3>end ) ) return 0;
     325           0 :   out[0] = (uchar)sig_cnt;
     326           0 :   out[1] = (uchar)ro_sig_cnt;
     327           0 :   out[2] = (uchar)ro_uns_cnt;
     328           0 :   out += 3;
     329             : 
     330           0 :   out = fd_txn_b_cu16_write( out, end, imm_cnt );
     331           0 :   if( FD_UNLIKELY( !out ) ) return 0;
     332             : 
     333           0 :   ulong addr_tbl_sz = imm_cnt*FD_TXN_ACCT_ADDR_SZ;
     334           0 :   if( FD_UNLIKELY( out+addr_tbl_sz>end ) ) return 0;
     335           0 :   for( ulong i=0UL; i<imm_cnt; i++ ) {
     336           0 :     fd_txn_b_acct_t * acct = ACCT( i );
     337           0 :     fd_memcpy( out, &acct->key, FD_TXN_ACCT_ADDR_SZ );
     338           0 :     out += FD_TXN_ACCT_ADDR_SZ;
     339           0 :   }
     340             : 
     341           0 :   if( FD_UNLIKELY( out+FD_TXN_ACCT_ADDR_SZ>end ) ) return 0;
     342           0 :   fd_memcpy( out, &builder->recent_blockhash, FD_TXN_ACCT_ADDR_SZ );
     343           0 :   out += FD_TXN_ACCT_ADDR_SZ;
     344             : 
     345           0 :   if( FD_UNLIKELY( out>=end ) ) return 0;
     346           0 :   ulong const instr_cnt = builder->instr_cnt;
     347           0 :   out = fd_txn_b_cu16_write( out, end, instr_cnt );
     348           0 :   if( FD_UNLIKELY( !out ) ) return 0;
     349             : 
     350           0 :   for( ulong j=0UL; j<instr_cnt; j++ ) {
     351           0 :     fd_txn_b_instr_t * instr = &builder->instr[ j ];
     352           0 :     ulong const instr_acct_cnt = instr->instr_acct_cnt;
     353             : 
     354           0 :     if( FD_UNLIKELY( out+1>end ) ) return 0;
     355           0 :     out[0] = builder->acct_rev[ instr->program_id ];
     356           0 :     out++;
     357             : 
     358           0 :     out = fd_txn_b_cu16_write( out, end, instr_acct_cnt );
     359           0 :     if( FD_UNLIKELY( !out ) ) return 0;
     360             : 
     361           0 :     if( FD_UNLIKELY( out+instr_acct_cnt>end ) ) return 0;
     362           0 :     for( ulong k=0UL; k<instr_acct_cnt; k++ ) {
     363           0 :       ulong const acct_idx = builder->acct_rev[ builder->instr_acct[ instr->instr_acct0 + k ] ];
     364           0 :       out[0] = (uchar)acct_idx;
     365           0 :       out++;
     366           0 :     }
     367             : 
     368           0 :     ulong const data_sz = instr->data_sz;
     369           0 :     out = fd_txn_b_cu16_write( out, end, data_sz );
     370           0 :     if( FD_UNLIKELY( !out ) ) return 0;
     371             : 
     372           0 :     if( FD_UNLIKELY( out+data_sz>end ) ) return 0;
     373           0 :     fd_memcpy( out, &builder->data_bump[ instr->data_off ], data_sz );
     374           0 :     out += data_sz;
     375           0 :   }
     376             : 
     377           0 :   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           0 : #undef ACCT
     406           0 :   return (uint)( out - out_ );
     407           0 : }
     408             : 
     409             : uint
     410             : fd_txn_build_raw( fd_txn_builder_t * builder,
     411           0 :                   uchar              out[ FD_TXN_MTU ] ) {
     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 ],
     418             :               fd_txn_t * restrict out_txn,
     419           0 :               ushort *            opt_out_txn_t_sz ) {
     420           0 :   uint payload_sz = fd_txn_build_core( builder, out );
     421           0 :   if( FD_UNLIKELY( !payload_sz ) ) return 0U;
     422             : 
     423           0 :   ulong txn_t_sz = fd_txn_parse( out, payload_sz, out_txn, NULL );
     424           0 :   if( FD_UNLIKELY( !txn_t_sz ) ) return 0U;
     425           0 :   if( opt_out_txn_t_sz ) *opt_out_txn_t_sz = (ushort)txn_t_sz;
     426           0 :   return payload_sz;
     427           0 : }

Generated by: LCOV version 1.14