LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_system_program_nonce.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 518 591 87.6 %
Date: 2024-11-13 11:58:15 Functions: 16 17 94.1 %

          Line data    Source code
       1             : #include "fd_system_program.h"
       2             : #include "../fd_account.h"
       3             : #include "../fd_acc_mgr.h"
       4             : #include "../fd_system_ids.h"
       5             : #include "../context/fd_exec_slot_ctx.h"
       6             : #include "../context/fd_exec_txn_ctx.h"
       7             : #include "../sysvar/fd_sysvar_rent.h"
       8             : #include "../fd_executor.h"
       9             : 
      10             : static int
      11             : require_acct( fd_exec_instr_ctx_t * ctx,
      12             :               ulong                 idx,
      13        4617 :               fd_pubkey_t const *   pubkey ) {
      14             : 
      15             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/sysvar_cache.rs#L228-L229 */
      16             : 
      17        4617 :   if( FD_UNLIKELY( ctx->instr->acct_cnt <= idx ) )
      18          66 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
      19             : 
      20             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/sysvar_cache.rs#L230-L232 */
      21             : 
      22        4551 :   if( FD_UNLIKELY( 0!=memcmp( ctx->instr->acct_pubkeys[idx].uc, pubkey->uc, sizeof(fd_pubkey_t) ) ) )
      23         981 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
      24             : 
      25        3570 :   return FD_EXECUTOR_INSTR_SUCCESS;
      26        4551 : }
      27             : 
      28             : static int
      29             : require_acct_rent( fd_exec_instr_ctx_t * ctx,
      30             :                    ulong                 idx,
      31         987 :                    fd_rent_t const **    out_rent ) {
      32             : 
      33         987 :   do {
      34         987 :     int err = require_acct( ctx, idx, &fd_sysvar_rent_id );
      35         987 :     if( FD_UNLIKELY( err ) ) return err;
      36         987 :   } while(0);
      37             : 
      38         927 :   fd_rent_t const * rent = fd_sysvar_cache_rent( ctx->slot_ctx->sysvar_cache );
      39         927 :   if( FD_UNLIKELY( !rent ) )
      40           0 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
      41             : 
      42         927 :   *out_rent = rent;
      43         927 :   return FD_EXECUTOR_INSTR_SUCCESS;
      44         927 : }
      45             : 
      46             : static int
      47             : require_acct_recent_blockhashes(
      48             :   fd_exec_instr_ctx_t *             ctx,
      49             :   ulong                             idx,
      50        3630 :   fd_recent_block_hashes_t const ** out ) {
      51             : 
      52        3630 :   do {
      53        3630 :     int err = require_acct( ctx, idx, &fd_sysvar_recent_block_hashes_id );
      54        3630 :     if( FD_UNLIKELY( err ) ) return err;
      55        3630 :   } while(0);
      56             : 
      57        2643 :   fd_recent_block_hashes_t const * rbh = fd_sysvar_cache_recent_block_hashes( ctx->slot_ctx->sysvar_cache );
      58        2643 :   if( FD_UNLIKELY( !rbh ) )
      59          27 :     return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
      60             : 
      61        2616 :   *out = rbh;
      62        2616 :   return FD_EXECUTOR_INSTR_SUCCESS;
      63        2643 : }
      64             : 
      65             : /* most_recent_block_hash mirrors
      66             :    solana_runtime::bank::Bank::last_blockhash_and_lamports_per_signature
      67             : 
      68             :    https://github.com/solana-labs/solana/blob/v1.17.23/runtime/src/bank.rs#L4033-L4040 */
      69             : 
      70             : static int
      71             : most_recent_block_hash( fd_exec_instr_ctx_t * ctx,
      72        1752 :                         fd_hash_t *           out ) {
      73             : 
      74        1752 :   fd_block_block_hash_entry_t * hashes = ctx->slot_ctx->slot_bank.recent_block_hashes.hashes;
      75        1752 :   if( deq_fd_block_block_hash_entry_t_empty( hashes ) ) {
      76           0 :     ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES;
      77           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
      78           0 :   }
      79             : 
      80        1752 :   *out = deq_fd_block_block_hash_entry_t_peek_head_const( hashes )->blockhash;
      81        1752 :   return FD_EXECUTOR_INSTR_SUCCESS;
      82        1752 : }
      83             : 
      84             : static void
      85             : fd_durable_nonce_from_blockhash( fd_hash_t *       out,
      86        9159 :                                  fd_hash_t const * blockhash ) {
      87        9159 :   uchar buf[45];
      88        9159 :   memcpy( buf,    "DURABLE_NONCE", 13UL );
      89        9159 :   memcpy( buf+13, blockhash,       32UL );
      90        9159 :   fd_sha256_hash( buf, sizeof(buf), out );
      91        9159 : }
      92             : 
      93             : /* fd_system_program_set_nonce_state is a helper for updating the
      94             :    contents of a nonce account.
      95             : 
      96             :    Matches solana_sdk::transaction_context::BorrowedAccount::set_state
      97             :    https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/transaction_context.rs#L1020-L1029 */
      98             : 
      99             : static int
     100             : fd_system_program_set_nonce_state( fd_exec_instr_ctx_t *             ctx,
     101             :                                    ulong                             acct_idx,
     102        2166 :                                    fd_nonce_state_versions_t const * new_state ) {
     103             : 
     104             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/transaction_context.rs#L1021
     105             :      => https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/transaction_context.rs#L868 */
     106             : 
     107        2166 :   do {
     108        2166 :     int err = 99999;
     109        2166 :     if( FD_UNLIKELY( !fd_account_can_data_be_changed( ctx->instr, acct_idx, &err ) ) )
     110         129 :       return err;
     111        2166 :   } while(0);
     112             : 
     113             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/transaction_context.rs#L1024-L1026 */
     114             : 
     115        2037 :   fd_borrowed_account_t * account = NULL;
     116        2037 :   do {
     117        2037 :     int err = fd_instr_borrowed_account_modify_idx( ctx, acct_idx, 0UL, &account );
     118        2037 :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
     119        2037 :   } while(0);
     120             : 
     121        2037 :   if( FD_UNLIKELY( fd_nonce_state_versions_size( new_state ) > account->meta->dlen ) )
     122           9 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     123             : 
     124             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/transaction_context.rs#L1027 */
     125             : 
     126        2028 :   do {
     127        2028 :     fd_bincode_encode_ctx_t encode =
     128        2028 :       { .data    = account->data,
     129        2028 :         .dataend = account->data + account->meta->dlen };
     130        2028 :     int err = fd_nonce_state_versions_encode( new_state, &encode );
     131        2028 :     if( FD_UNLIKELY( err ) ) {
     132           0 :       return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR;
     133           0 :     }
     134        2028 :   } while(0);
     135             : 
     136        2028 :   return FD_EXECUTOR_INSTR_SUCCESS;
     137        2028 : }
     138             : 
     139             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L20-L70
     140             : 
     141             :    Matches Solana Labs system_instruction::advance_nonce_account */
     142             : 
     143             : static int
     144             : fd_system_program_advance_nonce_account( fd_exec_instr_ctx_t *   ctx,
     145             :                                          fd_borrowed_account_t * account,
     146        1590 :                                          ulong                   instr_acc_idx ) {
     147             : 
     148             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L25-L32 */
     149             : 
     150        1590 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( ctx->instr, instr_acc_idx ) ) ) {
     151             :     /* Max msg_sz: 52 - 2 + 45 = 95 < 127 => we can use printf */
     152          45 :     fd_log_collector_printf_dangerous_max_127( ctx,
     153          45 :       "Authorize nonce account: Account %s must be writable", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     154          45 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     155          45 :   }
     156             : 
     157             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L34 */
     158             : 
     159        1545 :   fd_nonce_state_versions_t versions[1] = {{0}};
     160        1545 :   fd_bincode_decode_ctx_t decode =
     161        1545 :     { .data    = account->const_data,
     162        1545 :       .dataend = account->const_data + account->const_meta->dlen,
     163        1545 :       .valloc  = fd_scratch_virtual() };
     164        1545 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( versions, &decode )!=FD_BINCODE_SUCCESS ) )
     165          75 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     166             : 
     167             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L35 */
     168             : 
     169        1470 :   fd_nonce_state_t * state = NULL;
     170        1470 :   switch( versions->discriminant ) {
     171         141 :   case fd_nonce_state_versions_enum_legacy:
     172         141 :     state = &versions->inner.legacy;
     173         141 :     break;
     174        1329 :   case fd_nonce_state_versions_enum_current:
     175        1329 :     state = &versions->inner.current;
     176        1329 :     break;
     177           0 :   default:
     178           0 :     __builtin_unreachable();
     179        1470 :   }
     180             : 
     181        1470 :   switch( state->discriminant ) {
     182             : 
     183        1443 :   case fd_nonce_state_enum_initialized: {
     184        1443 :     fd_nonce_data_t * data = &state->inner.initialized;
     185             : 
     186             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L37-L44 */
     187             : 
     188        1443 :     if( FD_UNLIKELY( !fd_instr_any_signed( ctx->instr, &data->authority ) ) ) {
     189             :       /* Max msg_sz: 50 - 2 + 45 = 93 < 127 => we can use printf */
     190          18 :       fd_log_collector_printf_dangerous_max_127( ctx,
     191          18 :         "Advance nonce account: Account %s must be a signer", FD_BASE58_ENC_32_ALLOCA( &data->authority ) );
     192          18 :       return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     193          18 :     }
     194             : 
     195             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L45 */
     196             : 
     197        1425 :     fd_hash_t blockhash;
     198        1425 :     do {
     199        1425 :       int err = most_recent_block_hash( ctx, &blockhash );
     200        1425 :       if( FD_UNLIKELY( err ) ) return err;
     201        1425 :     } while(0);
     202             : 
     203        1425 :     fd_hash_t next_durable_nonce;
     204        1425 :     fd_durable_nonce_from_blockhash( &next_durable_nonce, &blockhash );
     205             : 
     206             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L46-L52 */
     207             : 
     208        1425 :     if( FD_UNLIKELY( 0==memcmp( data->durable_nonce.hash, next_durable_nonce.hash, sizeof(fd_hash_t) ) ) ) {
     209          15 :       fd_log_collector_msg_literal( ctx, "Advance nonce account: nonce can only advance once per slot" );
     210          15 :       ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_BLOCKHASH_NOT_EXPIRED;
     211          15 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     212          15 :     }
     213             : 
     214             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L54-L58 */
     215             : 
     216        1410 :     fd_nonce_state_versions_t new_state = {
     217        1410 :       .discriminant = fd_nonce_state_versions_enum_current,
     218        1410 :       .inner = { .current = {
     219        1410 :         .discriminant = fd_nonce_state_enum_initialized,
     220        1410 :         .inner = { .initialized = {
     221        1410 :           .authority      = data->authority,
     222        1410 :           .durable_nonce  = next_durable_nonce,
     223        1410 :           .fee_calculator = {
     224        1410 :             .lamports_per_signature = ctx->slot_ctx->prev_lamports_per_signature
     225        1410 :           }
     226        1410 :         } }
     227        1410 :       } }
     228        1410 :     };
     229             : 
     230             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L59 */
     231             : 
     232        1410 :     do {
     233        1410 :       int err = fd_system_program_set_nonce_state( ctx, instr_acc_idx, &new_state );
     234        1410 :       if( FD_UNLIKELY( err ) ) return err;
     235        1410 :     } while(0);
     236             : 
     237             :     /* Mark this as a nonce account usage.  This prevents the account
     238             :        state from reverting in case the transaction fails. */
     239             : 
     240        1362 :     ctx->txn_ctx->nonce_accounts[ ctx->instr->acct_txn_idxs[ instr_acc_idx ] ] = 1;
     241             : 
     242        1362 :     break;
     243        1410 :   }
     244             : 
     245          27 :   case fd_nonce_state_enum_uninitialized: {
     246             :     /* Max msg_sz: 50 - 2 + 45 = 93 < 127 => we can use printf */
     247          27 :     fd_log_collector_printf_dangerous_max_127( ctx,
     248          27 :       "Advance nonce account: Account %s state is invalid", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     249          27 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     250          27 :   }
     251             : 
     252        1470 :   } /* switch */
     253             : 
     254        1362 :   return FD_EXECUTOR_INSTR_SUCCESS;
     255        1470 : }
     256             : 
     257             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L423-L441
     258             : 
     259             :    Matches Solana Labs system_processor SystemInstruction::AdvanceNonceAccount => { ... } */
     260             : 
     261             : int
     262        1746 : fd_system_program_exec_advance_nonce_account( fd_exec_instr_ctx_t * ctx ) {
     263        1746 :   int err;
     264             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L423-L441 */
     265             : 
     266        1746 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
     267          15 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     268             : 
     269             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L425-L426 */
     270             : 
     271        1731 :   uchar const             instr_acc_idx = 0;
     272        6924 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, instr_acc_idx, account ) {
     273             : 
     274             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L427-L432 */
     275             : 
     276        1731 :   fd_recent_block_hashes_t const * recent_blockhashes = NULL;
     277        1731 :   do {
     278        1731 :     err = require_acct_recent_blockhashes( ctx, 1UL, &recent_blockhashes );
     279        1731 :     if( FD_UNLIKELY( err ) ) return err;
     280        1731 :   } while(0);
     281             : 
     282        1611 :   fd_block_block_hash_entry_t const * hashes = recent_blockhashes->hashes;
     283             : 
     284             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L433-L439 */
     285             : 
     286        1611 :   if( FD_UNLIKELY( deq_fd_block_block_hash_entry_t_empty( hashes ) ) ) {
     287          21 :     fd_log_collector_msg_literal( ctx, "Advance nonce account: recent blockhash list is empty" );
     288          21 :     ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES;
     289          21 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     290          21 :   }
     291             : 
     292        1590 :   err = fd_system_program_advance_nonce_account( ctx, account, instr_acc_idx );
     293             : 
     294             :   /* Implicit drop */
     295        1731 :   } FD_BORROWED_ACCOUNT_DROP( account );
     296             : 
     297        1590 :   return err;
     298        1731 : }
     299             : 
     300             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L72-L151
     301             : 
     302             :    Matches Solana Labs system_instruction::withdraw_nonce_account */
     303             : 
     304             : static int
     305             : fd_system_program_withdraw_nonce_account( fd_exec_instr_ctx_t * ctx,
     306             :                                           ulong                 requested_lamports,
     307         534 :                                           fd_rent_t const *     rent ) {
     308             : 
     309         534 :   ulong const from_acct_idx = 0UL;
     310         534 :   ulong const to_acct_idx   = 1UL;
     311             : 
     312             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L82-L83 */
     313             : 
     314        2136 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, from_acct_idx, from ) {
     315             : 
     316             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L84-L91 */
     317             : 
     318         534 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( ctx->instr, 0 ) ) ) {
     319             :     /* Max msg_sz: 51 - 2 + 45 = 94 < 127 => we can use printf */
     320          21 :     fd_log_collector_printf_dangerous_max_127( ctx,
     321          21 :       "Withdraw nonce account: Account %s must be writable", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ 0 ] ) );
     322          21 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     323          21 :   }
     324             : 
     325             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L93 */
     326             : 
     327         513 :   fd_nonce_state_versions_t versions[1] = {{0}};
     328         513 :   fd_bincode_decode_ctx_t decode =
     329         513 :     { .data    = from->const_data,
     330         513 :       .dataend = from->const_data + from->const_meta->dlen,
     331         513 :       .valloc  = fd_scratch_virtual() };
     332         513 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( versions, &decode )!=FD_BINCODE_SUCCESS ) )
     333         111 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     334             : 
     335             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L94 */
     336             : 
     337         402 :   fd_nonce_state_t * state = NULL;
     338         402 :   switch( versions->discriminant ) {
     339         234 :   case fd_nonce_state_versions_enum_legacy:
     340         234 :     state = &versions->inner.legacy;
     341         234 :     break;
     342         168 :   case fd_nonce_state_versions_enum_current:
     343         168 :     state = &versions->inner.current;
     344         168 :     break;
     345           0 :   default:
     346           0 :     __builtin_unreachable();
     347         402 :   }
     348             : 
     349         402 :   fd_pubkey_t signer[1] = {0};
     350         402 :   switch( state->discriminant ) {
     351             : 
     352         141 :   case fd_nonce_state_enum_uninitialized: {
     353             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L95-L106 */
     354             : 
     355         141 :     if( FD_UNLIKELY( requested_lamports > from->const_meta->info.lamports ) ) {
     356             :       /* Max msg_sz: 59 - 6 + 20 + 20 = 93 < 127 => we can use printf */
     357           9 :       fd_log_collector_printf_dangerous_max_127( ctx,
     358           9 :         "Withdraw nonce account: insufficient lamports %lu, need %lu", from->const_meta->info.lamports, requested_lamports );
     359           9 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     360           9 :     }
     361             : 
     362             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L105 */
     363             : 
     364         132 :     *signer = *from->pubkey;
     365             : 
     366         132 :     break;
     367         141 :   }
     368             : 
     369         261 :   case fd_nonce_state_enum_initialized: {
     370             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L107-L132 */
     371         261 :     fd_nonce_data_t * data = &state->inner.initialized;
     372             : 
     373         261 :     if( requested_lamports == from->const_meta->info.lamports ) {
     374             :         /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L108-L117 */
     375             : 
     376             :       /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L109 */
     377             : 
     378          45 :       fd_hash_t blockhash;
     379          45 :       do {
     380          45 :         int err = most_recent_block_hash( ctx, &blockhash );
     381          45 :         if( FD_UNLIKELY( err ) ) return err;
     382          45 :       } while(0);
     383             : 
     384          45 :       fd_hash_t next_durable_nonce;
     385          45 :       fd_durable_nonce_from_blockhash( &next_durable_nonce, &blockhash );
     386             : 
     387             :       /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L110-L116 */
     388             : 
     389          45 :       if( FD_UNLIKELY( 0==memcmp( data->durable_nonce.hash, next_durable_nonce.hash, sizeof(fd_hash_t) ) ) ) {
     390           0 :         fd_log_collector_msg_literal( ctx, "Withdraw nonce account: nonce can only advance once per slot" );
     391           0 :         ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_BLOCKHASH_NOT_EXPIRED;
     392           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     393           0 :       }
     394             : 
     395             :       /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L117 */
     396             : 
     397          45 :       fd_nonce_state_versions_t new_state[1] = {{
     398          45 :         .discriminant = fd_nonce_state_versions_enum_current,
     399          45 :         .inner = { .current = {
     400          45 :           .discriminant = fd_nonce_state_enum_uninitialized
     401          45 :         } }
     402          45 :       }};
     403             : 
     404          45 :       do {
     405          45 :         int err = fd_system_program_set_nonce_state( ctx, from_acct_idx, new_state );
     406          45 :         if( FD_UNLIKELY( err ) ) return err;
     407          45 :       } while(0);
     408             : 
     409         216 :     } else {
     410             :         /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L118-L130 */
     411             : 
     412             :       /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L120 */
     413             : 
     414         216 :       ulong min_balance = fd_rent_exempt_minimum_balance( rent, from->const_meta->dlen );
     415             : 
     416         216 :       ulong amount;
     417         216 :       if( FD_UNLIKELY( __builtin_uaddl_overflow( requested_lamports, min_balance, &amount ) ) )
     418           9 :         return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     419             : 
     420             :       /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L121-L129 */
     421             : 
     422         207 :       if( FD_UNLIKELY( amount > from->const_meta->info.lamports ) ) {
     423             :         /* Max msg_sz: 59 - 6 + 20 + 20 = 93 < 127 => we can use printf */
     424          15 :         fd_log_collector_printf_dangerous_max_127( ctx,
     425          15 :           "Withdraw nonce account: insufficient lamports %lu, need %lu", from->const_meta->info.lamports, amount );
     426          15 :         return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     427          15 :       }
     428             : 
     429         207 :     }
     430             : 
     431             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L131 */
     432             : 
     433         228 :     *signer = data->authority;
     434             : 
     435         228 :     break;
     436         261 :   }
     437             : 
     438         402 :   } /* switch */
     439             : 
     440             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L135-L142 */
     441             : 
     442         360 :   if( FD_UNLIKELY( !fd_instr_any_signed( ctx->instr, signer ) ) ) {
     443             :     /* Max msg_sz: 44 - 2 + 45 = 87 < 127 => we can use printf */
     444          24 :     fd_log_collector_printf_dangerous_max_127( ctx,
     445          24 :       "Withdraw nonce account: Account %s must sign", FD_BASE58_ENC_32_ALLOCA( signer ) );
     446          24 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     447          24 :   }
     448             : 
     449             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L144 */
     450             : 
     451         336 :   do {
     452             :     /* TODO verify that account is writable before calling this API */
     453         336 :     int err = fd_account_checked_sub_lamports( ctx, from_acct_idx, requested_lamports );
     454         336 :     if( FD_UNLIKELY( err ) ) return err;
     455         336 :   } while(0);
     456             : 
     457             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L145 */
     458             : 
     459         534 :     } FD_BORROWED_ACCOUNT_DROP( from );
     460             : 
     461             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L146-L147 */
     462             : 
     463         324 :   fd_borrowed_account_t * to = NULL;
     464         324 :   do {
     465         324 :     int err = fd_instr_borrowed_account_modify_idx( ctx, to_acct_idx, 0UL, &to );
     466         324 :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
     467         324 :   } while(0);
     468             : 
     469         324 :   if( FD_UNLIKELY( !fd_borrowed_account_acquire_write( to ) ) )
     470           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED;
     471             : 
     472             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L148 */
     473             : 
     474         324 :   do {
     475         324 :     int err = fd_account_checked_add_lamports( ctx, to_acct_idx, requested_lamports );
     476         324 :     if( FD_UNLIKELY( err ) ) return err;
     477         324 :   } while(0);
     478             : 
     479             :   /* Implicit drop */
     480         300 :   fd_borrowed_account_release_write( to );
     481             : 
     482         300 :   return FD_EXECUTOR_INSTR_SUCCESS;
     483         324 : }
     484             : 
     485             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L442-L461
     486             : 
     487             :    Matches Solana Labs system_processor SystemInstruction::WithdrawNonceAccount { ... } => { ... } */
     488             : 
     489             : int
     490             : fd_system_program_exec_withdraw_nonce_account( fd_exec_instr_ctx_t * ctx,
     491        1359 :                                                ulong                 requested_lamports ) {
     492             : 
     493             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L443 */
     494             : 
     495        1359 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) )
     496          27 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     497             : 
     498             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L445-L449 */
     499             : 
     500        1332 :   fd_recent_block_hashes_t const * recent_blockhashes = NULL;
     501        1332 :   do {
     502        1332 :     int err = require_acct_recent_blockhashes( ctx, 2UL, &recent_blockhashes );
     503        1332 :     if( FD_UNLIKELY( err ) ) return err;
     504        1332 :   } while(0);
     505             : 
     506             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L450 */
     507             : 
     508         564 :   fd_rent_t const * rent = NULL;
     509         564 :   do {
     510         564 :     int err = require_acct_rent( ctx, 3UL, &rent );
     511         564 :     if( FD_UNLIKELY( err ) ) return err;
     512         564 :   } while(0);
     513             : 
     514             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L451-L460 */
     515             : 
     516         534 :   return fd_system_program_withdraw_nonce_account( ctx, requested_lamports, rent );
     517         564 : }
     518             : 
     519             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L153-L198
     520             : 
     521             :    Matches Solana Labs system_instruction::initialize_nonce_account */
     522             : 
     523             : static int
     524             : fd_system_program_initialize_nonce_account( fd_exec_instr_ctx_t *   ctx,
     525             :                                             fd_borrowed_account_t * account,
     526             :                                             ulong                   instr_acc_idx,
     527             :                                             fd_pubkey_t const *     authorized,
     528         393 :                                             fd_rent_t const *       rent ) {
     529             : 
     530             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L159-L166 */
     531             : 
     532         393 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( ctx->instr, instr_acc_idx ) ) ) {
     533             :     /* Max msg_sz: 53 - 2 + 45 = 96 < 127 => we can use printf */
     534          39 :     fd_log_collector_printf_dangerous_max_127( ctx,
     535          39 :       "Initialize nonce account: Account %s must be writable", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     536          39 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     537          39 :   }
     538             : 
     539             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L168 */
     540             : 
     541         354 :   fd_nonce_state_versions_t versions[1] = {{0}};
     542         354 :   fd_bincode_decode_ctx_t decode =
     543         354 :     { .data    = account->const_data,
     544         354 :       .dataend = account->const_data + account->const_meta->dlen,
     545         354 :       .valloc  = fd_scratch_virtual() };
     546         354 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( versions, &decode )!=FD_BINCODE_SUCCESS ) )
     547          48 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     548             : 
     549         306 :   fd_nonce_state_t * state = NULL;
     550         306 :   switch( versions->discriminant ) {
     551         129 :   case fd_nonce_state_versions_enum_legacy:
     552         129 :     state = &versions->inner.legacy;
     553         129 :     break;
     554         177 :   case fd_nonce_state_versions_enum_current:
     555         177 :     state = &versions->inner.current;
     556         177 :     break;
     557           0 :   default:
     558           0 :     __builtin_unreachable();
     559         306 :   }
     560             : 
     561         306 :   switch( state->discriminant ) {
     562             : 
     563         294 :   case fd_nonce_state_enum_uninitialized: {
     564             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L169-L188 */
     565             : 
     566             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L170 */
     567             : 
     568         294 :     ulong min_balance = fd_rent_exempt_minimum_balance( rent, account->const_meta->dlen );
     569             : 
     570             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L171-L179 */
     571             : 
     572         294 :     if( FD_UNLIKELY( account->const_meta->info.lamports < min_balance ) ) {
     573             :       /* Max msg_sz: 61 - 6 + 20 + 20 = 95 < 127 => we can use printf */
     574          12 :       fd_log_collector_printf_dangerous_max_127( ctx,
     575          12 :         "Initialize nonce account: insufficient lamports %lu, need %lu", account->const_meta->info.lamports, min_balance );
     576          12 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
     577          12 :     }
     578             : 
     579             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L180 */
     580             : 
     581         282 :     fd_hash_t blockhash;
     582         282 :     do {
     583         282 :       int err = most_recent_block_hash( ctx, &blockhash );
     584         282 :       if( FD_UNLIKELY( err ) ) return err;
     585         282 :     } while(0);
     586             : 
     587         282 :     fd_hash_t durable_nonce;
     588         282 :     fd_durable_nonce_from_blockhash( &durable_nonce, &blockhash );
     589             : 
     590             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L181-L186 */
     591             : 
     592         282 :     fd_nonce_state_versions_t new_state = {
     593         282 :       .discriminant = fd_nonce_state_versions_enum_current,
     594         282 :       .inner = { .current = {
     595         282 :         .discriminant = fd_nonce_state_enum_initialized,
     596         282 :         .inner = { .initialized = {
     597         282 :           .authority      = *authorized,
     598         282 :           .durable_nonce  = durable_nonce,
     599         282 :           .fee_calculator = {
     600         282 :             .lamports_per_signature = ctx->slot_ctx->prev_lamports_per_signature
     601         282 :           }
     602         282 :         } }
     603         282 :       } }
     604         282 :     };
     605             : 
     606             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L187 */
     607             : 
     608         282 :     do {
     609         282 :       int err = fd_system_program_set_nonce_state( ctx, instr_acc_idx, &new_state );
     610         282 :       if( FD_UNLIKELY( err ) ) return err;
     611         282 :     } while(0);
     612             : 
     613         258 :     break;
     614         282 :   }
     615             : 
     616         258 :   case fd_nonce_state_enum_initialized: {
     617             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L189-L196 */
     618             : 
     619             :     /* Max msg_sz: 53 - 2 + 45 = 96 < 127 => we can use printf */
     620          12 :     fd_log_collector_printf_dangerous_max_127( ctx,
     621          12 :       "Initialize nonce account: Account %s state is invalid", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     622             : 
     623          12 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     624          12 :   }
     625             : 
     626         306 :   } /* switch */
     627             : 
     628         258 :   return FD_EXECUTOR_INSTR_SUCCESS;
     629         306 : }
     630             : 
     631             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L462-L481
     632             : 
     633             :    Matches Solana Labs system_processor SystemInstruction::InitializeNonceAccount { ... } => { ... } */
     634             : 
     635             : int
     636             : fd_system_program_exec_initialize_nonce_account( fd_exec_instr_ctx_t * ctx,
     637         582 :                                                  fd_pubkey_t const *   authorized ) {
     638         582 :   int err;
     639             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L463 */
     640             : 
     641         582 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
     642          15 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     643             : 
     644             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L464-L465 */
     645             : 
     646         567 :   uchar const             instr_acc_idx = 0;
     647        2268 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, instr_acc_idx, account ) {
     648             : 
     649             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L466-L471 */
     650             : 
     651         567 :   fd_recent_block_hashes_t const * recent_blockhashes = NULL;
     652         567 :   do {
     653         567 :     err = require_acct_recent_blockhashes( ctx, 1UL, &recent_blockhashes );
     654         567 :     if( FD_UNLIKELY( err ) ) return err;
     655         567 :   } while(0);
     656             : 
     657         441 :   fd_block_block_hash_entry_t const * hashes = recent_blockhashes->hashes;
     658             : 
     659             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L472-L478 */
     660             : 
     661         441 :   if( FD_UNLIKELY( deq_fd_block_block_hash_entry_t_empty( hashes ) ) ) {
     662          18 :     fd_log_collector_msg_literal( ctx, "Initialize nonce account: recent blockhash list is empty" );
     663          18 :     ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES;
     664          18 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     665          18 :   }
     666             : 
     667             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L479 */
     668             : 
     669         423 :   fd_rent_t const * rent = NULL;
     670         423 :   do {
     671         423 :     err = require_acct_rent( ctx, 2UL, &rent );
     672         423 :     if( FD_UNLIKELY( err ) ) return err;
     673         423 :   } while(0);
     674             : 
     675             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L480 */
     676             : 
     677         393 :   err = fd_system_program_initialize_nonce_account( ctx, account, instr_acc_idx, authorized, rent );
     678             : 
     679             :   /* Implicit drop */
     680         567 :   } FD_BORROWED_ACCOUNT_DROP( account );
     681             : 
     682         393 :   return err;
     683         567 : }
     684             : 
     685             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L200-L236
     686             : 
     687             :    Matches Solana Labs system_instruction::authorize_nonce_account */
     688             : 
     689             : static int
     690             : fd_system_program_authorize_nonce_account( fd_exec_instr_ctx_t *   ctx,
     691             :                                            fd_borrowed_account_t * account,
     692             :                                            ulong                   instr_acc_idx,
     693        1215 :                                            fd_pubkey_t const *     nonce_authority ) {
     694             : 
     695             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L206-L213 */
     696             : 
     697        1215 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( ctx->instr, instr_acc_idx ) ) ) {
     698             :     /* Max msg_sz: 52 - 2 + 45 = 95 < 127 => we can use printf */
     699         258 :     fd_log_collector_printf_dangerous_max_127( ctx,
     700         258 :       "Authorize nonce account: Account %s must be writable", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     701         258 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     702         258 :   }
     703             : 
     704             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L214-L215 */
     705             : 
     706         957 :   fd_nonce_state_versions_t versions[1] = {{0}};
     707         957 :   fd_bincode_decode_ctx_t decode =
     708         957 :     { .data    = account->const_data,
     709         957 :       .dataend = account->const_data + account->const_meta->dlen,
     710         957 :       .valloc  = fd_scratch_virtual() };
     711         957 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( versions, &decode )!=FD_BINCODE_SUCCESS ) )
     712         492 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     713             : 
     714             :   /* Inlining solana_program::nonce::state::Versions::authorize
     715             :      https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L76-L102 */
     716             : 
     717             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L81 */
     718             : 
     719         465 :   fd_nonce_state_t * state = NULL;
     720         465 :   switch( versions->discriminant ) {
     721         162 :   case fd_nonce_state_versions_enum_legacy:
     722         162 :     state = &versions->inner.legacy;
     723         162 :     break;
     724         303 :   case fd_nonce_state_versions_enum_current:
     725         303 :     state = &versions->inner.current;
     726         303 :     break;
     727           0 :   default:
     728           0 :     __builtin_unreachable();
     729         465 :   }
     730             : 
     731             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L81-L84 */
     732             : 
     733         465 :   if( FD_UNLIKELY( state->discriminant != fd_nonce_state_enum_initialized ) ) {
     734             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L219-L226 */
     735             : 
     736             :     /* Max msg_sz: 52 - 2 + 45 = 95 < 127 => we can use printf */
     737          33 :     fd_log_collector_printf_dangerous_max_127( ctx,
     738          33 :       "Authorize nonce account: Account %s state is invalid", FD_BASE58_ENC_32_ALLOCA( &ctx->instr->acct_pubkeys[ instr_acc_idx ] ) );
     739             : 
     740          33 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     741          33 :   }
     742             : 
     743         432 :   fd_nonce_data_t * data = &state->inner.initialized;
     744             : 
     745             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L85-L89 */
     746             : 
     747         432 :   if( FD_UNLIKELY( !fd_instr_any_signed( ctx->instr, &data->authority ) ) ) {
     748             :     /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L227-L234 */
     749             :     /* Max msg_sz: 45 - 2 + 45 = 88 < 127 => we can use printf */
     750         162 :     fd_log_collector_printf_dangerous_max_127( ctx,
     751         162 :       "Authorize nonce account: Account %s must sign", FD_BASE58_ENC_32_ALLOCA( &data->authority ) );
     752         162 :     return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     753         162 :   }
     754             : 
     755             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L90-L95 */
     756             : 
     757         270 :   fd_nonce_state_t new_state[1] = {{
     758         270 :     .discriminant = fd_nonce_state_enum_initialized,
     759         270 :     .inner = { .initialized = {
     760         270 :       .authority      = *nonce_authority,
     761         270 :       .durable_nonce  = data->durable_nonce,
     762         270 :       .fee_calculator = data->fee_calculator
     763         270 :     } }
     764         270 :   }};
     765             : 
     766             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L96-L101 */
     767             : 
     768         270 :   fd_nonce_state_versions_t new_versioned[1] = {{0}};
     769         270 :   new_versioned->discriminant = versions->discriminant;
     770         270 :   switch( versions->discriminant ) {
     771         105 :   case fd_nonce_state_versions_enum_legacy:
     772         105 :     new_versioned->inner.legacy = *new_state;
     773         105 :     break;
     774         165 :   case fd_nonce_state_versions_enum_current:
     775         165 :     new_versioned->inner.current = *new_state;
     776         165 :     break;
     777           0 :   default:
     778           0 :     __builtin_unreachable();
     779         270 :   }
     780             : 
     781             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L218 */
     782             : 
     783         270 :   do {
     784         270 :     int err = fd_system_program_set_nonce_state( ctx, instr_acc_idx, new_versioned );
     785         270 :     if( FD_UNLIKELY( err ) ) return err;
     786         270 :   } while(0);
     787             : 
     788         222 :   return FD_EXECUTOR_INSTR_SUCCESS;
     789         270 : }
     790             : 
     791             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L482-L487
     792             : 
     793             :    Matches Solana Labs system_processor SystemInstruction::AuthorizeNonceAccount { ... } => { ... } */
     794             : 
     795             : int
     796             : fd_system_program_exec_authorize_nonce_account( fd_exec_instr_ctx_t * ctx,
     797        1221 :                                                 fd_pubkey_t const *   nonce_authority ) {
     798        1221 :   int err;
     799             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L483 */
     800             : 
     801        1221 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
     802           6 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     803             : 
     804             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L484-L485 */
     805             : 
     806        4860 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, 0, account ) {
     807             : 
     808             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L486 */
     809             : 
     810        1215 :   err = fd_system_program_authorize_nonce_account( ctx, account, 0UL, nonce_authority );
     811             : 
     812             :   /* Implicit drop */
     813        1215 :   } FD_BORROWED_ACCOUNT_DROP( account );
     814             : 
     815        1215 :   return err;
     816        1215 : }
     817             : 
     818             : /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L488-L503
     819             : 
     820             :    Matches Solana Labs system_processor SystemInstruction::UpgradeNonceAccount { ... } => { ... } */
     821             : 
     822             : int
     823         612 : fd_system_program_exec_upgrade_nonce_account( fd_exec_instr_ctx_t * ctx ) {
     824             : 
     825         612 :   ulong const nonce_acct_idx = 0UL;
     826             : 
     827             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L489 */
     828             : 
     829         612 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
     830           6 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     831             : 
     832             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L490-L491 */
     833             : 
     834        2424 :   FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, nonce_acct_idx, account ) {
     835             : 
     836             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L492-L494 */
     837             : 
     838         606 :   if( FD_UNLIKELY( 0!=memcmp( account->const_meta->info.owner, fd_solana_system_program_id.key, sizeof(fd_pubkey_t) ) ) )
     839         114 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
     840             : 
     841             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L495-L497 */
     842             : 
     843         492 :   if( FD_UNLIKELY( !fd_instr_acc_is_writable_idx( ctx->instr, 0 ) ) )
     844          21 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     845             : 
     846             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L498 */
     847             : 
     848         471 :   fd_nonce_state_versions_t versions[1] = {{0}};
     849         471 :   fd_bincode_decode_ctx_t decode =
     850         471 :     { .data    = account->const_data,
     851         471 :       .dataend = account->const_data + account->const_meta->dlen,
     852         471 :       .valloc  = fd_scratch_virtual() };
     853         471 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( versions, &decode )!=FD_BINCODE_SUCCESS ) )
     854         258 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     855             : 
     856             :   /* Inlining solana_program::nonce::state::Versions::upgrade
     857             :      https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/nonce/state/mod.rs#L55-L73 */
     858             : 
     859         213 :   if( FD_UNLIKELY( versions->discriminant != fd_nonce_state_versions_enum_legacy ) )
     860          30 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     861             : 
     862         183 :   fd_nonce_state_t * state = &versions->inner.legacy;
     863         183 :   if( FD_UNLIKELY( state->discriminant != fd_nonce_state_enum_initialized ) )
     864          24 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     865             : 
     866         159 :   fd_durable_nonce_from_blockhash( &state->inner.initialized.durable_nonce, &state->inner.initialized.durable_nonce );
     867             : 
     868             :   /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L501 */
     869             : 
     870         159 :   fd_nonce_state_versions_t new_state[1] = {{
     871         159 :     .discriminant = fd_nonce_state_versions_enum_current,
     872         159 :     .inner = { .current = *state }
     873         159 :   }};
     874             : 
     875         159 :   do {
     876         159 :     int err = fd_system_program_set_nonce_state( ctx, nonce_acct_idx, new_state );
     877         159 :     if( FD_UNLIKELY( err ) ) return err;
     878         159 :   } while(0);
     879             : 
     880             :   /* Implicit drop */
     881         606 :   } FD_BORROWED_ACCOUNT_DROP( account );
     882             : 
     883         150 :   return FD_EXECUTOR_INSTR_SUCCESS;
     884         606 : }
     885             : 
     886             : int
     887             : fd_load_nonce_account( fd_exec_txn_ctx_t const *   txn_ctx,
     888             :                        fd_nonce_state_versions_t * state,
     889             :                        fd_valloc_t                 valloc,
     890           0 :                        int *                       perr ) {
     891             : 
     892           0 :   *perr = 0;
     893             : 
     894           0 :   fd_txn_t const *      txn_descriptor = txn_ctx->txn_descriptor;
     895           0 :   fd_rawtxn_b_t const * txn_raw        = txn_ctx->_txn_raw;
     896             : 
     897           0 :   if( txn_descriptor->instr_cnt == 0 ) {
     898           0 :     *perr = FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     899           0 :     return 0;
     900           0 :   }
     901             : 
     902           0 :   fd_txn_instr_t const * txn_instr = &txn_descriptor->instr[0];
     903             : 
     904           0 :   if( FD_UNLIKELY( txn_instr->program_id >= txn_descriptor->acct_addr_cnt ) )
     905           0 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     906             : 
     907           0 :   fd_acct_addr_t const * tx_accs = fd_txn_get_acct_addrs( txn_descriptor, txn_raw->raw );
     908           0 :   fd_acct_addr_t const * prog_id = tx_accs + txn_instr->program_id;
     909             : 
     910           0 :   if( memcmp( prog_id->b, fd_solana_system_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     911           0 :     return 0;
     912           0 :   }
     913             : 
     914           0 :   uchar const * instr_data = fd_txn_get_instr_data( txn_instr, txn_raw->raw );
     915           0 :   uchar const * instr_acct_idxs = fd_txn_get_instr_accts( txn_instr, txn_raw->raw );
     916             : 
     917           0 :   if( FD_UNLIKELY(
     918           0 :       txn_instr->data_sz != 4UL ||
     919           0 :       FD_LOAD( uint, instr_data ) != (uint)fd_system_program_instruction_enum_advance_nonce_account ) ) {
     920           0 :     *perr = FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     921           0 :     return 0;
     922           0 :   }
     923             : 
     924           0 :   if( FD_UNLIKELY( ( txn_descriptor->acct_addr_cnt < 1 ) |
     925           0 :                    ( txn_instr->acct_cnt < 1           ) ) ) {
     926           0 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     927           0 :   }  
     928           0 :   if( FD_UNLIKELY( instr_acct_idxs[0] >= txn_descriptor->acct_addr_cnt ) ) {
     929           0 :     *perr = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
     930           0 :     return 0;
     931           0 :   }
     932             : 
     933           0 :   fd_acct_addr_t const * me = &tx_accs[ instr_acct_idxs[0] ];
     934             : 
     935             :   // https://github.com/firedancer-io/solana/blob/ffd63324f988e1b2151dab34983c71d6ff4087f6/runtime/src/nonce_keyed_account.rs#L66
     936             : 
     937           0 :   FD_BORROWED_ACCOUNT_DECL(me_rec);
     938           0 :   int err = fd_acc_mgr_view( txn_ctx->acc_mgr, txn_ctx->funk_txn, (fd_pubkey_t const *)me, me_rec );
     939           0 :   if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) {
     940             : 
     941           0 :     *perr = FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     942           0 :     return 0;
     943           0 :   }
     944             : 
     945           0 :   fd_bincode_decode_ctx_t decode = {
     946           0 :     .data    = me_rec->const_data,
     947           0 :     .dataend = me_rec->const_data + me_rec->const_meta->dlen,
     948           0 :     .valloc  = valloc
     949           0 :   };
     950             : 
     951           0 :   if( fd_nonce_state_versions_decode( state, &decode ) ) {
     952           0 :     *perr = FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     953           0 :     return 0;
     954           0 :   }
     955             : 
     956           0 :   return 1;
     957           0 : }
     958             : 
     959             : /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/runtime/src/bank.rs#L3529-L3554 */
     960             : /* The age of a transaction is valid under two conditions. The first is that 
     961             :    the transactions blockhash is a recent blockhash (within 151) in the block
     962             :    hash queue. The other condition is that the transaction contains a valid 
     963             :    nonce account. This is the case under several conditions. If neither 
     964             :    condition is met then the transaction is invalid.
     965             :    Note: We check 151 and not 150 due to a known bug in agave. */
     966             : int
     967        7248 : fd_check_transaction_age( fd_exec_txn_ctx_t const * txn_ctx ) {
     968        7248 :   fd_block_hash_queue_t hash_queue         = txn_ctx->slot_ctx->slot_bank.block_hash_queue;
     969        7248 :   fd_hash_t *           last_blockhash     = hash_queue.last_hash;
     970             : 
     971             :   /* check_transaction_age */
     972        7248 :   fd_hash_t   next_durable_nonce   = {0};
     973        7248 :   fd_durable_nonce_from_blockhash( &next_durable_nonce, last_blockhash );
     974        7248 :   ushort      recent_blockhash_off = txn_ctx->txn_descriptor->recent_blockhash_off;
     975        7248 :   fd_hash_t * recent_blockhash     = (fd_hash_t *)((uchar *)txn_ctx->_txn_raw->raw + recent_blockhash_off);
     976             : 
     977             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/runtime/src/bank.rs#L3538-L3542 */
     978             :   /* get_hash_info_if_valid. Check 151 hashes from the block hash queue and its
     979             :      age to see if it is valid. */
     980             : 
     981        7248 :   if( fd_executor_is_blockhash_valid_for_age( &hash_queue, recent_blockhash, FD_RECENT_BLOCKHASHES_MAX_ENTRIES ) ) {
     982        4755 :     return FD_RUNTIME_EXECUTE_SUCCESS;
     983        4755 :   }
     984             : 
     985             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/runtime/src/bank.rs#L3622-L3633 */
     986             :   /* check_and_load_message_nonce_account */
     987        2493 :   if( FD_UNLIKELY( !memcmp( &next_durable_nonce, recent_blockhash, sizeof(fd_hash_t) ) ) ) { /* nonce_is_advanceable == false  */
     988           0 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
     989           0 :   }
     990             : 
     991             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/runtime/src/bank.rs#L3603-L3620*/
     992             :   /* load_message_nonce_account */
     993             : 
     994             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/sdk/program/src/message/sanitized.rs#L345-L371 */
     995             :   /* get_durable_nonce */
     996        2493 :   if( FD_UNLIKELY( !txn_ctx->txn_descriptor->instr_cnt ) ) {
     997         483 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
     998         483 :   }
     999             :   /* Check the first instruction (nonce instruction) to see if the program id
    1000             :      is the system program. Also make sure that it is an advance nonce account
    1001             :      instruction. Finally make sure that the first insutrction account is
    1002             :      writeable; if it is, then that account is a durable nonce account. */
    1003        2010 :   fd_txn_instr_t const * txn_instr = &txn_ctx->txn_descriptor->instr[0];
    1004        2010 :   fd_acct_addr_t const * tx_accs = fd_txn_get_acct_addrs( txn_ctx->txn_descriptor, txn_ctx->_txn_raw->raw );
    1005        2010 :   fd_acct_addr_t const * prog_id = tx_accs + txn_instr->program_id;
    1006        2010 :   if( FD_UNLIKELY( memcmp( prog_id->b, fd_solana_system_program_id.key, sizeof( fd_pubkey_t ) ) ) ) {
    1007         354 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1008         354 :   }
    1009        1656 :   uchar const * instr_data  = fd_txn_get_instr_data( txn_instr, txn_ctx->_txn_raw->raw );
    1010        1656 :   uchar const * instr_accts = fd_txn_get_instr_accts( txn_instr, txn_ctx->_txn_raw->raw );
    1011             : 
    1012             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/sdk/program/src/message/sanitized.rs#L356-L358 */
    1013        1656 :   if( FD_UNLIKELY( txn_instr->data_sz<4UL || FD_LOAD( uint, instr_data ) != 
    1014        1656 :                    (uint)fd_system_program_instruction_enum_advance_nonce_account ) ) {
    1015          12 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1016          12 :   }
    1017        1644 :   if( FD_UNLIKELY( !fd_txn_account_is_writable_idx( txn_ctx, instr_accts[0] ) ) ) {
    1018          21 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1019          21 :   }
    1020             : 
    1021        1623 :   FD_BORROWED_ACCOUNT_DECL( durable_nonce_rec );
    1022        1623 :   int err = fd_acc_mgr_view( txn_ctx->acc_mgr, txn_ctx->slot_ctx->funk_txn, &txn_ctx->accounts[ instr_accts[0] ], durable_nonce_rec );
    1023        1623 :   if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
    1024           3 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1025           3 :   }
    1026             : 
    1027             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/sdk/src/nonce_account.rs#L28-L42 */
    1028             :   /* verify_nonce_account */  
    1029        1620 :   uchar const * owner_pubkey = durable_nonce_rec->const_meta->info.owner;
    1030        1620 :   if( FD_UNLIKELY( memcmp( owner_pubkey, fd_solana_system_program_id.key, sizeof( fd_pubkey_t ) ) ) ) {
    1031           3 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1032           3 :   }
    1033             : 
    1034        1617 :   fd_bincode_decode_ctx_t decode = {
    1035        1617 :     .data    = durable_nonce_rec->const_data,
    1036        1617 :     .dataend = durable_nonce_rec->const_data + durable_nonce_rec->const_meta->dlen,
    1037        1617 :     .valloc  = fd_scratch_virtual()
    1038        1617 :   };
    1039             : 
    1040        1617 :   fd_nonce_state_versions_t state = {0};
    1041        1617 :   if( FD_UNLIKELY( fd_nonce_state_versions_decode( &state, &decode ) ) ) {
    1042         120 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1043         120 :   }
    1044             : 
    1045             :   /* https://github.com/anza-xyz/agave/blob/16de8b75ebcd57022409b422de557dd37b1de8db/sdk/program/src/nonce/state/mod.rs#L36-L53 */
    1046             :   /* verify_recent_blockhash. Thjis checks that the decoded nonce record is
    1047             :      not a legacy nonce nor uninitialized. If this is the case, then we can
    1048             :      verify by comparing the decoded durable nonce to the recent blockhash */
    1049        1497 :   if( FD_UNLIKELY( fd_nonce_state_versions_is_legacy( &state ) ) ) {
    1050           3 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1051           3 :   }
    1052             : 
    1053        1494 :   fd_nonce_state_t nonce_state = state.inner.current;
    1054        1494 :   if( FD_UNLIKELY( fd_nonce_state_is_uninitialized( &nonce_state ) ) ) {
    1055           3 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1056           3 :   }
    1057             : 
    1058        1491 :   if( FD_UNLIKELY( memcmp( &nonce_state.inner.initialized.durable_nonce, recent_blockhash, sizeof(fd_hash_t) ) ) ) {
    1059          21 :     return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1060          21 :   }
    1061             : 
    1062             :   /* Finally check that the nonce is authorized by seeing if any accounts in 
    1063             :      the nonce instruction are signers. This is a successful exit case. */
    1064        4512 :   for( ushort i=0; i<txn_instr->acct_cnt; ++i ) {
    1065        4497 :     if( fd_txn_is_signer( txn_ctx->txn_descriptor, (int)instr_accts[i] ) ) {
    1066        3240 :       if( !memcmp( &txn_ctx->accounts[ instr_accts[i] ], &state.inner.current.inner.initialized.authority, sizeof( fd_pubkey_t ) ) ) {
    1067        1455 :         return FD_RUNTIME_EXECUTE_SUCCESS;
    1068        1455 :       }
    1069        3240 :     }
    1070        4497 :   }
    1071             :   /* This means that the blockhash was not found */
    1072          15 :   return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1073             : 
    1074        1470 : }

Generated by: LCOV version 1.14