LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_acc_mgr.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 81 269 30.1 %
Date: 2024-11-13 11:58:15 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      108789 :                 fd_funk_t * funk ) {
      14             : 
      15      108789 :   if( FD_UNLIKELY( !mem ) ) {
      16           0 :     FD_LOG_WARNING(( "NULL mem" ));
      17           0 :     return NULL;
      18           0 :   }
      19             : 
      20      108789 :   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      108789 :   fd_memset( mem, 0, FD_ACC_MGR_FOOTPRINT );
      26             : 
      27      108789 :   fd_acc_mgr_t * acc_mgr = fd_type_pun( mem );
      28      108789 :   acc_mgr->funk = funk;
      29      108789 :   return acc_mgr;
      30             : 
      31      108789 : }
      32             : 
      33             : void *
      34      108789 : fd_acc_mgr_delete( fd_acc_mgr_t * acc_mgr ) {
      35             : 
      36      108789 :   if( FD_UNLIKELY( !acc_mgr ) ) return NULL;
      37             : 
      38      108789 :   memset( acc_mgr, 0, FD_ACC_MGR_FOOTPRINT );
      39      108789 :   return acc_mgr;
      40      108789 : }
      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     3767430 :                      fd_funk_txn_t const ** txn_out  ) {
     105             : 
     106     3767430 :   fd_funk_rec_key_t id   = fd_acc_funk_key( pubkey );
     107     3767430 :   fd_funk_t *       funk = acc_mgr->funk;
     108             : 
     109     3767430 :   fd_funk_rec_t const * rec = fd_funk_rec_query_global( funk, txn, &id, txn_out );
     110             : 
     111     3767430 :   if( FD_UNLIKELY( !rec || !!( rec->flags & FD_FUNK_REC_FLAG_ERASE ) ) )  {
     112     2136666 :     fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
     113     2136666 :     return NULL;
     114     2136666 :   }
     115     1630764 :   if (NULL != orec)
     116     1630728 :     *orec = rec;
     117             : 
     118     1630764 :   void const * raw = fd_funk_val( rec, fd_funk_wksp(funk) );
     119             :   // TODO/FIXME: this check causes issues with some metadata writes
     120             : 
     121     1630764 :   fd_account_meta_t const * metadata = fd_type_pun_const( raw );
     122     1630764 :   if( metadata->magic != FD_ACCOUNT_META_MAGIC )
     123           0 :     return NULL;
     124             : 
     125     1630764 :   return metadata;
     126     1630764 : }
     127             : 
     128             : int
     129             : fd_acc_mgr_view( fd_acc_mgr_t *          acc_mgr,
     130             :                  fd_funk_txn_t const *   txn,
     131             :                  fd_pubkey_t const *     pubkey,
     132     2669112 :                  fd_borrowed_account_t * account) {
     133             :   /* TODO: re-add this check after consulting on why this builtin program check.
     134             :      Is it the case that the  */
     135             :   // if( fd_pubkey_is_builtin_program( pubkey )
     136             :   //     || memcmp(pubkey->uc, fd_solana_compute_budget_program_id.uc, sizeof(fd_pubkey_t))==0 ) {
     137             :   //   txn = NULL;
     138             :   // }
     139     2669112 :   int err = FD_ACC_MGR_SUCCESS;
     140     2669112 :   fd_account_meta_t const * meta = fd_acc_mgr_view_raw( acc_mgr, txn, pubkey, &account->const_rec, &err, NULL );
     141     2669112 :   if( FD_UNLIKELY( !fd_acc_exists( meta ) ) ) {
     142     1062114 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     143     1038399 :       return err;
     144     1038399 :     }
     145       23715 :     return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
     146     1062114 :   }
     147             : 
     148     1606998 :   if( FD_BORROWED_ACCOUNT_MAGIC != account->magic ) {
     149           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 ));
     150           0 :   }
     151             : 
     152     1606998 :   fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
     153             : 
     154     1606998 :   if( FD_UNLIKELY( meta->magic != FD_ACCOUNT_META_MAGIC ) )
     155           0 :     return FD_ACC_MGR_ERR_WRONG_MAGIC;
     156             : 
     157     1606998 :   account->orig_rec  = account->const_rec;
     158     1606998 :   account->orig_meta = account->const_meta = meta;
     159     1606998 :   account->orig_data = account->const_data = (uchar const *)meta + meta->hlen;
     160             : 
     161     1606998 :   if (ULONG_MAX == account->starting_dlen)
     162     1606998 :     account->starting_dlen = meta->dlen;
     163             : 
     164     1606998 :   if (ULONG_MAX == account->starting_lamports)
     165     1606998 :     account->starting_lamports = meta->info.lamports;
     166             : 
     167     1606998 :   return FD_ACC_MGR_SUCCESS;
     168     1606998 : }
     169             : 
     170             : fd_account_meta_t *
     171             : fd_acc_mgr_modify_raw( fd_acc_mgr_t *        acc_mgr,
     172             :                        fd_funk_txn_t *       txn,
     173             :                        fd_pubkey_t const *   pubkey,
     174             :                        int                   do_create,
     175             :                        ulong                 min_data_sz,
     176             :                        fd_funk_rec_t const * opt_con_rec,
     177             :                        fd_funk_rec_t **      opt_out_rec,
     178     2145591 :                        int *                 opt_err ) {
     179             : 
     180     2145591 :   fd_funk_t *       funk = acc_mgr->funk;
     181             : 
     182     2145591 :   fd_funk_rec_key_t id   = fd_acc_funk_key( pubkey );
     183             : 
     184             : //#ifdef VLOG
     185             : //  ulong rec_cnt = 0;
     186             : //  for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     187             : //       NULL != rec;
     188             : //       rec = fd_funk_txn_next_rec( funk, rec ) ) {
     189             : //
     190             : //    if( !fd_funk_key_is_acc( rec->pair.key  ) ) continue;
     191             : //
     192             : //    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));
     193             : //
     194             : //    rec_cnt++;
     195             : //  }
     196             : //
     197             : //  FD_LOG_DEBUG(( "fd_acc_mgr_modify_raw: %s create: %s", FD_BASE58_ENC_32_ALLOCA( pubkey->uc ), do_create ? "true" : "false"));
     198             : //#endif
     199             : 
     200     2145591 :   int funk_err = FD_FUNK_SUCCESS;
     201     2145591 :   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 );
     202             : 
     203     2145591 :   if( FD_UNLIKELY( !rec ) )  {
     204           0 :     if( FD_LIKELY( funk_err==FD_FUNK_ERR_KEY ) ) {
     205           0 :       fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
     206           0 :       return NULL;
     207           0 :     }
     208             :     /* Irrecoverable funky internal error [[noreturn]] */
     209           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 ) ));
     210           0 :   }
     211             : 
     212     2145591 :   if (NULL != opt_out_rec)
     213     2145591 :     *opt_out_rec = rec;
     214             : 
     215             :   // At this point, we don't know if the record WILL be rent exempt so
     216             :   // it is safer to just stick it into the partition and look at it later.
     217     2145591 :   if ( acc_mgr->slots_per_epoch != 0 )
     218           0 :     fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     219             : 
     220     2145591 :   fd_account_meta_t * ret = fd_funk_val( rec, fd_funk_wksp( funk ) );
     221             : 
     222     2145591 :   if( do_create && ret->magic==0UL ) {
     223     1304970 :     fd_account_meta_init( ret );
     224     1304970 :   }
     225             : 
     226     2145591 :   if( ret->magic != FD_ACCOUNT_META_MAGIC )
     227           0 :     FD_LOG_ERR(( "bad magic" ));
     228             : 
     229     2145591 :   return ret;
     230     2145591 : }
     231             : 
     232             : int
     233             : fd_acc_mgr_modify( fd_acc_mgr_t *          acc_mgr,
     234             :                    fd_funk_txn_t *         txn,
     235             :                    fd_pubkey_t const *     pubkey,
     236             :                    int                     do_create,
     237             :                    ulong                   min_data_sz,
     238     2145585 :                    fd_borrowed_account_t * account ) {
     239     2145585 :   int err = FD_ACC_MGR_SUCCESS;
     240             : 
     241     2145585 :   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 );
     242     2145585 :   if( FD_UNLIKELY( !meta ) ) return err;
     243             : 
     244     2145585 :   assert( account->magic == FD_BORROWED_ACCOUNT_MAGIC );
     245             : 
     246     2145585 :   fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
     247             : 
     248     2145585 :   if( FD_UNLIKELY( meta->magic != FD_ACCOUNT_META_MAGIC ) )
     249           0 :     return FD_ACC_MGR_ERR_WRONG_MAGIC;
     250             : 
     251             : #ifdef VLOG
     252             :   FD_LOG_DEBUG(( "fd_acc_mgr_modify: %s create: %s  lamports: %ld  owner: %s  executable: %s,  rent_epoch: %ld, data_len: %ld",
     253             :                  FD_BASE58_ENC_32_ALLOCA( pubkey->uc ),
     254             :                  do_create ? "true" : "false",
     255             :                  meta->info.lamports,
     256             :                  FD_BASE58_ENC_32_ALLOCA( meta->info.owner ),
     257             :                  meta->info.executable ? "true" : "false",
     258             :                  meta->info.rent_epoch, meta->dlen ));
     259             : #endif
     260             : 
     261     2145585 :   account->orig_rec  = account->const_rec  = account->rec;
     262     2145585 :   account->orig_meta = account->const_meta = account->meta = meta;
     263     2145585 :   account->orig_data = account->const_data = account->data = (uchar *)meta + meta->hlen;
     264             : 
     265     2145585 :   if( ULONG_MAX == account->starting_dlen )
     266     2145585 :     account->starting_dlen = meta->dlen;
     267             : 
     268     2145585 :   if( ULONG_MAX == account->starting_lamports )
     269     2145585 :     account->starting_lamports = meta->info.lamports;
     270             : 
     271     2145585 :   return FD_ACC_MGR_SUCCESS;
     272     2145585 : }
     273             : 
     274             : FD_FN_CONST char const *
     275           0 : fd_acc_mgr_strerror( int err ) {
     276           0 :   switch( err ) {
     277           0 :   case FD_ACC_MGR_SUCCESS:
     278           0 :     return "success";
     279           0 :   case FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT:
     280           0 :     return "unknown account";
     281           0 :   case FD_ACC_MGR_ERR_WRITE_FAILED:
     282           0 :     return "write failed";
     283           0 :   case FD_ACC_MGR_ERR_READ_FAILED:
     284           0 :     return "read failed";
     285           0 :   case FD_ACC_MGR_ERR_WRONG_MAGIC:
     286           0 :     return "wrong magic";
     287           0 :   default:
     288           0 :     return "unknown";
     289           0 :   }
     290           0 : }
     291             : 
     292             : int
     293             : fd_acc_mgr_save( fd_acc_mgr_t *          acc_mgr,
     294           0 :                  fd_borrowed_account_t * account ) {
     295           0 :   if( account->meta == NULL || account->rec == NULL ) {
     296             :     // The meta is NULL so the account is not writable.
     297           0 :     FD_LOG_DEBUG(( "fd_acc_mgr_save: account is not writable: %s", FD_BASE58_ENC_32_ALLOCA( account->pubkey ) ));
     298           0 :     return FD_ACC_MGR_SUCCESS;
     299           0 :   }
     300             : 
     301           0 :   fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
     302           0 :   ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     303           0 :   uchar * raw = fd_funk_val( account->rec, wksp );
     304           0 :   fd_memcpy( raw, account->meta, reclen );
     305             : 
     306           0 :   return FD_ACC_MGR_SUCCESS;
     307           0 : }
     308             : 
     309             : int
     310             : fd_acc_mgr_save_non_tpool( fd_acc_mgr_t *          acc_mgr,
     311             :                            fd_funk_txn_t *         txn,
     312           0 :                            fd_borrowed_account_t * account ) {
     313           0 :   fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
     314           0 :   fd_funk_t * funk = acc_mgr->funk;
     315           0 :   fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
     316           0 :   if( rec == NULL ) {
     317           0 :     int err;
     318           0 :     fd_funk_start_write( acc_mgr->funk );
     319           0 :     rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
     320           0 :     fd_funk_end_write( acc_mgr->funk );
     321           0 :     if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
     322           0 :   }
     323           0 :   account->rec = rec;
     324           0 :   if ( acc_mgr->slots_per_epoch != 0 )
     325           0 :     fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     326           0 :   ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     327           0 :   fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
     328           0 :   int err;
     329           0 :   if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
     330           0 :     FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
     331           0 :   }
     332           0 :   return fd_acc_mgr_save( acc_mgr, account );
     333           0 : }
     334             : 
     335             : void
     336           0 : fd_acc_mgr_lock( fd_acc_mgr_t * acc_mgr ) {
     337           0 :   FD_TEST( !acc_mgr->is_locked );
     338           0 :   acc_mgr->is_locked = 1;
     339           0 : }
     340             : 
     341             : void
     342           0 : fd_acc_mgr_unlock( fd_acc_mgr_t * acc_mgr ) {
     343           0 :   FD_TEST( acc_mgr->is_locked );
     344           0 :   acc_mgr->is_locked = 0;
     345           0 : }
     346             : 
     347             : struct fd_acc_mgr_save_task_args {
     348             :   fd_acc_mgr_t * acc_mgr;
     349             : };
     350             : typedef struct fd_acc_mgr_save_task_args fd_acc_mgr_save_task_args_t;
     351             : 
     352             : struct fd_acc_mgr_save_task_info {
     353             :   fd_borrowed_account_t * * accounts;
     354             :   ulong accounts_cnt;
     355             :   int result;
     356             : };
     357             : typedef struct fd_acc_mgr_save_task_info fd_acc_mgr_save_task_info_t;
     358             : 
     359             : static void
     360             : fd_acc_mgr_save_task( void *tpool,
     361             :                       ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
     362             :                       void *args FD_PARAM_UNUSED,
     363             :                       void *reduce FD_PARAM_UNUSED, ulong stride FD_PARAM_UNUSED,
     364             :                       ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
     365             :                       ulong m0, ulong m1 FD_PARAM_UNUSED,
     366           0 :                       ulong n0 FD_PARAM_UNUSED, ulong n1 FD_PARAM_UNUSED ) {
     367           0 :   fd_acc_mgr_save_task_args_t * task_args = (fd_acc_mgr_save_task_args_t *)args;
     368           0 :   fd_acc_mgr_save_task_info_t * task_info = (fd_acc_mgr_save_task_info_t *)tpool + m0;
     369             : 
     370           0 :   for( ulong i = 0; i < task_info->accounts_cnt; i++ ) {
     371           0 :     int err = fd_acc_mgr_save(task_args->acc_mgr,task_info->accounts[i] );
     372           0 :     if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) {
     373           0 :       task_info->result = err;
     374           0 :       return;
     375           0 :     }
     376           0 :   }
     377           0 :   task_info->result = FD_ACC_MGR_SUCCESS;
     378           0 : }
     379             : 
     380             : int
     381             : fd_acc_mgr_save_many_tpool( fd_acc_mgr_t *          acc_mgr,
     382             :                             fd_funk_txn_t *         txn,
     383             :                             fd_borrowed_account_t * * accounts,
     384             :                             ulong accounts_cnt,
     385           0 :                             fd_tpool_t * tpool ) {
     386           0 :   FD_SCRATCH_SCOPE_BEGIN {
     387           0 :     fd_funk_t *        funk = acc_mgr->funk;
     388           0 :     fd_wksp_t * wksp = fd_funk_wksp( funk );
     389           0 :     fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
     390             : 
     391           0 :     ulong batch_cnt = fd_ulong_min(
     392           0 :       fd_funk_rec_map_private_list_cnt( fd_funk_rec_map_key_max( rec_map ) ),
     393           0 :       fd_ulong_pow2_up( fd_tpool_worker_cnt( tpool ) )
     394           0 :     );
     395           0 :     ulong batch_mask = (batch_cnt - 1UL);
     396             : 
     397           0 :     ulong * batch_szs = fd_scratch_alloc( 8UL, batch_cnt * sizeof(ulong) );
     398           0 :     fd_memset( batch_szs, 0, batch_cnt * sizeof(ulong) );
     399             : 
     400             :     /* Compute the batch sizes */
     401           0 :     for( ulong i = 0; i < accounts_cnt; i++ ) {
     402           0 :       ulong batch_idx = i & batch_mask;
     403           0 :       batch_szs[batch_idx]++;
     404           0 :     }
     405             : 
     406           0 :     fd_borrowed_account_t * * task_accounts = fd_scratch_alloc( 8UL, accounts_cnt * sizeof(fd_borrowed_account_t *) );
     407           0 :     fd_acc_mgr_save_task_info_t * task_infos = fd_scratch_alloc( 8UL, batch_cnt * sizeof(fd_acc_mgr_save_task_info_t) );
     408           0 :     fd_borrowed_account_t * * task_accounts_cursor = task_accounts;
     409             : 
     410             :     /* Construct the batches */
     411           0 :     for( ulong i = 0; i < batch_cnt; i++ ) {
     412           0 :       ulong batch_sz = batch_szs[i];
     413           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
     414             : 
     415           0 :       task_info->accounts_cnt = 0;
     416           0 :       task_info->accounts = task_accounts_cursor;
     417           0 :       task_info->result = 0;
     418             : 
     419           0 :       task_accounts_cursor += batch_sz;
     420           0 :     }
     421             : 
     422           0 :     fd_funk_start_write( funk );
     423             : 
     424           0 :     for( ulong i = 0; i < accounts_cnt; i++ ) {
     425           0 :       fd_borrowed_account_t * account = accounts[i];
     426             : 
     427           0 :       ulong batch_idx = i & batch_mask;
     428           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[batch_idx];
     429           0 :       task_info->accounts[task_info->accounts_cnt++] = account;
     430           0 :       fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
     431           0 :       fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
     432           0 :       if( rec == NULL ) {
     433           0 :         int err;
     434           0 :         rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
     435           0 :         if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
     436           0 :       }
     437           0 :       account->rec = rec;
     438           0 :       if ( acc_mgr->slots_per_epoch != 0 )
     439           0 :         fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
     440             : 
     441             :       /* This check is to prevent a seg fault in the case where an account with
     442             :          null data tries to get saved. This notably happens if firedancer is
     443             :          attemping to execute a bad block. This should NEVER happen in the case
     444             :          of a proper replay. */
     445           0 :       if( FD_UNLIKELY( !account->const_meta ) ) {
     446           0 :         FD_LOG_ERR(( "An account likely does not exist. This block could be invalid." ));
     447           0 :       }
     448             : 
     449           0 :       ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
     450           0 :       int err;
     451           0 :       if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
     452           0 :         FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
     453           0 :       }
     454           0 :     }
     455             : 
     456           0 :     fd_acc_mgr_save_task_args_t task_args = {
     457           0 :       .acc_mgr = acc_mgr
     458           0 :     };
     459             : 
     460             :     /* Save accounts in a thread pool */
     461             : 
     462           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 );
     463             : 
     464           0 :     fd_funk_end_write( funk );
     465             : 
     466             :     /* Check results */
     467           0 :     for( ulong i = 0; i < batch_cnt; i++ ) {
     468           0 :       fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
     469           0 :       if( task_info->result != FD_ACC_MGR_SUCCESS ) {
     470           0 :         return task_info->result;
     471           0 :       }
     472           0 :     }
     473             : 
     474           0 :     return FD_ACC_MGR_SUCCESS;
     475           0 :   } FD_SCRATCH_SCOPE_END;
     476           0 : }

Generated by: LCOV version 1.14