LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_acc_mgr.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 58 242 24.0 %
Date: 2025-03-20 12:08:36 Functions: 5 14 35.7 %

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

Generated by: LCOV version 1.14