LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_acc_mgr.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 79 271 29.2 %
Date: 2025-01-08 12:08:44 Functions: 6 16 37.5 %

          Line data    Source code
       1             : #include "fd_acc_mgr.h"
       2             : #include "../../ballet/base58/fd_base58.h"
       3             : #include "context/fd_exec_epoch_ctx.h"
       4             : #include "context/fd_exec_slot_ctx.h"
       5             : #include "fd_rent_lists.h"
       6             : #include "fd_rocksdb.h"
       7             : #include "sysvar/fd_sysvar_rent.h"
       8             : #include "fd_system_ids.h"
       9             : #include <assert.h>
      10             : 
      11             : fd_acc_mgr_t *
      12             : fd_acc_mgr_new( void *      mem,
      13      407862 :                 fd_funk_t * funk ) {
      14             : 
      15      407862 :   if( FD_UNLIKELY( !mem ) ) {
      16           0 :     FD_LOG_WARNING(( "NULL mem" ));
      17           0 :     return NULL;
      18           0 :   }
      19             : 
      20      407862 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_ACC_MGR_ALIGN ) ) ) {
      21           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      22           0 :     return NULL;
      23           0 :   }
      24             : 
      25      407862 :   fd_memset( mem, 0, FD_ACC_MGR_FOOTPRINT );
      26             : 
      27      407862 :   fd_acc_mgr_t * acc_mgr = fd_type_pun( mem );
      28      407862 :   acc_mgr->funk = funk;
      29      407862 :   return acc_mgr;
      30             : 
      31      407862 : }
      32             : 
      33             : void *
      34      407862 : fd_acc_mgr_delete( fd_acc_mgr_t * acc_mgr ) {
      35             : 
      36      407862 :   if( FD_UNLIKELY( !acc_mgr ) ) return NULL;
      37             : 
      38      407862 :   memset( acc_mgr, 0, FD_ACC_MGR_FOOTPRINT );
      39      407862 :   return acc_mgr;
      40      407862 : }
      41             : 
      42             : static ulong
      43             : fd_rent_lists_key_to_bucket( fd_acc_mgr_t * acc_mgr,
      44           0 :                              fd_funk_rec_t const * rec ) {
      45           0 :   fd_pubkey_t const * key = fd_type_pun_const( &rec->pair.key[0].uc );
      46           0 :   ulong prefixX_be = key->ul[0];
      47           0 :   ulong prefixX    = fd_ulong_bswap( prefixX_be );
      48           0 :   return fd_rent_key_to_partition( prefixX, acc_mgr->part_width, acc_mgr->slots_per_epoch );
      49           0 : }
      50             : 
      51             : static uint
      52             : fd_rent_lists_cb( fd_funk_rec_t * rec,
      53             :                   uint            part_cnt,
      54           0 :                   void *          cb_arg ) {
      55           0 :   (void)part_cnt;
      56             : 
      57           0 :   fd_exec_slot_ctx_t * slot_ctx = (fd_exec_slot_ctx_t *)cb_arg;
      58           0 :   fd_acc_mgr_t *       acc_mgr  = slot_ctx->acc_mgr;
      59             : 
      60           0 :   if( fd_funk_key_is_acc( rec->pair.key ) ) {
      61           0 :     if( acc_mgr->skip_rent_rewrites ) {
      62           0 :       void const * data = fd_funk_val( rec, fd_funk_wksp(acc_mgr->funk) );
      63           0 :       fd_account_meta_t const * metadata = fd_type_pun_const( data );
      64             : 
      65           0 :       fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
      66           0 :       ulong required_balance = fd_rent_exempt_minimum_balance( &epoch_bank->rent, metadata->dlen );
      67           0 :       if( required_balance <= metadata->info.lamports )
      68           0 :         return FD_FUNK_PART_NULL;
      69           0 :     }
      70             : 
      71           0 :     return (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec );
      72           0 :   }
      73             : 
      74           0 :   return FD_FUNK_PART_NULL;
      75           0 : }
      76             : 
      77             : void
      78             : fd_acc_mgr_set_slots_per_epoch( fd_exec_slot_ctx_t * slot_ctx,
      79           0 :                                 ulong                slots_per_epoch ) {
      80           0 :   fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
      81             : 
      82             :   /* Handle feature activation of 'skip_rent_rewrites' or change of
      83             :      slots_per_epoch. */
      84             : 
      85           0 :   int skip_rent_rewrites = FD_FEATURE_ACTIVE( slot_ctx, skip_rent_rewrites );
      86             : 
      87           0 :   if( ( slots_per_epoch    == acc_mgr->slots_per_epoch    ) &
      88           0 :       ( skip_rent_rewrites == acc_mgr->skip_rent_rewrites ) )
      89           0 :     return;
      90             : 
      91           0 :   acc_mgr->slots_per_epoch    = slots_per_epoch;
      92           0 :   acc_mgr->skip_rent_rewrites = !!skip_rent_rewrites;
      93           0 :   acc_mgr->part_width         = fd_rent_partition_width( slots_per_epoch );
      94             : 
      95           0 :   fd_funk_repartition( acc_mgr->funk, (uint)slots_per_epoch, fd_rent_lists_cb, slot_ctx );
      96           0 : }
      97             : 
      98             : fd_account_meta_t const *
      99             : fd_acc_mgr_view_raw( fd_acc_mgr_t *         acc_mgr,
     100             :                      fd_funk_txn_t const *  txn,
     101             :                      fd_pubkey_t const *    pubkey,
     102             :                      fd_funk_rec_t const ** orec,
     103             :                      int *                  opt_err,
     104     5399877 :                      fd_funk_txn_t const ** txn_out  ) {
     105             : 
     106     5399877 :   fd_funk_rec_key_t id   = fd_acc_funk_key( pubkey );
     107     5399877 :   fd_funk_t *       funk = acc_mgr->funk;
     108             : 
     109     5399877 :   fd_funk_rec_t const * rec = fd_funk_rec_query_global( funk, txn, &id, txn_out );
     110             : 
     111     5399877 :   if( FD_UNLIKELY( !rec || !!( rec->flags & FD_FUNK_REC_FLAG_ERASE ) ) )  {
     112     4322757 :     fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
     113     4322757 :     return NULL;
     114     4322757 :   }
     115     1077120 :   if( NULL != orec )
     116     1077105 :     *orec = rec;
     117             : 
     118     1077120 :   void const * raw = fd_funk_val( rec, fd_funk_wksp(funk) );
     119             :   // TODO/FIXME: this check causes issues with some metadata writes
     120             : 
     121     1077120 :   fd_account_meta_t const * metadata = fd_type_pun_const( raw );
     122     1077120 :   if( FD_UNLIKELY( metadata->magic != FD_ACCOUNT_META_MAGIC ) ) {
     123           0 :     fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_WRONG_MAGIC );
     124           0 :     return NULL;
     125           0 :   }
     126             : 
     127     1077120 :   return metadata;
     128     1077120 : }
     129             : 
     130             : int
     131             : fd_acc_mgr_view( fd_acc_mgr_t *          acc_mgr,
     132             :                  fd_funk_txn_t const *   txn,
     133             :                  fd_pubkey_t const *     pubkey,
     134     4792536 :                  fd_borrowed_account_t * account) {
     135             :   /* TODO: re-add this check after consulting on why this builtin program check.
     136             :      Is it the case that the  */
     137             :   // if( fd_pubkey_is_builtin_program( pubkey )
     138             :   //     || memcmp(pubkey->uc, fd_solana_compute_budget_program_id.uc, sizeof(fd_pubkey_t))==0 ) {
     139             :   //   txn = NULL;
     140             :   // }
     141     4792536 :   int err = FD_ACC_MGR_SUCCESS;
     142     4792536 :   fd_account_meta_t const * meta = fd_acc_mgr_view_raw( acc_mgr, txn, pubkey, &account->const_rec, &err, NULL );
     143     4792536 :   if( FD_UNLIKELY( !fd_acc_exists( meta ) ) ) {
     144     3733179 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     145     3715446 :       return err;
     146     3715446 :     }
     147       17733 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     148     3733179 :   }
     149             : 
     150     1059357 :   if( FD_UNLIKELY( FD_BORROWED_ACCOUNT_MAGIC != account->magic ) ) {
     151           0 :     FD_LOG_ERR(( "bad magic for borrowed account - acc: %s, expected: %016lx, got: %016lx", FD_BASE58_ENC_32_ALLOCA( pubkey->uc ), FD_BORROWED_ACCOUNT_MAGIC, account->magic ));
     152           0 :   }
     153             : 
     154     1059357 :   fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
     155             : 
     156     1059357 :   account->orig_rec  = account->const_rec;
     157     1059357 :   account->orig_meta = account->const_meta = meta;
     158     1059357 :   account->orig_data = account->const_data = (uchar const *)meta + meta->hlen;
     159             : 
     160     1059357 :   if( ULONG_MAX == account->starting_dlen )
     161     1059357 :     account->starting_dlen = meta->dlen;
     162             : 
     163     1059357 :   if( ULONG_MAX == account->starting_lamports )
     164     1059357 :     account->starting_lamports = meta->info.lamports;
     165             : 
     166     1059357 :   return FD_ACC_MGR_SUCCESS;
     167     1059357 : }
     168             : 
     169             : fd_account_meta_t *
     170             : fd_acc_mgr_modify_raw( fd_acc_mgr_t *        acc_mgr,
     171             :                        fd_funk_txn_t *       txn,
     172             :                        fd_pubkey_t const *   pubkey,
     173             :                        int                   do_create,
     174             :                        ulong                 min_data_sz,
     175             :                        fd_funk_rec_t const * opt_con_rec,
     176             :                        fd_funk_rec_t **      opt_out_rec,
     177     1687767 :                        int *                 opt_err ) {
     178             : 
     179     1687767 :   fd_funk_t *       funk = acc_mgr->funk;
     180             : 
     181     1687767 :   fd_funk_rec_key_t id   = fd_acc_funk_key( pubkey );
     182             : 
     183             : //#ifdef VLOG
     184             : //  ulong rec_cnt = 0;
     185             : //  for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     186             : //       NULL != rec;
     187             : //       rec = fd_funk_txn_next_rec( funk, rec ) ) {
     188             : //
     189             : //    if( !fd_funk_key_is_acc( rec->pair.key  ) ) continue;
     190             : //
     191             : //    FD_LOG_DEBUG(( "fd_acc_mgr_modify_raw: %s create: %s  rec_cnt: %d", FD_BASE58_ENC_32_ALLOCA( rec->pair.key->uc ), do_create ? "true" : "false", rec_cnt));
     192             : //
     193             : //    rec_cnt++;
     194             : //  }
     195             : //
     196             : //  FD_LOG_DEBUG(( "fd_acc_mgr_modify_raw: %s create: %s", FD_BASE58_ENC_32_ALLOCA( pubkey->uc ), do_create ? "true" : "false"));
     197             : //#endif
     198             : 
     199     1687767 :   int funk_err = FD_FUNK_SUCCESS;
     200     1687767 :   fd_funk_rec_t * rec = fd_funk_rec_write_prepare( funk, txn, &id, sizeof(fd_account_meta_t)+min_data_sz, do_create, opt_con_rec, &funk_err );
     201             : 
     202     1687767 :   if( FD_UNLIKELY( !rec ) )  {
     203           0 :     if( FD_LIKELY( funk_err==FD_FUNK_ERR_KEY ) ) {
     204           0 :       fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
     205           0 :       return NULL;
     206           0 :     }
     207             :     /* Irrecoverable funky internal error [[noreturn]] */
     208           0 :     FD_LOG_ERR(( "fd_funk_rec_write_prepare(%s) failed (%i-%s)", FD_BASE58_ENC_32_ALLOCA( pubkey->key ), funk_err, fd_funk_strerror( funk_err ) ));
     209           0 :   }
     210             : 
     211     1687767 :   if (NULL != opt_out_rec)
     212     1687767 :     *opt_out_rec = rec;
     213             : 
     214             :   // At this point, we don't know if the record WILL be rent exempt so
     215             :   // it is safer to just stick it into the partition and look at it later.
     216     1687767 :   if ( acc_mgr->slots_per_epoch != 0 )
     217           0 :     fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     218             : 
     219     1687767 :   fd_account_meta_t * ret = fd_funk_val( rec, fd_funk_wksp( funk ) );
     220             : 
     221     1687767 :   if( do_create && ret->magic==0UL ) {
     222      803628 :     fd_account_meta_init( ret );
     223      803628 :   }
     224             : 
     225     1687767 :   if( ret->magic != FD_ACCOUNT_META_MAGIC ) {
     226           0 :     fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_WRONG_MAGIC );
     227           0 :     return NULL;
     228           0 :   }
     229             : 
     230     1687767 :   return ret;
     231     1687767 : }
     232             : 
     233             : int
     234             : fd_acc_mgr_modify( fd_acc_mgr_t *          acc_mgr,
     235             :                    fd_funk_txn_t *         txn,
     236             :                    fd_pubkey_t const *     pubkey,
     237             :                    int                     do_create,
     238             :                    ulong                   min_data_sz,
     239     1687761 :                    fd_borrowed_account_t * account ) {
     240     1687761 :   int err = FD_ACC_MGR_SUCCESS;
     241             : 
     242     1687761 :   fd_account_meta_t * meta = fd_acc_mgr_modify_raw( acc_mgr, txn, pubkey, do_create, min_data_sz, account->const_rec, &account->rec, &err );
     243     1687761 :   if( FD_UNLIKELY( !meta ) ) return err;
     244             : 
     245     1687761 :   assert( account->magic == FD_BORROWED_ACCOUNT_MAGIC );
     246             : 
     247           0 :   fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
     248             : 
     249     1687761 :   if( FD_UNLIKELY( meta->magic != FD_ACCOUNT_META_MAGIC ) )
     250           0 :     return FD_ACC_MGR_ERR_WRONG_MAGIC;
     251             : 
     252             : #ifdef VLOG
     253             :   FD_LOG_DEBUG(( "fd_acc_mgr_modify: %s create: %s  lamports: %ld  owner: %s  executable: %s,  rent_epoch: %ld, data_len: %ld",
     254             :                  FD_BASE58_ENC_32_ALLOCA( pubkey->uc ),
     255             :                  do_create ? "true" : "false",
     256             :                  meta->info.lamports,
     257             :                  FD_BASE58_ENC_32_ALLOCA( meta->info.owner ),
     258             :                  meta->info.executable ? "true" : "false",
     259             :                  meta->info.rent_epoch, meta->dlen ));
     260             : #endif
     261             : 
     262     1687761 :   account->orig_rec  = account->const_rec  = account->rec;
     263     1687761 :   account->orig_meta = account->const_meta = account->meta = meta;
     264     1687761 :   account->orig_data = account->const_data = account->data = (uchar *)meta + meta->hlen;
     265             : 
     266     1687761 :   if( ULONG_MAX == account->starting_dlen )
     267     1687761 :     account->starting_dlen = meta->dlen;
     268             : 
     269     1687761 :   if( ULONG_MAX == account->starting_lamports )
     270     1687761 :     account->starting_lamports = meta->info.lamports;
     271             : 
     272     1687761 :   return FD_ACC_MGR_SUCCESS;
     273     1687761 : }
     274             : 
     275             : FD_FN_CONST char const *
     276           0 : fd_acc_mgr_strerror( int err ) {
     277           0 :   switch( err ) {
     278           0 :   case FD_ACC_MGR_SUCCESS:
     279           0 :     return "success";
     280           0 :   case FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT:
     281           0 :     return "unknown account";
     282           0 :   case FD_ACC_MGR_ERR_WRITE_FAILED:
     283           0 :     return "write failed";
     284           0 :   case FD_ACC_MGR_ERR_READ_FAILED:
     285           0 :     return "read failed";
     286           0 :   case FD_ACC_MGR_ERR_WRONG_MAGIC:
     287           0 :     return "wrong magic";
     288           0 :   default:
     289           0 :     return "unknown";
     290           0 :   }
     291           0 : }
     292             : 
     293             : int
     294             : fd_acc_mgr_save( fd_acc_mgr_t *          acc_mgr,
     295           0 :                  fd_borrowed_account_t * account ) {
     296           0 :   if( account->meta == NULL || account->rec == NULL ) {
     297             :     // The meta is NULL so the account is not writable.
     298           0 :     FD_LOG_DEBUG(( "fd_acc_mgr_save: account is not writable: %s", FD_BASE58_ENC_32_ALLOCA( account->pubkey ) ));
     299           0 :     return FD_ACC_MGR_SUCCESS;
     300           0 :   }
     301             : 
     302           0 :   fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
     303           0 :   ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     304           0 :   uchar * raw = fd_funk_val( account->rec, wksp );
     305           0 :   fd_memcpy( raw, account->meta, reclen );
     306             : 
     307           0 :   return FD_ACC_MGR_SUCCESS;
     308           0 : }
     309             : 
     310             : int
     311             : fd_acc_mgr_save_non_tpool( fd_acc_mgr_t *          acc_mgr,
     312             :                            fd_funk_txn_t *         txn,
     313           0 :                            fd_borrowed_account_t * account ) {
     314           0 :   fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
     315           0 :   fd_funk_t * funk = acc_mgr->funk;
     316           0 :   fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
     317           0 :   if( rec == NULL ) {
     318           0 :     int err;
     319           0 :     fd_funk_start_write( acc_mgr->funk );
     320           0 :     rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
     321           0 :     fd_funk_end_write( acc_mgr->funk );
     322           0 :     if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
     323           0 :   }
     324           0 :   account->rec = rec;
     325           0 :   if ( acc_mgr->slots_per_epoch != 0 )
     326           0 :     fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     327           0 :   ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     328           0 :   fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
     329           0 :   int err;
     330           0 :   if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
     331           0 :     FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
     332           0 :   }
     333           0 :   return fd_acc_mgr_save( acc_mgr, account );
     334           0 : }
     335             : 
     336             : void
     337           0 : fd_acc_mgr_lock( fd_acc_mgr_t * acc_mgr ) {
     338           0 :   FD_TEST( !acc_mgr->is_locked );
     339           0 :   acc_mgr->is_locked = 1;
     340           0 : }
     341             : 
     342             : void
     343           0 : fd_acc_mgr_unlock( fd_acc_mgr_t * acc_mgr ) {
     344           0 :   FD_TEST( acc_mgr->is_locked );
     345           0 :   acc_mgr->is_locked = 0;
     346           0 : }
     347             : 
     348             : struct fd_acc_mgr_save_task_args {
     349             :   fd_acc_mgr_t * acc_mgr;
     350             : };
     351             : typedef struct fd_acc_mgr_save_task_args fd_acc_mgr_save_task_args_t;
     352             : 
     353             : struct fd_acc_mgr_save_task_info {
     354             :   fd_borrowed_account_t * * accounts;
     355             :   ulong accounts_cnt;
     356             :   int result;
     357             : };
     358             : typedef struct fd_acc_mgr_save_task_info fd_acc_mgr_save_task_info_t;
     359             : 
     360             : static void
     361             : fd_acc_mgr_save_task( void *tpool,
     362             :                       ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
     363             :                       void *args FD_PARAM_UNUSED,
     364             :                       void *reduce FD_PARAM_UNUSED, ulong stride FD_PARAM_UNUSED,
     365             :                       ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
     366             :                       ulong m0, ulong m1 FD_PARAM_UNUSED,
     367           0 :                       ulong n0 FD_PARAM_UNUSED, ulong n1 FD_PARAM_UNUSED ) {
     368           0 :   fd_acc_mgr_save_task_args_t * task_args = (fd_acc_mgr_save_task_args_t *)args;
     369           0 :   fd_acc_mgr_save_task_info_t * task_info = (fd_acc_mgr_save_task_info_t *)tpool + m0;
     370             : 
     371           0 :   for( ulong i = 0; i < task_info->accounts_cnt; i++ ) {
     372           0 :     int err = fd_acc_mgr_save(task_args->acc_mgr,task_info->accounts[i] );
     373           0 :     if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) {
     374           0 :       task_info->result = err;
     375           0 :       return;
     376           0 :     }
     377           0 :   }
     378           0 :   task_info->result = FD_ACC_MGR_SUCCESS;
     379           0 : }
     380             : 
     381             : int
     382             : fd_acc_mgr_save_many_tpool( fd_acc_mgr_t *          acc_mgr,
     383             :                             fd_funk_txn_t *         txn,
     384             :                             fd_borrowed_account_t * * accounts,
     385             :                             ulong accounts_cnt,
     386           0 :                             fd_tpool_t * tpool ) {
     387           0 :   FD_SCRATCH_SCOPE_BEGIN {
     388           0 :     fd_funk_t *        funk = acc_mgr->funk;
     389           0 :     fd_wksp_t * wksp = fd_funk_wksp( funk );
     390           0 :     fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
     391             : 
     392           0 :     ulong batch_cnt = fd_ulong_min(
     393           0 :       fd_funk_rec_map_private_list_cnt( fd_funk_rec_map_key_max( rec_map ) ),
     394           0 :       fd_ulong_pow2_up( fd_tpool_worker_cnt( tpool ) )
     395           0 :     );
     396           0 :     ulong batch_mask = (batch_cnt - 1UL);
     397             : 
     398           0 :     ulong * batch_szs = fd_scratch_alloc( 8UL, batch_cnt * sizeof(ulong) );
     399           0 :     fd_memset( batch_szs, 0, batch_cnt * sizeof(ulong) );
     400             : 
     401             :     /* Compute the batch sizes */
     402           0 :     for( ulong i = 0; i < accounts_cnt; i++ ) {
     403           0 :       ulong batch_idx = i & batch_mask;
     404           0 :       batch_szs[batch_idx]++;
     405           0 :     }
     406             : 
     407           0 :     fd_borrowed_account_t * * task_accounts = fd_scratch_alloc( 8UL, accounts_cnt * sizeof(fd_borrowed_account_t *) );
     408           0 :     fd_acc_mgr_save_task_info_t * task_infos = fd_scratch_alloc( 8UL, batch_cnt * sizeof(fd_acc_mgr_save_task_info_t) );
     409           0 :     fd_borrowed_account_t * * task_accounts_cursor = task_accounts;
     410             : 
     411             :     /* Construct the batches */
     412           0 :     for( ulong i = 0; i < batch_cnt; i++ ) {
     413           0 :       ulong batch_sz = batch_szs[i];
     414           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
     415             : 
     416           0 :       task_info->accounts_cnt = 0;
     417           0 :       task_info->accounts = task_accounts_cursor;
     418           0 :       task_info->result = 0;
     419             : 
     420           0 :       task_accounts_cursor += batch_sz;
     421           0 :     }
     422             : 
     423           0 :     fd_funk_start_write( funk );
     424             : 
     425           0 :     for( ulong i = 0; i < accounts_cnt; i++ ) {
     426           0 :       fd_borrowed_account_t * account = accounts[i];
     427             : 
     428           0 :       ulong batch_idx = i & batch_mask;
     429           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[batch_idx];
     430           0 :       task_info->accounts[task_info->accounts_cnt++] = account;
     431           0 :       fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
     432           0 :       fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
     433           0 :       if( rec == NULL ) {
     434           0 :         int err;
     435           0 :         rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
     436           0 :         if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
     437           0 :       }
     438           0 :       account->rec = rec;
     439           0 :       if ( acc_mgr->slots_per_epoch != 0 )
     440           0 :         fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     441             : 
     442             :       /* This check is to prevent a seg fault in the case where an account with
     443             :          null data tries to get saved. This notably happens if firedancer is
     444             :          attemping to execute a bad block. This should NEVER happen in the case
     445             :          of a proper replay. */
     446           0 :       if( FD_UNLIKELY( !account->const_meta ) ) {
     447           0 :         FD_LOG_ERR(( "An account likely does not exist. This block could be invalid." ));
     448           0 :       }
     449             : 
     450           0 :       ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     451           0 :       int err;
     452           0 :       if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
     453           0 :         FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
     454           0 :       }
     455           0 :     }
     456             : 
     457           0 :     fd_acc_mgr_save_task_args_t task_args = {
     458           0 :       .acc_mgr = acc_mgr
     459           0 :     };
     460             : 
     461             :     /* Save accounts in a thread pool */
     462             : 
     463           0 :     fd_tpool_exec_all_rrobin( tpool, 0, fd_tpool_worker_cnt( tpool ), fd_acc_mgr_save_task, task_infos, &task_args, NULL, 1, 0, batch_cnt );
     464             : 
     465           0 :     fd_funk_end_write( funk );
     466             : 
     467             :     /* Check results */
     468           0 :     for( ulong i = 0; i < batch_cnt; i++ ) {
     469           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
     470           0 :       if( task_info->result != FD_ACC_MGR_SUCCESS ) {
     471           0 :         return task_info->result;
     472           0 :       }
     473           0 :     }
     474             : 
     475           0 :     return FD_ACC_MGR_SUCCESS;
     476           0 :   } FD_SCRATCH_SCOPE_END;
     477           0 : }

Generated by: LCOV version 1.14