LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_hashes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 744 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 19 0.0 %

          Line data    Source code
       1             : #include "fd_hashes.h"
       2             : #include "fd_acc_mgr.h"
       3             : #include "fd_runtime.h"
       4             : #include "fd_account.h"
       5             : #include "context/fd_capture_ctx.h"
       6             : #include "sysvar/fd_sysvar_epoch_schedule.h"
       7             : #include "../capture/fd_solcap_writer.h"
       8             : #include "../../ballet/base58/fd_base58.h"
       9             : #include "../../ballet/blake3/fd_blake3.h"
      10             : #include "../../ballet/lthash/fd_lthash.h"
      11             : #include "../../ballet/sha256/fd_sha256.h"
      12             : 
      13             : #include <assert.h>
      14             : #include <stdio.h>
      15             : 
      16             : #define SORT_NAME sort_pubkey_hash_pair
      17           0 : #define SORT_KEY_T fd_pubkey_hash_pair_t
      18             : static int
      19           0 : fd_pubkey_hash_pair_compare(fd_pubkey_hash_pair_t const * a, fd_pubkey_hash_pair_t const * b) {
      20           0 :   for (uint i = 0; i < sizeof(fd_pubkey_t)/sizeof(ulong); ++i) {
      21             :     /* First byte is least significant when seen as a long. Make it most significant. */
      22           0 :     ulong al = __builtin_bswap64(a->rec->pair.key->ul[i]);
      23           0 :     ulong bl = __builtin_bswap64(b->rec->pair.key->ul[i]);
      24           0 :     if (al != bl) return (al < bl);
      25           0 :   }
      26           0 :   return 0;
      27           0 : }
      28           0 : #define SORT_BEFORE(a,b) fd_pubkey_hash_pair_compare(&a, &b)
      29             : #include "../../util/tmpl/fd_sort.c"
      30             : 
      31           0 : #define FD_ACCOUNT_DELTAS_MERKLE_FANOUT (16UL)
      32           0 : #define FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT (16UL)
      33             : 
      34             : struct fd_pubkey_hash_pair_list {
      35             :   fd_pubkey_hash_pair_t * pairs;
      36             :   ulong pairs_len;
      37             : };
      38             : typedef struct fd_pubkey_hash_pair_list fd_pubkey_hash_pair_list_t;
      39             : 
      40             : static void
      41           0 : fd_hash_account_deltas( fd_pubkey_hash_pair_list_t * lists, ulong lists_len, fd_hash_t * hash, fd_exec_slot_ctx_t * slot_ctx FD_PARAM_UNUSED ) {
      42           0 :   fd_sha256_t shas[FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT];
      43           0 :   uchar       num_hashes[FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT+1];
      44             : 
      45             :   // Init the number of hashes
      46           0 :   fd_memset( num_hashes, 0, sizeof(num_hashes) );
      47             : 
      48             :   // FD_LOG_DEBUG(("sorting %d", pairs_len));
      49             :   // long timer_sort = -fd_log_wallclock();
      50             :   // sort_pubkey_hash_pair_inplace( pairs, pairs_len );
      51             :   // timer_sort += fd_log_wallclock();
      52             :   // FD_LOG_DEBUG(("sorting done %6.3f ms", (double)timer_sort*(1e-6)));
      53             : 
      54             :   // FD_LOG_DEBUG(("fancy bmtree started"));
      55           0 :   for( ulong j = 0; j < FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT; ++j ) {
      56           0 :     fd_sha256_init( &shas[j] );
      57           0 : }
      58             : 
      59           0 :   if( lists_len == 0 ) {
      60           0 :     fd_sha256_fini( &shas[0], hash->hash );
      61           0 :     return;
      62           0 :   }
      63             : 
      64           0 :   fd_pubkey_hash_pair_t * prev_pair = NULL;
      65           0 :   for( ulong k = 0; k < lists_len; ++k ) {
      66           0 :     fd_pubkey_hash_pair_t * pairs = lists[k].pairs;
      67           0 :     ulong pairs_len               = lists[k].pairs_len;
      68           0 :     for( ulong i = 0; i < pairs_len; ++i ) {
      69             : #ifdef VLOG
      70             :       FD_LOG_NOTICE(( "account delta hash X { \"key\":%ld, \"pubkey\":\"%s\", \"hash\":\"%s\" },",
      71             :                       i,
      72             :                       FD_BASE58_ENC_32_ALLOCA( pairs[i].pubkey->key ),
      73             :                       FD_BASE58_ENC_32_ALLOCA( pairs[i].hash->hash ) ));
      74             : #endif
      75             : 
      76           0 :       if( prev_pair ) FD_TEST(fd_pubkey_hash_pair_compare(prev_pair, &pairs[i]) > 0);
      77           0 :       prev_pair = &pairs[i];
      78           0 :       fd_sha256_append( &shas[0], pairs[i].hash->hash, sizeof( fd_hash_t ) );
      79           0 :       num_hashes[0]++;
      80             : 
      81           0 :       for( ulong j = 0; j < FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT; ++j ) {
      82           0 :         if (num_hashes[j] == FD_ACCOUNT_DELTAS_MERKLE_FANOUT) {
      83           0 :           num_hashes[j] = 0;
      84           0 :           num_hashes[j+1]++;
      85           0 :           fd_sha256_fini( &shas[j], hash->hash );
      86           0 :           fd_sha256_init( &shas[j] );
      87           0 :           fd_sha256_append( &shas[j+1], (uchar const *) hash->hash, sizeof( fd_hash_t ) );
      88           0 :         } else {
      89           0 :           break;
      90           0 :         }
      91           0 :       }
      92           0 :     }
      93           0 :   }
      94             : 
      95           0 :   ulong tot_num_hashes = 0;
      96           0 :   for (ulong k = 0; k < FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT; ++k ) {
      97           0 :     tot_num_hashes += num_hashes[k];
      98           0 :   }
      99             : 
     100           0 :   if (tot_num_hashes == 1) {
     101           0 :     return;
     102           0 :   }
     103             : 
     104             :   // TODO: use CZT on pairs_len
     105           0 :   ulong height = 0;
     106           0 :   for( long i = FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT-1; i >= 0; --i ) {
     107           0 :     if( num_hashes[i] != 0 ) {
     108           0 :       height = (ulong) i + 1;
     109           0 :       break;
     110           0 :     }
     111           0 :   }
     112             : 
     113             : 
     114           0 :   for( ulong i = 0; i < height; ++i ) {
     115           0 :     if( num_hashes[i]==0 ) {
     116           0 :       continue;
     117           0 :     }
     118             :     // At level i, finalize and append to i + 1
     119             :     //fd_hash_t sub_hash;
     120           0 :     fd_sha256_fini( &shas[i], hash );
     121           0 :     num_hashes[i] = 0;
     122           0 :     num_hashes[i+1]++;
     123             : 
     124           0 :     ulong tot_num_hashes = 0;
     125           0 :     for (ulong k = 0; k < FD_ACCOUNT_DELTAS_MAX_MERKLE_HEIGHT; ++k ) {
     126           0 :       tot_num_hashes += num_hashes[k];
     127           0 :     }
     128           0 :     if (i == (height-1)) {
     129           0 :       assert(tot_num_hashes == 1);
     130           0 :       return;
     131           0 :     }
     132           0 :     fd_sha256_append( &shas[i+1], (uchar const *) hash->hash, sizeof( fd_hash_t ) );
     133             : 
     134             :     // There is now one more hash at level i+1
     135             : 
     136             :     // check, have we filled this level and ones above it.
     137           0 :     for( ulong j = i+1; j < height; ++j ) {
     138             :       // if the level is full, finalize and push into next level.
     139           0 :       if (num_hashes[j] == FD_ACCOUNT_DELTAS_MERKLE_FANOUT) {
     140           0 :         num_hashes[j] = 0;
     141           0 :         num_hashes[j+1]++;
     142           0 :         fd_hash_t sub_hash;
     143           0 :         fd_sha256_fini( &shas[j], &sub_hash );
     144           0 :         if (j != height - 1) {
     145           0 :           fd_sha256_append( &shas[j+1], (uchar const *) sub_hash.hash, sizeof( fd_hash_t ) );
     146           0 :         } else {
     147           0 :           memcpy(hash->hash, sub_hash.hash, sizeof(fd_hash_t));
     148           0 :           return;
     149           0 :         }
     150           0 :       }
     151           0 :     }
     152           0 :   }
     153             : 
     154             :   // If the level at the `height' was rolled into, do something about it
     155           0 : }
     156             : 
     157             : 
     158             : void
     159           0 : fd_calculate_epoch_accounts_hash_values(fd_exec_slot_ctx_t * slot_ctx) {
     160             : 
     161           0 :   ulong slot_idx = 0;
     162           0 :   fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     163           0 :   ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_ctx->slot_bank.slot, &slot_idx );
     164             : 
     165           0 :   ulong slots_per_epoch = fd_epoch_slot_cnt( &epoch_bank->epoch_schedule, epoch );
     166           0 :   ulong first_slot_in_epoch           = fd_epoch_slot0   ( &epoch_bank->epoch_schedule, epoch );
     167             : 
     168           0 :   ulong calculation_offset_start = slots_per_epoch / 4;
     169           0 :   ulong calculation_offset_stop = slots_per_epoch / 4 * 3;
     170           0 :   ulong calculation_interval = fd_ulong_sat_sub(calculation_offset_stop, calculation_offset_start);
     171             : 
     172             :   // This came from the vote program.. maybe we need to put it into a header?
     173           0 :   const ulong MAX_LOCKOUT_HISTORY = 31UL;
     174           0 :   const ulong CALCULATION_INTERVAL_BUFFER = 150UL;
     175           0 :   const ulong MINIMUM_CALCULATION_INTERVAL = MAX_LOCKOUT_HISTORY + CALCULATION_INTERVAL_BUFFER;
     176             : 
     177           0 :   if (calculation_interval < MINIMUM_CALCULATION_INTERVAL) {
     178           0 :     epoch_bank->eah_start_slot = ULONG_MAX;
     179           0 :     epoch_bank->eah_stop_slot = ULONG_MAX;
     180           0 :     epoch_bank->eah_interval = ULONG_MAX;
     181           0 :     return;
     182           0 :   }
     183             : 
     184           0 :   epoch_bank->eah_start_slot = first_slot_in_epoch + calculation_offset_start;
     185           0 :   if (slot_ctx->slot_bank.slot > epoch_bank->eah_start_slot)
     186           0 :     epoch_bank->eah_start_slot = ULONG_MAX;
     187           0 :   epoch_bank->eah_stop_slot = first_slot_in_epoch + calculation_offset_stop;
     188           0 :   if (slot_ctx->slot_bank.slot > epoch_bank->eah_stop_slot)
     189           0 :     epoch_bank->eah_stop_slot = ULONG_MAX;
     190           0 :   epoch_bank->eah_interval = calculation_interval;
     191           0 : }
     192             : 
     193             : // https://github.com/solana-labs/solana/blob/b0dcaf29e358c37a0fcb8f1285ce5fff43c8ec55/runtime/src/bank/epoch_accounts_hash_utils.rs#L13
     194             : static int
     195           0 : fd_should_include_epoch_accounts_hash(fd_exec_slot_ctx_t * slot_ctx) {
     196             : 
     197           0 :   fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     198           0 :   ulong calculation_stop = epoch_bank->eah_stop_slot;
     199           0 :   return slot_ctx->slot_bank.prev_slot < calculation_stop && (slot_ctx->slot_bank.slot >= calculation_stop);
     200           0 : }
     201             : 
     202             : static int
     203           0 : fd_should_snapshot_include_epoch_accounts_hash(fd_exec_slot_ctx_t * slot_ctx) {
     204             : 
     205           0 :   fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     206             : 
     207             :   // We need to find the correct logic
     208           0 :   if (epoch_bank->eah_start_slot != ULONG_MAX)
     209           0 :     return 0;
     210           0 :   if (epoch_bank->eah_stop_slot == ULONG_MAX)
     211           0 :     return 0;
     212           0 :   return 1;
     213           0 : }
     214             : 
     215             : // slot_ctx should be const.
     216             : static void
     217             : fd_hash_bank( fd_exec_slot_ctx_t * slot_ctx,
     218             :               fd_capture_ctx_t * capture_ctx,
     219             :               fd_hash_t * hash,
     220             :               fd_pubkey_hash_pair_t * dirty_keys,
     221           0 :               ulong dirty_key_cnt ) {
     222           0 :   slot_ctx->prev_banks_hash = slot_ctx->slot_bank.banks_hash;
     223           0 :   slot_ctx->parent_signature_cnt = slot_ctx->signature_cnt;
     224           0 :   slot_ctx->prev_lamports_per_signature = slot_ctx->slot_bank.lamports_per_signature;
     225           0 :   slot_ctx->parent_transaction_count = slot_ctx->slot_bank.transaction_count;
     226             : 
     227           0 :   sort_pubkey_hash_pair_inplace( dirty_keys, dirty_key_cnt );
     228           0 :   fd_pubkey_hash_pair_list_t list1 = { .pairs = dirty_keys, .pairs_len = dirty_key_cnt };
     229           0 :   fd_hash_account_deltas(&list1, 1, &slot_ctx->account_delta_hash, slot_ctx );
     230             : 
     231           0 :   fd_sha256_t sha;
     232           0 :   fd_sha256_init( &sha );
     233           0 :   fd_sha256_append( &sha, (uchar const *) &slot_ctx->slot_bank.banks_hash, sizeof( fd_hash_t ) );
     234           0 :   fd_sha256_append( &sha, (uchar const *) &slot_ctx->account_delta_hash, sizeof( fd_hash_t  ) );
     235           0 :   fd_sha256_append( &sha, (uchar const *) &slot_ctx->signature_cnt, sizeof( ulong ) );
     236           0 :   fd_sha256_append( &sha, (uchar const *) &slot_ctx->slot_bank.poh, sizeof( fd_hash_t ) );
     237             : 
     238           0 :   fd_sha256_fini( &sha, hash->hash );
     239             : 
     240           0 :   if (fd_should_include_epoch_accounts_hash(slot_ctx)) {
     241           0 :     fd_sha256_init( &sha );
     242           0 :     fd_sha256_append( &sha, (uchar const *) &hash->hash, sizeof( fd_hash_t ) );
     243             : 
     244           0 :     fd_sha256_append( &sha, (uchar const *) &slot_ctx->slot_bank.epoch_account_hash.hash, sizeof( fd_hash_t ) );
     245             : 
     246           0 :     fd_sha256_fini( &sha, hash->hash );
     247           0 :   }
     248             : 
     249           0 :   if( capture_ctx != NULL && capture_ctx->capture != NULL ) {
     250           0 :     fd_solcap_write_bank_preimage(
     251           0 :         capture_ctx->capture,
     252           0 :         hash->hash,
     253           0 :         slot_ctx->prev_banks_hash.hash,
     254           0 :         slot_ctx->account_delta_hash.hash,
     255           0 :         &slot_ctx->slot_bank.poh.hash,
     256           0 :         slot_ctx->signature_cnt );
     257           0 :   }
     258             : 
     259           0 :   FD_LOG_NOTICE(( "\n\n[Replay]\n"
     260           0 :                   "slot:             %lu\n"
     261           0 :                   "bank hash:        %s\n"
     262           0 :                   "parent bank hash: %s\n"
     263           0 :                   "accounts_delta:   %s\n"
     264           0 :                   "lthash:           %s\n"
     265           0 :                   "signature_count:  %lu\n"
     266           0 :                   "last_blockhash:   %s\n",
     267           0 :                   slot_ctx->slot_bank.slot,
     268           0 :                   FD_BASE58_ENC_32_ALLOCA( hash->hash ),
     269           0 :                   FD_BASE58_ENC_32_ALLOCA( slot_ctx->prev_banks_hash.hash ),
     270           0 :                   FD_BASE58_ENC_32_ALLOCA( slot_ctx->account_delta_hash.hash ),
     271           0 :                   FD_LTHASH_ENC_32_ALLOCA( (fd_lthash_value_t *) slot_ctx->slot_bank.lthash.lthash ),
     272           0 :                   slot_ctx->signature_cnt,
     273           0 :                   FD_BASE58_ENC_32_ALLOCA( slot_ctx->slot_bank.poh.hash ) ));
     274           0 : }
     275             : 
     276             : struct fd_accounts_hash_task_info {
     277             :   fd_exec_slot_ctx_t * slot_ctx;
     278             :   fd_pubkey_t acc_pubkey[1];
     279             :   fd_hash_t acc_hash[1];
     280             :   fd_funk_rec_t const * rec;
     281             :   uint should_erase;
     282             :   uint hash_changed;
     283             : };
     284             : typedef struct fd_accounts_hash_task_info fd_accounts_hash_task_info_t;
     285             : 
     286             : struct fd_accounts_hash_task_data {
     287             :   struct fd_accounts_hash_task_info *info;
     288             :   ulong                              info_sz;
     289             :   fd_lthash_value_t                 *lthash_values;
     290             : };
     291             : typedef struct fd_accounts_hash_task_data fd_accounts_hash_task_data_t;
     292             : 
     293             : static void
     294             : fd_account_hash_task( void *tpool,
     295             :                       ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
     296             :                       void *args FD_PARAM_UNUSED,
     297             :                       void *reduce FD_PARAM_UNUSED, ulong stride FD_PARAM_UNUSED,
     298             :                       ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
     299             :                       ulong m0, ulong m1 FD_PARAM_UNUSED,
     300           0 :                       ulong n0 FD_PARAM_UNUSED, ulong n1 FD_PARAM_UNUSED) {
     301           0 :   fd_accounts_hash_task_info_t * task_info = ((fd_accounts_hash_task_data_t *)tpool)->info + m0;
     302           0 :   fd_exec_slot_ctx_t * slot_ctx = task_info->slot_ctx;
     303           0 :   int err = 0;
     304           0 :   fd_funk_txn_t const * txn_out = NULL;
     305           0 :   fd_account_meta_t const * acc_meta = fd_acc_mgr_view_raw( slot_ctx->acc_mgr, slot_ctx->funk_txn, task_info->acc_pubkey, &task_info->rec, &err, &txn_out );
     306           0 :   if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     307           0 :     FD_LOG_WARNING(( "failed to view account during bank hash" ));
     308           0 :     return;
     309           0 :   }
     310             : 
     311           0 :   fd_account_meta_t * acc_meta_parent = NULL;
     312           0 :   if( NULL != txn_out ) {
     313           0 :     fd_funk_t *     funk = slot_ctx->acc_mgr->funk;
     314           0 :     fd_wksp_t *     wksp = fd_funk_wksp( funk );
     315           0 :     fd_funk_txn_t * txn_map  = fd_funk_txn_map( funk, wksp );
     316           0 :     txn_out = fd_funk_txn_parent( (fd_funk_txn_t *) txn_out, txn_map );
     317           0 :     acc_meta_parent = (fd_account_meta_t *)fd_acc_mgr_view_raw( slot_ctx->acc_mgr, txn_out, task_info->acc_pubkey, NULL, &err, NULL);
     318           0 :   }
     319             : 
     320           0 :   fd_lthash_value_t * acc = &(((fd_accounts_hash_task_data_t *)tpool)->lthash_values[n0]);
     321             : 
     322           0 :   if( FD_UNLIKELY(acc_meta->info.lamports == 0) ) {
     323           0 :     fd_memset( task_info->acc_hash->hash, 0, FD_HASH_FOOTPRINT );
     324             : 
     325             :     /* If we erase records instantly, this causes problems with the
     326             :         iterator.  Instead, we will store away the record and erase
     327             :         it later where appropriate.  */
     328           0 :     task_info->should_erase = 1;
     329           0 :     if( memcmp( task_info->acc_hash->hash, acc_meta->hash, sizeof(fd_hash_t) ) != 0 ) {
     330           0 :       task_info->hash_changed = 1;
     331           0 :     }
     332           0 :   } else {
     333           0 :     uchar *             acc_data = fd_account_get_data((fd_account_meta_t *) acc_meta);
     334           0 :     fd_pubkey_t const * acc_key  = fd_type_pun_const( task_info->rec->pair.key[0].uc );
     335           0 :     fd_lthash_value_t new_lthash_value;
     336           0 :     fd_lthash_zero(&new_lthash_value);
     337           0 :     fd_hash_account_current( task_info->acc_hash->hash, &new_lthash_value, acc_meta, acc_key->key, acc_data );
     338             : 
     339           0 :     if( memcmp( task_info->acc_hash->hash, acc_meta->hash, sizeof(fd_hash_t) ) != 0 ) {
     340           0 :       task_info->hash_changed = 1;
     341           0 :       fd_lthash_add( acc, &new_lthash_value);
     342           0 :     }
     343           0 :   }
     344             : 
     345           0 :   if( FD_LIKELY(task_info->hash_changed && ((NULL != acc_meta_parent) && (acc_meta_parent->info.lamports != 0) ) ) ) {
     346           0 :     uchar *             acc_data = fd_account_get_data(acc_meta_parent);
     347           0 :     fd_pubkey_t const * acc_key  = fd_type_pun_const( task_info->rec->pair.key[0].uc );
     348           0 :     fd_lthash_value_t old_lthash_value;
     349           0 :     fd_lthash_zero(&old_lthash_value);
     350           0 :     fd_hash_t old_hash;
     351             : 
     352           0 :     fd_hash_account_current( old_hash.hash, &old_lthash_value, acc_meta_parent, acc_key->key, acc_data );
     353           0 :     fd_lthash_sub( acc, &old_lthash_value );
     354           0 :   }
     355             : 
     356           0 :   if( acc_meta->slot == slot_ctx->slot_bank.slot ) {
     357           0 :       task_info->hash_changed = 1;
     358           0 :   }
     359           0 : }
     360             : 
     361             : void
     362             : fd_collect_modified_accounts( fd_exec_slot_ctx_t * slot_ctx,
     363           0 :                               fd_accounts_hash_task_data_t *task_data ) {
     364           0 :   fd_acc_mgr_t *  acc_mgr = slot_ctx->acc_mgr;
     365           0 :   fd_funk_t *     funk    = acc_mgr->funk;
     366           0 :   fd_funk_txn_t * txn     = slot_ctx->funk_txn;
     367             : 
     368           0 :   ulong rec_cnt = 0;
     369           0 :   for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     370           0 :        NULL != rec;
     371           0 :        rec = fd_funk_txn_next_rec( funk, rec ) ) {
     372             : 
     373           0 :     if( !fd_funk_key_is_acc( rec->pair.key  ) )
     374           0 :       continue;
     375             : 
     376           0 :     fd_pubkey_t const * pubkey  = fd_type_pun_const( rec->pair.key[0].uc );
     377             : 
     378           0 :     if (((pubkey->ul[0] == 0) & (pubkey->ul[1] == 0) & (pubkey->ul[2] == 0) & (pubkey->ul[3] == 0)))
     379           0 :       FD_LOG_WARNING(( "null pubkey (system program?) showed up as modified" ));
     380             : 
     381           0 :     rec_cnt++;
     382           0 :   }
     383             : 
     384           0 :   task_data->info = fd_valloc_malloc( slot_ctx->valloc, 8UL, rec_cnt * sizeof(fd_accounts_hash_task_info_t) );
     385             : 
     386             :   /* Iterate over accounts that have been changed in the current
     387             :      database transaction. */
     388           0 :   ulong task_info_idx = 0;
     389           0 :   for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     390           0 :        NULL != rec;
     391           0 :        rec = fd_funk_txn_next_rec( funk, rec ) ) {
     392             : 
     393           0 :     fd_pubkey_t const * acc_key  = fd_type_pun_const( rec->pair.key[0].uc );
     394             : 
     395           0 :     if( !fd_funk_key_is_acc( rec->pair.key  ) )
     396           0 :       continue;
     397             : 
     398           0 :     fd_accounts_hash_task_info_t * task_info = &task_data->info[task_info_idx++];
     399             : 
     400           0 :     *task_info->acc_pubkey = *acc_key;
     401           0 :     task_info->slot_ctx = slot_ctx;
     402           0 :     task_info->hash_changed = 0;
     403           0 :     task_info->should_erase = 0;
     404           0 :   }
     405             : 
     406           0 :   task_data->info_sz = task_info_idx;
     407           0 : }
     408             : 
     409             : int
     410             : fd_update_hash_bank_tpool( fd_exec_slot_ctx_t * slot_ctx,
     411             :                            fd_capture_ctx_t *   capture_ctx,
     412             :                            fd_hash_t *          hash,
     413             :                            ulong                signature_cnt,
     414           0 :                            fd_tpool_t *         tpool ) {
     415           0 :   fd_acc_mgr_t *  acc_mgr = slot_ctx->acc_mgr;
     416           0 :   fd_funk_t *     funk    = acc_mgr->funk;
     417           0 :   fd_funk_txn_t * txn     = slot_ctx->funk_txn;
     418             : 
     419             :   /* Collect list of changed accounts to be added to bank hash */
     420           0 :   fd_accounts_hash_task_data_t task_data;
     421             : 
     422           0 :   ulong wcnt = fd_tpool_worker_cnt( tpool );
     423           0 :   task_data.lthash_values = fd_valloc_malloc( slot_ctx->valloc, FD_LTHASH_VALUE_ALIGN, wcnt * FD_LTHASH_VALUE_FOOTPRINT );
     424           0 :   for( ulong i = 0; i < wcnt; i++ ) {
     425           0 :     fd_lthash_zero(&task_data.lthash_values[i]);
     426           0 :   }
     427             : 
     428             :   /* Find accounts which might have changed */
     429           0 :   fd_collect_modified_accounts( slot_ctx, &task_data);
     430             : 
     431           0 :   fd_pubkey_hash_pair_t * dirty_keys = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, task_data.info_sz * FD_PUBKEY_HASH_PAIR_FOOTPRINT );
     432           0 :   ulong dirty_key_cnt = 0;
     433             : 
     434             :   /* Find accounts which have changed */
     435           0 :   fd_tpool_exec_all_rrobin( tpool, 0, wcnt, fd_account_hash_task, &task_data, NULL, NULL, 1, 0, task_data.info_sz );
     436             : 
     437             :   // Apply the lthash changes to the bank lthash
     438           0 :   fd_lthash_value_t * acc = (fd_lthash_value_t *)fd_type_pun(slot_ctx->slot_bank.lthash.lthash);
     439           0 :   for( ulong i = 0; i < wcnt; i++ ) {
     440           0 :     fd_lthash_add( acc, &task_data.lthash_values[i] );
     441           0 :   }
     442             : 
     443           0 :   for( ulong i = 0; i < task_data.info_sz; i++ ) {
     444           0 :     fd_accounts_hash_task_info_t * task_info = &task_data.info[i];
     445             :     /* Upgrade to writable record */
     446           0 :     if( !task_info->hash_changed ) {
     447           0 :       continue;
     448           0 :     }
     449             : 
     450           0 :     FD_BORROWED_ACCOUNT_DECL(acc_rec);
     451           0 :     acc_rec->const_rec = task_info->rec;
     452             : 
     453           0 :     fd_pubkey_t const * acc_key = fd_type_pun_const( task_info->rec->pair.key[0].uc );
     454           0 :     int err = fd_acc_mgr_modify( acc_mgr, txn, acc_key, 0, 0UL, acc_rec);
     455           0 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     456           0 :       FD_LOG_ERR(( "failed to modify account during bank hash" ));
     457           0 :     }
     458             : 
     459             :     /* Update hash */
     460             : 
     461           0 :     memcpy( acc_rec->meta->hash, task_info->acc_hash->hash, sizeof(fd_hash_t) );
     462           0 :     acc_rec->meta->slot = slot_ctx->slot_bank.slot;
     463             : 
     464             :     /* Add account to "dirty keys" list, which will be added to the
     465             :        bank hash. */
     466             : 
     467           0 :     fd_pubkey_hash_pair_t * dirty_entry = &dirty_keys[dirty_key_cnt++];
     468           0 :     dirty_entry->rec = task_info->rec;
     469           0 :     dirty_entry->hash = (fd_hash_t const *)acc_rec->meta->hash;
     470             : 
     471           0 :     char acc_key_string[ FD_BASE58_ENCODED_32_SZ ];
     472           0 :     fd_acct_addr_cstr( acc_key_string, (uchar const*)acc_key );
     473           0 :     char owner_string[ FD_BASE58_ENCODED_32_SZ ];
     474           0 :     fd_acct_addr_cstr( owner_string, acc_rec->meta->info.owner );
     475             : 
     476           0 :     FD_LOG_DEBUG(( "fd_acc_mgr_update_hash: %s "
     477           0 :         "slot: %lu "
     478           0 :         "lamports: %lu  "
     479           0 :         "owner: %s "
     480           0 :         "executable: %s,  "
     481           0 :         "rent_epoch: %lu, "
     482           0 :         "data_len: %lu",
     483           0 :         acc_key_string,
     484           0 :         slot_ctx->slot_bank.slot,
     485           0 :         acc_rec->meta->info.lamports,
     486           0 :         owner_string,
     487           0 :         acc_rec->meta->info.executable ? "true" : "false",
     488           0 :         acc_rec->meta->info.rent_epoch,
     489           0 :         acc_rec->meta->dlen ));
     490             : 
     491           0 :     if( capture_ctx != NULL && capture_ctx->capture != NULL ) {
     492           0 :       fd_account_meta_t const * acc_meta = fd_acc_mgr_view_raw( slot_ctx->acc_mgr, slot_ctx->funk_txn, task_info->acc_pubkey, &task_info->rec, &err, NULL);
     493           0 :       if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     494           0 :         FD_LOG_WARNING(( "failed to view account during capture" ));
     495           0 :         continue;
     496           0 :       }
     497             : 
     498           0 :       uchar const *       acc_data = (uchar *)acc_meta + acc_meta->hlen;
     499             : 
     500           0 :       err = fd_solcap_write_account(
     501           0 :         capture_ctx->capture,
     502           0 :         acc_key->uc,
     503           0 :         &acc_rec->meta->info,
     504           0 :         acc_data,
     505           0 :         acc_rec->meta->dlen,
     506           0 :         task_info->acc_hash->hash );
     507           0 :       FD_TEST( err==0 );
     508           0 :     }
     509           0 :   }
     510             : 
     511             :   /* Sort and hash "dirty keys" to the accounts delta hash. */
     512             : 
     513             :   // FD_LOG_DEBUG(("slot %ld, dirty %ld", slot_ctx->slot_bank.slot, dirty_key_cnt));
     514             : 
     515           0 :   slot_ctx->signature_cnt = signature_cnt;
     516           0 :   fd_hash_bank( slot_ctx, capture_ctx, hash, dirty_keys, dirty_key_cnt);
     517             : 
     518           0 :   for( ulong i = 0; i < task_data.info_sz; i++ ) {
     519           0 :     fd_accounts_hash_task_info_t * task_info = &task_data.info[i];
     520             :     /* Upgrade to writable record */
     521           0 :     if( FD_LIKELY( !task_info->should_erase ) ) {
     522           0 :       continue;
     523           0 :     }
     524             : 
     525           0 :     fd_funk_rec_remove(funk, fd_funk_rec_modify(funk, task_info->rec), 1);
     526           0 :   }
     527             : 
     528             :   // Sanity-check LT Hash
     529             :   //    fd_accounts_check_lthash( slot_ctx );
     530             : 
     531           0 :   fd_valloc_free( slot_ctx->valloc, task_data.info );
     532           0 :   fd_valloc_free( slot_ctx->valloc, task_data.lthash_values );
     533           0 :   fd_valloc_free( slot_ctx->valloc, dirty_keys );
     534             : 
     535           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     536           0 : }
     537             : 
     538             : int
     539             : fd_print_account_hashes( fd_exec_slot_ctx_t * slot_ctx,
     540           0 :                          fd_tpool_t *         tpool ) {
     541             : 
     542             :   // fd_acc_mgr_t *  acc_mgr = slot_ctx->acc_mgr;
     543             :   // fd_funk_txn_t * txn     = slot_ctx->funk_txn;
     544             : 
     545             :   /* Collect list of changed accounts to be added to bank hash */
     546           0 :   fd_accounts_hash_task_data_t task_data;
     547             : 
     548           0 :   fd_collect_modified_accounts( slot_ctx, &task_data );
     549             : 
     550           0 :   fd_pubkey_hash_pair_t * dirty_keys = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, task_data.info_sz * FD_PUBKEY_HASH_PAIR_FOOTPRINT );
     551           0 :   ulong dirty_key_cnt = 0;
     552             : 
     553           0 :   ulong wcnt = fd_tpool_worker_cnt( tpool );
     554           0 :   task_data.lthash_values = fd_valloc_malloc( slot_ctx->valloc, FD_LTHASH_VALUE_ALIGN, wcnt * FD_LTHASH_VALUE_FOOTPRINT );
     555           0 :   for( ulong i = 0; i < wcnt; i++ ) {
     556           0 :     fd_lthash_zero(&task_data.lthash_values[i]);
     557           0 :   }
     558             : 
     559             :   /* Find accounts which have changed */
     560           0 :   fd_tpool_exec_all_rrobin( tpool, 0, fd_tpool_worker_cnt( tpool ), fd_account_hash_task, task_data.info, NULL, NULL, 1, 0, task_data.info_sz );
     561             : 
     562           0 :   for( ulong i = 0; i < task_data.info_sz; i++ ) {
     563           0 :     fd_accounts_hash_task_info_t * task_info = &task_data.info[i];
     564             :     /* Upgrade to writable record */
     565           0 :     if( !task_info->hash_changed ) {
     566           0 :       continue;
     567           0 :     }
     568             : 
     569           0 :     FD_BORROWED_ACCOUNT_DECL(acc_rec);
     570           0 :     acc_rec->const_rec = task_info->rec;
     571             : 
     572             :     // int err = fd_acc_mgr_modify( acc_mgr, txn, acc_key, 0, 0UL, acc_rec);
     573             :     // if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     574             :     //   FD_LOG_ERR(( "failed to modify account during bank hash" ));
     575             :     // }
     576             : 
     577             :     /* Update hash */
     578             : 
     579             :     // memcpy( acc_rec->meta->hash, task_info->acc_hash->hash, sizeof(fd_hash_t) );
     580             :     // acc_rec->meta->slot = slot_ctx->slot_bank.slot;
     581             : 
     582             :     /* Add account to "dirty keys" list, which will be added to the
     583             :        bank hash. */
     584             : 
     585           0 :     fd_pubkey_hash_pair_t * dirty_entry = &dirty_keys[dirty_key_cnt++];
     586           0 :     dirty_entry->rec = task_info->rec;
     587           0 :     dirty_entry->hash = (fd_hash_t const *)task_info->acc_hash->hash;
     588             : 
     589             :     // FD_TEST( err==0 );
     590           0 :   }
     591             : 
     592             :   /* Sort and hash "dirty keys" to the accounts delta hash. */
     593             : 
     594             : #ifdef VLOG
     595             :   for( ulong i = 0; i < dirty_key_cnt; ++i ) {
     596             :     FD_LOG_NOTICE(( "account delta hash X { \"key\":%ld, \"pubkey\":\"%s\", \"hash\":\"%s\" },",
     597             :                     i,
     598             :                     FD_BASE58_ENC_32_ALLOCA( dirty_keys[i].pubkey->key ),
     599             :                     FD_BASE58_ENC_32_ALLOCA( dirty_keys[i].hash->hash) ));
     600             : 
     601             :     /*
     602             :       pubkey
     603             :       slot
     604             :       lamports
     605             :       owner
     606             :       executable
     607             :       rent_epoch
     608             :       data_len
     609             :       data
     610             :       hash
     611             :     */
     612             :     // fd_pubkey_t current_owner;
     613             :     // fd_acc_mgr_get_owner( global->acc_mgr, global->funk_txn, &pairs[i].pubkey, &current_owner );
     614             :     // char encoded_owner[50];
     615             :     // fd_base58_encode_32((uchar *) &current_owner, 0, encoded_owner);
     616             :     int err = FD_ACC_MGR_SUCCESS;
     617             :     uchar * raw_acc_data = (uchar*) fd_acc_mgr_view_raw(slot_ctx->acc_mgr, slot_ctx->funk_txn, dirty_keys[i].pubkey, NULL, &err, NULL);
     618             :     if (NULL != raw_acc_data) {
     619             : 
     620             :       fd_account_meta_t * metadata = (fd_account_meta_t *)raw_acc_data;
     621             :       uchar *             acc_data = fd_account_get_data(metadata);
     622             :       char *              acc_data_str = fd_valloc_malloc(slot_ctx->valloc, 8, 5*metadata->dlen + 1);
     623             : 
     624             :       char * acc_data_str_cursor = acc_data_str;
     625             :       if (metadata->dlen > 0) {
     626             :         for( ulong j = 0; j < (metadata->dlen - 1); j++ ) {
     627             :           int x = sprintf(acc_data_str_cursor, "%u, ", acc_data[j]);
     628             :           acc_data_str_cursor += x;
     629             :         }
     630             :         sprintf(acc_data_str_cursor, "%u", acc_data[metadata->dlen - 1]);
     631             :       } else {
     632             :         *acc_data_str_cursor = 0;
     633             :       }
     634             : 
     635             :       FD_LOG_NOTICE(( "account_delta_hash_compare pubkey: (%s) slot: (%lu) lamports: (%lu), owner: (%s), executable: (%d), rent_epoch: (%lu), data_len: (%ld), hash: (%s) ",
     636             :                       FD_BASE58_ENC_32_ALLOCA( dirty_keys[i].pubkey->uc ),
     637             :                       slot_ctx->slot_bank.slot,
     638             :                       metadata->info.lamports,
     639             :                       FD_BASE58_ENC_32_ALLOCA( metadata->info.owner ),
     640             :                       metadata->info.executable,
     641             :                       metadata->info.rent_epoch,
     642             :                       metadata->dlen,
     643             :                       FD_BASE58_ENC_32_ALLOCA( dirty_keys[i].hash->hash ) ));
     644             : 
     645             :       fd_valloc_free(slot_ctx->valloc, acc_data_str);
     646             :     }
     647             :   }
     648             : #endif
     649             : 
     650           0 :   fd_valloc_free( slot_ctx->valloc, task_data.info );
     651           0 :   fd_valloc_free( slot_ctx->valloc, task_data.lthash_values );
     652           0 :   fd_valloc_free( slot_ctx->valloc, dirty_keys );
     653             : 
     654           0 :   return 0;
     655           0 : }
     656             : 
     657             : int
     658             : fd_update_hash_bank( fd_exec_slot_ctx_t * slot_ctx,
     659             :                      fd_capture_ctx_t *   capture_ctx,
     660             :                      fd_hash_t *          hash,
     661           0 :                      ulong                signature_cnt ) {
     662             : 
     663           0 :   fd_acc_mgr_t *       acc_mgr  = slot_ctx->acc_mgr;
     664           0 :   fd_funk_t *          funk     = acc_mgr->funk;
     665           0 :   fd_funk_txn_t *      txn      = slot_ctx->funk_txn;
     666             : 
     667             :   /* Collect list of changed accounts to be added to bank hash */
     668             : 
     669             : 
     670           0 :   ulong rec_cnt = 0;
     671           0 :   for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     672           0 :        NULL != rec;
     673           0 :        rec = fd_funk_txn_next_rec( funk, rec ) ) {
     674             : 
     675           0 :     if( !fd_funk_key_is_acc( rec->pair.key  ) ) continue;
     676           0 :     if( !fd_funk_rec_is_modified( funk, rec ) ) continue;
     677             : 
     678           0 :     rec_cnt++;
     679           0 :   }
     680             :   /* Iterate over accounts that have been changed in the current
     681             :      database transaction. */
     682           0 :   fd_pubkey_hash_pair_t * dirty_keys = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, rec_cnt * FD_PUBKEY_HASH_PAIR_FOOTPRINT );
     683           0 :   fd_funk_rec_t const * * erase_recs = fd_valloc_malloc( slot_ctx->valloc, 8UL, rec_cnt * sizeof(fd_funk_rec_t *) );
     684             : 
     685           0 :   ulong dirty_key_cnt = 0;
     686           0 :   ulong erase_rec_cnt = 0;
     687             : 
     688           0 :   for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
     689           0 :        NULL != rec;
     690           0 :        rec = fd_funk_txn_next_rec( funk, rec ) ) {
     691             : 
     692           0 :     fd_pubkey_t const *       acc_key  = fd_type_pun_const( rec->pair.key[0].uc );
     693             : 
     694           0 :     if( !fd_funk_key_is_acc( rec->pair.key  ) ) continue;
     695           0 :     if( !fd_funk_rec_is_modified( funk, rec ) ) continue;
     696             : 
     697             :     /* Get dirty account */
     698             : 
     699           0 :     fd_funk_rec_t const *     rec      = NULL;
     700             : 
     701           0 :     int           err = 0;
     702           0 :     fd_account_meta_t const * acc_meta = fd_acc_mgr_view_raw( acc_mgr, txn, acc_key, &rec, &err, NULL);
     703           0 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     704           0 :       FD_LOG_ERR(( "failed to view account during bank hash" ));
     705           0 :     }
     706           0 :     uchar const *             acc_data = (uchar *)acc_meta + acc_meta->hlen;
     707             : 
     708             :     /* Hash account */
     709             : 
     710           0 :     fd_hash_t acc_hash[1];
     711             :     // TODO: talk to jsiegel about this
     712           0 :     if (FD_UNLIKELY(acc_meta->info.lamports == 0)) { //!fd_acc_exists(_raw))) {
     713           0 :       fd_memset( acc_hash->hash, 0, FD_HASH_FOOTPRINT );
     714             : 
     715             :       /* If we erase records instantly, this causes problems with the
     716             :          iterator.  Instead, we will store away the record and erase
     717             :          it later where appropriate.  */
     718           0 :       erase_recs[erase_rec_cnt++] = rec;
     719           0 :     } else {
     720             :       // Maybe instead of going through the whole hash mechanism, we
     721             :       // can find the parent funky record and just compare the data?
     722           0 :       fd_hash_account_current( acc_hash->hash, NULL, acc_meta, acc_key->key, acc_data );
     723           0 :     }
     724             : 
     725             :     /* If hash didn't change, nothing to do */
     726           0 :     if( 0==memcmp( acc_hash->hash, acc_meta->hash, sizeof(fd_hash_t) ) ) {
     727           0 :       if( acc_meta->slot == slot_ctx->slot_bank.slot ) {
     728             :         /* no-op */
     729           0 :       } else {
     730           0 :         continue;
     731           0 :       }
     732           0 :     }
     733             : 
     734             :     /* Upgrade to writable record */
     735             : 
     736             :     // How the heck do we deal with new accounts?  test that
     737           0 :     FD_BORROWED_ACCOUNT_DECL(acc_rec);
     738           0 :     acc_rec->const_rec = rec;
     739             : 
     740           0 :     err = fd_acc_mgr_modify( acc_mgr, txn, acc_key, 0, 0UL, acc_rec);
     741           0 :     if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
     742           0 :       FD_LOG_ERR(( "failed to modify account during bank hash" ));
     743           0 :     }
     744             : 
     745             :     /* Update hash */
     746             : 
     747           0 :     memcpy( acc_rec->meta->hash, acc_hash->hash, sizeof(fd_hash_t) );
     748           0 :     acc_rec->meta->slot = slot_ctx->slot_bank.slot;
     749             : 
     750             :     /* Logging ... */
     751           0 :     FD_LOG_DEBUG(( "fd_acc_mgr_update_hash: %s "
     752           0 :         "slot: %lu "
     753           0 :         "lamports: %lu  "
     754           0 :         "owner: %s  "
     755           0 :         "executable: %s,  "
     756           0 :         "rent_epoch: %lu, "
     757           0 :         "data_len: %lu",
     758           0 :         FD_BASE58_ENC_32_ALLOCA( acc_key ),
     759           0 :         slot_ctx->slot_bank.slot,
     760           0 :         acc_rec->meta->info.lamports,
     761           0 :         FD_BASE58_ENC_32_ALLOCA( acc_rec->meta->info.owner ),
     762           0 :         acc_rec->meta->info.executable ? "true" : "false",
     763           0 :         acc_rec->meta->info.rent_epoch,
     764           0 :         acc_rec->meta->dlen ));
     765             : 
     766             : 
     767             :     /* Add account to "dirty keys" list, which will be added to the
     768             :        bank hash. */
     769             : 
     770           0 :     fd_pubkey_hash_pair_t * dirty_entry = &dirty_keys[dirty_key_cnt++];
     771           0 :     dirty_entry->rec = rec;
     772           0 :     dirty_entry->hash = (fd_hash_t const *)acc_rec->meta->hash;
     773             : 
     774             :     /* Add to capture */
     775           0 :     if( capture_ctx != NULL && capture_ctx->capture != NULL ) {
     776           0 :       err = fd_solcap_write_account(
     777           0 :           capture_ctx->capture,
     778           0 :           acc_key->uc,
     779           0 :           &acc_rec->meta->info,
     780           0 :           acc_data,
     781           0 :           acc_rec->meta->dlen,
     782           0 :           acc_hash->hash );
     783           0 :     }
     784           0 :     FD_TEST( err==0 );
     785           0 :   }
     786             : 
     787             :   /* Sort and hash "dirty keys" to the accounts delta hash. */
     788             : 
     789             :   // FD_LOG_DEBUG(("slot %ld, dirty %ld", slot_ctx->slot_bank.slot, dirty_key_cnt));
     790             : 
     791           0 :   slot_ctx->signature_cnt = signature_cnt;
     792           0 :   fd_hash_bank( slot_ctx, capture_ctx, hash, dirty_keys, dirty_key_cnt );
     793             : 
     794             : //  if( FD_FEATURE_ACTIVE( slot_ctx, lattice_account_hash ) ) {
     795             : //    // Sanity-check LT Hash
     796             : //    fd_accounts_check_lthash( slot_ctx );
     797             : 
     798             :     // Check that the old account_delta_hash is the same as the lthash
     799             : //    FD_TEST( 0==memcmp( slot_ctx->slot_bank.lthash.lthash, slot_ctx->account_delta_hash.hash, sizeof(fd_hash_t) ) );
     800             : //  }
     801             : 
     802           0 :   fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
     803           0 :   if (slot_ctx->slot_bank.slot >= epoch_bank->eah_start_slot) {
     804           0 :     fd_accounts_hash( slot_ctx, NULL, &slot_ctx->slot_bank.epoch_account_hash );
     805           0 :     epoch_bank->eah_start_slot = ULONG_MAX;
     806           0 :   }
     807             : 
     808           0 :   for (ulong i = 0; i < erase_rec_cnt; i++) {
     809           0 :     fd_funk_rec_t const * erase_rec = erase_recs[i];
     810           0 :     fd_funk_rec_remove(funk, fd_funk_rec_modify(funk, erase_rec), 1);
     811           0 :   }
     812             : 
     813           0 :   fd_valloc_free( slot_ctx->valloc, dirty_keys );
     814           0 :   fd_valloc_free( slot_ctx->valloc, erase_recs );
     815             : 
     816           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     817           0 : }
     818             : 
     819             : void const *
     820             : fd_hash_account( uchar                     hash[ static 32 ],
     821             :                  fd_lthash_value_t       * lthash,
     822             :                  fd_account_meta_t const * m,
     823             :                  uchar const               pubkey[ static 32 ],
     824           0 :                  uchar const             * data ) {
     825           0 :   ulong         lamports   = m->info.lamports;  /* >0UL */
     826           0 :   ulong         rent_epoch = m->info.rent_epoch;
     827           0 :   uchar         executable = m->info.executable & 0x1;
     828           0 :   uchar const * owner      = (uchar const *)m->info.owner;
     829             : 
     830           0 :   fd_blake3_t b3[1];
     831           0 :   fd_blake3_init  ( b3 );
     832           0 :   fd_blake3_append( b3, &lamports,   sizeof( ulong ) );
     833           0 :   fd_blake3_append( b3, &rent_epoch, sizeof( ulong ) );
     834           0 :   fd_blake3_append( b3, data,        m->dlen         );
     835           0 :   fd_blake3_append( b3, &executable, sizeof( uchar ) );
     836           0 :   fd_blake3_append( b3, owner,       32UL            );
     837           0 :   fd_blake3_append( b3, pubkey,      32UL            );
     838           0 :   if( NULL == lthash ) {
     839           0 :     fd_blake3_fini  ( b3, hash );
     840           0 :   } else {
     841           0 :     fd_blake3_fini_varlen( b3, lthash->bytes, FD_LTHASH_LEN_BYTES );
     842           0 :     fd_memcpy( hash, lthash->bytes, 32);
     843           0 :   }
     844             : 
     845           0 :   return hash;
     846           0 : }
     847             : 
     848             : void const *
     849             : fd_hash_account_current( uchar                      hash  [ static 32 ],
     850             :                          fd_lthash_value_t         *lthash,
     851             :                          fd_account_meta_t const   *account,
     852             :                          uchar const                pubkey[ static 32 ],
     853           0 :                          uchar const               *data ) {
     854           0 :   return fd_hash_account( hash, lthash, account, pubkey, data );
     855           0 : }
     856             : 
     857             : struct accounts_hash {
     858             :   fd_funk_rec_t * key;
     859             :   ulong  hash;
     860             : };
     861             : typedef struct accounts_hash accounts_hash_t;
     862             : 
     863             : #define MAP_NAME accounts_hash
     864           0 : #define MAP_KEY_T fd_funk_rec_t *
     865           0 : #define MAP_HASH_T ulong
     866           0 : #define MAP_KEY_EQUAL(k0,k1) ((NULL != k0) && (NULL != k1) && fd_funk_rec_key_eq( k0->pair.key, k1->pair.key ))
     867           0 : #define MAP_KEY_HASH(p) fd_funk_rec_key_hash( p->pair.key, 2887034UL )
     868             : #define MAP_KEY_EQUAL_IS_SLOW 1
     869           0 : #define MAP_KEY_NULL 0UL
     870           0 : #define MAP_KEY_INVAL(k) (NULL == k)
     871             : 
     872             : // #define MAP_KEY_COPY(kd,ks)   fd_funk_xid_key_pair_copy((kd),(ks))
     873             : 
     874           0 : #define MAP_T    accounts_hash_t
     875             : #include "../../util/tmpl/fd_map_dynamic.c"
     876             : 
     877             : static fd_pubkey_hash_pair_t *
     878             : fd_accounts_sorted_subrange( fd_exec_slot_ctx_t * slot_ctx, uint range_idx, uint range_cnt, ulong * num_pairs_out, fd_lthash_value_t *lthash_values, ulong n0
     879           0 :  ) {
     880           0 :   fd_funk_t *     funk = slot_ctx->acc_mgr->funk;
     881           0 :   fd_wksp_t *     wksp = fd_funk_wksp( funk );
     882           0 :   fd_funk_rec_t * rec_map  = fd_funk_rec_map( funk, wksp );
     883           0 :   ulong           num_iter_accounts = fd_funk_rec_map_key_max( rec_map );
     884           0 :   ulong           max_pairs = ( range_cnt == 1U ? num_iter_accounts : 2UL*num_iter_accounts/range_cnt ); /* Initial estimate */
     885           0 :   ulong           num_pairs = 0;
     886           0 :   fd_pubkey_hash_pair_t * pairs = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, max_pairs * sizeof(fd_pubkey_hash_pair_t) );
     887           0 :   FD_TEST(NULL != pairs);
     888           0 :   ulong           range_len = ULONG_MAX/range_cnt;
     889           0 :   ulong           range_min = range_len*range_idx;
     890           0 :   ulong           range_max = ( range_idx+1U < range_cnt ? range_min+range_len-1U : ULONG_MAX );
     891             : 
     892           0 :   fd_lthash_value_t accum;
     893           0 :   fd_lthash_zero(&accum);
     894             : 
     895           0 :   for( ulong i = num_iter_accounts; i; --i ) {
     896           0 :     fd_funk_rec_t const * rec = rec_map + (i-1UL);
     897           0 :     if ( ( rec->map_next >> 63 ) /* unused map entry */ ||
     898           0 :          !fd_funk_key_is_acc( rec->pair.key ) /* not a solana record */ ||
     899           0 :          ( rec->pair.xid->ul[0] | rec->pair.xid->ul[1] ) != 0 /* not root xid */ ) {
     900           0 :       continue;
     901           0 :     }
     902             : 
     903           0 :     ulong n = __builtin_bswap64(rec->pair.key->ul[0]);
     904           0 :     if( n < range_min || n > range_max ) {
     905           0 :       continue;
     906           0 :     }
     907             : 
     908           0 :     fd_account_meta_t * metadata = (fd_account_meta_t *) fd_funk_val_const( rec, wksp );
     909           0 :     int is_empty = (metadata->info.lamports == 0);
     910           0 :     if( is_empty ) {
     911           0 :       continue;
     912           0 :     }
     913             : 
     914           0 :     uchar hash[32];
     915           0 :     fd_lthash_value_t new_lthash_value;
     916           0 :     fd_lthash_zero(&new_lthash_value);
     917             : 
     918           0 :     fd_hash_account_current( (uchar *) hash, &new_lthash_value, metadata, rec->pair.key->uc, fd_account_get_data(metadata) );
     919           0 :     fd_lthash_add( &accum, &new_lthash_value );
     920             : 
     921           0 :     fd_hash_t * h = (fd_hash_t *) metadata->hash;
     922           0 :     if( (h->ul[0] | h->ul[1] | h->ul[2] | h->ul[3]) != 0 ) {
     923           0 :       if( fd_acc_exists( metadata ) && memcmp( metadata->hash, &hash, 32 ) != 0 ) {
     924           0 :         FD_LOG_WARNING(( "snapshot hash (%s) doesn't match calculated hash (%s)", FD_BASE58_ENC_32_ALLOCA( metadata->hash ), FD_BASE58_ENC_32_ALLOCA( &hash ) ));
     925           0 :       }
     926           0 :     } else
     927           0 :       fd_memcpy( metadata->hash, &hash, 32 );
     928             : 
     929           0 :     if( (metadata->info.executable & ~1) != 0 )
     930           0 :       continue;
     931             : 
     932           0 :     if( num_pairs == max_pairs ) {
     933             :       /* Try again with a larger array */
     934           0 :       fd_valloc_free( slot_ctx->valloc, pairs );
     935           0 :       max_pairs *= 2;
     936           0 :       pairs = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, max_pairs * sizeof(fd_pubkey_hash_pair_t) );
     937           0 :       FD_TEST(NULL != pairs);
     938           0 :       num_pairs = 0;
     939           0 :       fd_lthash_zero(&accum);
     940           0 :       i = num_iter_accounts+1;
     941           0 :       continue;
     942           0 :     }
     943             : 
     944           0 :     fd_pubkey_hash_pair_t * pair = &pairs[num_pairs++];
     945           0 :     pair->rec = rec;
     946           0 :     pair->hash = (const fd_hash_t *)metadata->hash;
     947           0 :   }
     948             : 
     949           0 :   sort_pubkey_hash_pair_inplace( pairs, num_pairs );
     950             : 
     951             :   // FD_LOG_NOTICE(( "sorted_subrange %lx ... %lx => %lu pairs", range_min, range_max, num_pairs ));
     952           0 :   *num_pairs_out = num_pairs;
     953             : 
     954           0 :   fd_lthash_add( &lthash_values[n0], &accum  );
     955           0 :   return pairs;
     956           0 : }
     957             : 
     958             : struct fd_subrange_task_info {
     959             :   fd_exec_slot_ctx_t * slot_ctx;
     960             :   ulong num_lists;
     961             :   fd_pubkey_hash_pair_list_t * lists;
     962             :   fd_lthash_value_t *lthash_values;
     963             : };
     964             : typedef struct fd_subrange_task_info fd_subrange_task_info_t;
     965             : 
     966             : static void
     967             : fd_accounts_sorted_subrange_task( void *tpool,
     968             :                                   ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
     969             :                                   void *args FD_PARAM_UNUSED,
     970             :                                   void *reduce FD_PARAM_UNUSED, ulong stride FD_PARAM_UNUSED,
     971             :                                   ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
     972             :                                   ulong m0, ulong m1 FD_PARAM_UNUSED,
     973           0 :                                   ulong n0, ulong n1 FD_PARAM_UNUSED) {
     974           0 :   fd_subrange_task_info_t * task_info = (fd_subrange_task_info_t *)tpool;
     975           0 :   fd_pubkey_hash_pair_list_t * list = task_info->lists + m0;
     976           0 :   list->pairs = fd_accounts_sorted_subrange( task_info->slot_ctx, (uint)m0, (uint)task_info->num_lists, &list->pairs_len, task_info->lthash_values, n0 );
     977           0 : }
     978             : 
     979             : int
     980           0 : fd_accounts_hash( fd_exec_slot_ctx_t * slot_ctx, fd_tpool_t * tpool, fd_hash_t * accounts_hash ) {
     981           0 :   FD_LOG_NOTICE(("accounts_hash start"));
     982             : 
     983           0 :   if( tpool == NULL || fd_tpool_worker_cnt( tpool ) <= 1U ) {
     984           0 :     ulong                   num_pairs = 0;
     985           0 :     fd_lthash_value_t *lthash_values = fd_valloc_malloc( slot_ctx->valloc, FD_LTHASH_VALUE_ALIGN, FD_LTHASH_VALUE_FOOTPRINT );
     986           0 :     fd_lthash_zero(&lthash_values[0]);
     987             : 
     988           0 :     fd_pubkey_hash_pair_t * pairs = fd_accounts_sorted_subrange( slot_ctx, 0, 1, &num_pairs, lthash_values, 0 );
     989           0 :     FD_TEST(NULL != pairs);
     990           0 :     fd_pubkey_hash_pair_list_t list1 = { .pairs = pairs, .pairs_len = num_pairs };
     991           0 :     fd_hash_account_deltas( &list1, 1, accounts_hash, slot_ctx );
     992           0 :     fd_valloc_free( slot_ctx->valloc, pairs );
     993             : 
     994           0 :     fd_lthash_value_t * acc = (fd_lthash_value_t *)fd_type_pun(slot_ctx->slot_bank.lthash.lthash);
     995           0 :     fd_lthash_add( acc, &lthash_values[0] );
     996             : 
     997           0 :     fd_valloc_free( slot_ctx->valloc, lthash_values );
     998           0 :   } else {
     999           0 :     ulong num_lists = fd_tpool_worker_cnt( tpool );
    1000           0 :     FD_LOG_NOTICE(( "launching %lu hash tasks", num_lists ));
    1001           0 :     fd_pubkey_hash_pair_list_t lists[num_lists];
    1002             : 
    1003           0 :     fd_lthash_value_t *lthash_values = fd_valloc_malloc( slot_ctx->valloc, FD_LTHASH_VALUE_ALIGN, num_lists * FD_LTHASH_VALUE_FOOTPRINT );
    1004           0 :     for( ulong i = 0; i < num_lists; i++ ) {
    1005           0 :       fd_lthash_zero(&lthash_values[i]);
    1006           0 :     }
    1007             : 
    1008           0 :     fd_subrange_task_info_t task_info = {
    1009           0 :       .slot_ctx = slot_ctx,
    1010           0 :       .num_lists = num_lists,
    1011           0 :       .lists = lists,
    1012           0 :       .lthash_values = lthash_values};
    1013           0 :     fd_tpool_exec_all_rrobin( tpool, 0, num_lists, fd_accounts_sorted_subrange_task, &task_info, NULL, NULL, 1, 0, num_lists );
    1014           0 :     fd_hash_account_deltas( lists, num_lists, accounts_hash, slot_ctx );
    1015           0 :     for( ulong i = 0; i < num_lists; ++i ) {
    1016           0 :       fd_valloc_free( slot_ctx->valloc, lists[i].pairs );
    1017           0 :     }
    1018           0 :     fd_lthash_value_t * acc = (fd_lthash_value_t *)fd_type_pun(slot_ctx->slot_bank.lthash.lthash);
    1019           0 :     for( ulong i = 0; i < num_lists; i++ ) {
    1020           0 :       fd_lthash_add( acc, &lthash_values[i] );
    1021           0 :     }
    1022             : 
    1023           0 :     fd_valloc_free( slot_ctx->valloc, lthash_values );
    1024           0 :   }
    1025           0 :   FD_LOG_NOTICE(("accounts_lthash %s", FD_LTHASH_ENC_32_ALLOCA( (fd_lthash_value_t *) slot_ctx->slot_bank.lthash.lthash )));
    1026             : 
    1027             :   // fd_accounts_check_lthash( slot_ctx );
    1028             : 
    1029           0 :   FD_LOG_INFO(("accounts_hash %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash->hash) ));
    1030             : 
    1031           0 :   return 0;
    1032           0 : }
    1033             : 
    1034             : int
    1035           0 : fd_accounts_hash_inc_only( fd_exec_slot_ctx_t * slot_ctx, fd_hash_t *accounts_hash, fd_funk_txn_t * child_txn, ulong do_hash_verify ) {
    1036           0 :   FD_LOG_NOTICE(("accounts_hash_inc_only start for txn %p, do_hash_verify=%s", (void *)child_txn, do_hash_verify ? "true" : "false" ));
    1037             : 
    1038           0 :   fd_funk_t *     funk = slot_ctx->acc_mgr->funk;
    1039           0 :   fd_wksp_t *     wksp = fd_funk_wksp( funk );
    1040           0 :   fd_funk_rec_t * rec_map  = fd_funk_rec_map( funk, wksp );
    1041             : 
    1042             :   // How many total records are we dealing with?
    1043           0 :   ulong                   num_iter_accounts = fd_funk_rec_map_key_cnt( rec_map );
    1044           0 :   ulong                   num_pairs = 0;
    1045           0 :   fd_pubkey_hash_pair_t * pairs = fd_valloc_malloc( slot_ctx->valloc, FD_PUBKEY_HASH_PAIR_ALIGN, num_iter_accounts * sizeof(fd_pubkey_hash_pair_t) );
    1046           0 :   FD_TEST(NULL != pairs);
    1047             : 
    1048           0 :   fd_blake3_t *b3 = NULL;
    1049           0 :   fd_scratch_push();
    1050             : 
    1051           0 :   for (fd_funk_rec_t const *rec = fd_funk_txn_first_rec( funk, child_txn ); NULL != rec; rec = fd_funk_txn_next_rec(funk, rec)) {
    1052           0 :     if ( !fd_funk_key_is_acc( rec->pair.key ) )
    1053           0 :       continue;
    1054             : 
    1055           0 :     fd_account_meta_t * metadata = (fd_account_meta_t *) fd_funk_val_const( rec, wksp );
    1056           0 :     int is_empty = (metadata->info.lamports == 0);
    1057             : 
    1058           0 :     if (is_empty) {
    1059           0 :       pairs[num_pairs].rec = rec;
    1060             : 
    1061           0 :       fd_hash_t * hash = fd_scratch_alloc(alignof(fd_hash_t), sizeof(fd_hash_t));
    1062           0 :       if (NULL == b3)
    1063           0 :         b3 = fd_scratch_alloc(alignof(fd_blake3_t), sizeof(fd_blake3_t));
    1064           0 :       fd_blake3_init  ( b3 );
    1065           0 :       fd_blake3_append( b3, rec->pair.key->uc,   sizeof( fd_pubkey_t ) );
    1066           0 :       fd_blake3_fini  ( b3, hash );
    1067             : 
    1068           0 :       pairs[num_pairs].hash = hash;
    1069           0 :       num_pairs++;
    1070           0 :       continue;
    1071           0 :     } else {
    1072           0 :       fd_hash_t *h = (fd_hash_t *) metadata->hash;
    1073           0 :       if ((h->ul[0] | h->ul[1] | h->ul[2] | h->ul[3]) == 0) {
    1074             :         // By the time we fall into this case, we can assume the ignore_slot feature is enabled...
    1075           0 :         fd_hash_account_current( (uchar *) metadata->hash, NULL, metadata, rec->pair.key->uc, fd_account_get_data(metadata) );
    1076           0 :       } else if( do_hash_verify ) {
    1077           0 :         uchar hash[32];
    1078           0 :         ulong old_slot = slot_ctx->slot_bank.slot;
    1079           0 :         slot_ctx->slot_bank.slot = metadata->slot;
    1080           0 :         fd_hash_account_current( (uchar *) &hash, NULL, metadata, rec->pair.key->uc, fd_account_get_data(metadata) );
    1081           0 :         slot_ctx->slot_bank.slot = old_slot;
    1082           0 :         if ( fd_acc_exists( metadata ) && memcmp( metadata->hash, &hash, 32 ) != 0 ) {
    1083           0 :           FD_LOG_WARNING(( "snapshot hash (%s) doesn't match calculated hash (%s)", FD_BASE58_ENC_32_ALLOCA( metadata->hash ), FD_BASE58_ENC_32_ALLOCA( &hash ) ));
    1084           0 :         }
    1085           0 :       }
    1086           0 :     }
    1087             : 
    1088           0 :     if ((metadata->info.executable & ~1) != 0)
    1089           0 :       continue;
    1090             : 
    1091           0 :     pairs[num_pairs].rec = rec;
    1092           0 :     pairs[num_pairs].hash = (const fd_hash_t *)metadata->hash;
    1093           0 :     num_pairs++;
    1094           0 :   }
    1095             : 
    1096           0 :   sort_pubkey_hash_pair_inplace( pairs, num_pairs );
    1097           0 :   fd_pubkey_hash_pair_list_t list1 = { .pairs = pairs, .pairs_len = num_pairs };
    1098           0 :   fd_hash_account_deltas( &list1, 1, accounts_hash, slot_ctx );
    1099             : 
    1100           0 :   fd_valloc_free( slot_ctx->valloc, pairs );
    1101           0 :   fd_scratch_pop();
    1102             : 
    1103           0 :   FD_LOG_INFO(( "accounts_hash %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash->hash) ));
    1104             : 
    1105           0 :   return 0;
    1106           0 : }
    1107             : 
    1108             : int
    1109           0 : fd_snapshot_hash( fd_exec_slot_ctx_t * slot_ctx, fd_tpool_t * tpool, fd_hash_t * accounts_hash, uint check_hash ) {
    1110           0 :   (void) check_hash;
    1111             : 
    1112           0 :   if( fd_should_snapshot_include_epoch_accounts_hash (slot_ctx) ) {
    1113           0 :     FD_LOG_NOTICE(( "snapshot is including epoch account hash" ));
    1114           0 :     fd_sha256_t h;
    1115           0 :     fd_hash_t hash;
    1116           0 :     fd_accounts_hash( slot_ctx, tpool, &hash );
    1117             : 
    1118           0 :     fd_sha256_init( &h );
    1119           0 :     fd_sha256_append( &h, (uchar const *) hash.hash, sizeof( fd_hash_t ) );
    1120           0 :     fd_sha256_append( &h, (uchar const *) slot_ctx->slot_bank.epoch_account_hash.hash, sizeof( fd_hash_t ) );
    1121           0 :     fd_sha256_fini( &h, accounts_hash );
    1122             : 
    1123           0 :     return 0;
    1124           0 :   }
    1125           0 :   return fd_accounts_hash( slot_ctx, tpool, accounts_hash );
    1126           0 : }
    1127             : 
    1128             : /* Re-computes the lthash from the current slot */
    1129             : void
    1130           0 : fd_accounts_check_lthash( fd_exec_slot_ctx_t * slot_ctx ) {
    1131           0 :   fd_funk_t *     funk = slot_ctx->acc_mgr->funk;
    1132           0 :   fd_wksp_t *     wksp = fd_funk_wksp( funk );
    1133           0 :   fd_funk_rec_t * rec_map  = fd_funk_rec_map( funk, wksp );
    1134           0 :   fd_funk_txn_t * txn_map  = fd_funk_txn_map( funk, wksp );
    1135             : 
    1136             :   // How many txns are we dealing with?
    1137           0 :   ulong txn_cnt = 1;
    1138           0 :   fd_funk_txn_t * txn = slot_ctx->funk_txn;
    1139           0 :   while (NULL != txn) {
    1140           0 :     txn_cnt++;
    1141           0 :     txn = fd_funk_txn_parent( txn, txn_map );
    1142           0 :   }
    1143             : 
    1144           0 :   fd_funk_txn_t ** txns = fd_alloca_check(sizeof(fd_funk_txn_t *), sizeof(fd_funk_txn_t *) * txn_cnt);
    1145           0 :   if ( FD_UNLIKELY(NULL == txns))
    1146           0 :     FD_LOG_ERR(("Out of scratch space?"));
    1147             : 
    1148             :   // Lay it flat to make it easier to walk backwards up the chain from
    1149             :   // the root
    1150           0 :   txn = slot_ctx->funk_txn;
    1151           0 :   ulong txn_idx = txn_cnt;
    1152           0 :   while (1) {
    1153           0 :     txns[--txn_idx] = txn;
    1154           0 :     if (NULL == txn)
    1155           0 :       break;
    1156           0 :     txn = fd_funk_txn_parent( txn, txn_map );
    1157           0 :   }
    1158             : 
    1159             :   // How many total records are we dealing with?
    1160           0 :   ulong           num_iter_accounts = fd_funk_rec_map_key_cnt( rec_map );
    1161             : 
    1162           0 :   int accounts_hash_slots = fd_ulong_find_msb(num_iter_accounts  ) + 1;
    1163             : 
    1164           0 :   FD_LOG_WARNING(("allocating memory for hash.  num_iter_accounts: %lu   slots: %d", num_iter_accounts, accounts_hash_slots));
    1165           0 :   void * hashmem = fd_valloc_malloc( slot_ctx->valloc, accounts_hash_align(), accounts_hash_footprint(accounts_hash_slots));
    1166           0 :   FD_LOG_WARNING(("initializing memory for hash"));
    1167           0 :   accounts_hash_t * hash_map = accounts_hash_join(accounts_hash_new(hashmem, accounts_hash_slots));
    1168             : 
    1169           0 :   FD_LOG_WARNING(("copying in accounts"));
    1170             : 
    1171             :   // walk up the transactions...
    1172           0 :   for (ulong idx = 0; idx < txn_cnt; idx++) {
    1173           0 :     FD_LOG_WARNING(("txn idx %lu", idx));
    1174           0 :     for (fd_funk_rec_t const *rec = fd_funk_txn_first_rec( funk, txns[idx]);
    1175           0 :          NULL != rec;
    1176           0 :          rec = fd_funk_txn_next_rec(funk, rec)) {
    1177           0 :       if ( fd_funk_key_is_acc( rec->pair.key ) ) {
    1178           0 :         accounts_hash_t * q = accounts_hash_query(hash_map, (fd_funk_rec_t *) rec, NULL);
    1179           0 :         if (NULL != q)
    1180           0 :           accounts_hash_remove(hash_map, q);
    1181           0 :         if (!(rec->flags & FD_FUNK_REC_FLAG_ERASE))
    1182           0 :           accounts_hash_insert(hash_map, (fd_funk_rec_t *) rec);
    1183           0 :       }
    1184           0 :     }
    1185           0 :   }
    1186             : 
    1187           0 :   FD_LOG_WARNING(("assumulating a new lthash"));
    1188             : 
    1189             :   // Initialize the accumulator to zero
    1190           0 :   fd_lthash_value_t acc_lthash;
    1191           0 :   fd_lthash_zero( &acc_lthash );
    1192             : 
    1193           0 :   ulong slot_cnt = accounts_hash_slot_cnt(hash_map);;
    1194           0 :   for( ulong slot_idx=0UL; slot_idx<slot_cnt; slot_idx++ ) {
    1195           0 :     accounts_hash_t *slot = &hash_map[slot_idx];
    1196           0 :     if (FD_UNLIKELY (NULL != slot->key)) {
    1197           0 :       void const * data = fd_funk_val_const( slot->key, wksp );
    1198           0 :       fd_account_meta_t * metadata = (fd_account_meta_t *)fd_type_pun_const( data );
    1199           0 :       if( FD_UNLIKELY(metadata->info.lamports != 0) ) {
    1200           0 :         uchar *             acc_data = fd_account_get_data(metadata);
    1201           0 :         uchar hash  [ 32 ];
    1202           0 :         fd_lthash_value_t new_lthash_value;
    1203           0 :         fd_lthash_zero(&new_lthash_value);
    1204           0 :         fd_hash_account_current( hash, &new_lthash_value, metadata, slot->key->pair.key[0].uc, acc_data );
    1205           0 :         fd_lthash_add( &acc_lthash, &new_lthash_value );
    1206             : 
    1207           0 :         if (fd_acc_exists( metadata ) && memcmp( metadata->hash, &hash, 32 ) != 0 ) {
    1208           0 :           FD_LOG_WARNING(( "snapshot hash (%s) doesn't match calculated hash (%s)", FD_BASE58_ENC_32_ALLOCA( metadata->hash ), FD_BASE58_ENC_32_ALLOCA( &hash ) ));
    1209           0 :         }
    1210           0 :       }
    1211           0 :     }
    1212           0 :   }
    1213             : 
    1214             :   // Compare the accumulator to the slot
    1215           0 :   fd_lthash_value_t * acc = (fd_lthash_value_t *)fd_type_pun_const( slot_ctx->slot_bank.lthash.lthash );
    1216           0 :   if ( memcmp( acc, &acc_lthash, sizeof( fd_lthash_value_t ) ) == 0 ) {
    1217           0 :     FD_LOG_NOTICE(("accounts_lthash %s == %s", FD_LTHASH_ENC_32_ALLOCA (acc), FD_LTHASH_ENC_32_ALLOCA (&acc_lthash)));
    1218           0 :   } else {
    1219           0 :     FD_LOG_ERR(("accounts_lthash %s != %s", FD_LTHASH_ENC_32_ALLOCA (acc), FD_LTHASH_ENC_32_ALLOCA (&acc_lthash)));
    1220           0 :   }
    1221           0 : }

Generated by: LCOV version 1.14