LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_system_program.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 234 315 74.3 %
Date: 2026-10-22 18:10:43 Functions: 7 455 1.5 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_program_fd_system_program_h
       2             : #define HEADER_fd_src_flamenco_runtime_program_fd_system_program_h
       3             : 
       4             : /* fd_system_program.h provides hand-written types and zero-copy
       5             :    parsers for Solana's SystemInstruction enum, plus entrypoints for
       6             :    the system program.
       7             : 
       8             :    The decoder produces pointers into the caller-owned instruction
       9             :    buffer for variable-length fields (seeds).  Callers must keep the
      10             :    instruction buffer alive for the lifetime of the decoded struct.
      11             : 
      12             :    https://github.com/anza-xyz/solana-sdk/blob/system-interface%40v3.0.0/system-interface/src/instruction.rs#L92-L299 */
      13             : 
      14             : #include "../../fd_flamenco_base.h"
      15             : #include "../../../ballet/utf8/fd_utf8.h"
      16             : #include "../../accdb/fd_accdb.h"
      17             : #include "../../../ballet/txn/fd_txn.h"
      18             : 
      19             : /* Custom error types */
      20             : 
      21         280 : #define FD_SYSTEM_PROGRAM_ERR_ACCT_ALREADY_IN_USE              (0)  /* SystemError::AccountAlreadyInUse */
      22          21 : #define FD_SYSTEM_PROGRAM_ERR_RESULT_WITH_NEGATIVE_LAMPORTS    (1)  /* SystemError::ResultWithNegativeLamports */
      23             : #define FD_SYSTEM_PROGRAM_ERR_INVALID_PROGRAM_ID               (2)  /* SystemError::InvalidProgramId */
      24          15 : #define FD_SYSTEM_PROGRAM_ERR_INVALID_ACCT_DATA_LEN            (3)  /* SystemError::InvalidAccountDataLength */
      25             : #define FD_SYSTEM_PROGRAM_ERR_MAX_SEED_LEN_EXCEEDED            (4)  /* SystemError::MaxSeedLengthExceeded */
      26         512 : #define FD_SYSTEM_PROGRAM_ERR_ADDR_WITH_SEED_MISMATCH          (5)  /* SystemError::AddressWithSeedMismatch */
      27          15 : #define FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES      (6)  /* SystemError::NonceNoRecentBlockhashes */
      28           0 : #define FD_SYSTEM_PROGRAM_ERR_NONCE_BLOCKHASH_NOT_EXPIRED      (7)  /* SystemError::NonceBlockhashNotExpired */
      29             : #define FD_SYSTEM_PROGRAM_ERR_NONCE_UNEXPECTED_BLOCKHASH_VALUE (8)  /* SystemError::NonceUnexpectedBlockhashValue */
      30             : 
      31          21 : #define FD_SYSTEM_PROGRAM_NONCE_DLEN (80UL)
      32             : 
      33             : /* Nonce account state bincode wire format (must match Agave byte-for-byte).
      34             : 
      35             :    https://github.com/anza-xyz/solana-sdk/blob/nonce%40v3.0.0/nonce/src/versions.rs
      36             :    https://github.com/anza-xyz/solana-sdk/blob/nonce%40v3.0.0/nonce/src/state.rs
      37             : 
      38             :    Outer enum `Versions` (4-byte u32 LE discriminant):
      39             :      0 = Legacy(Box<State>)
      40             :      1 = Current(Box<State>)
      41             :    Inner enum `State` (4-byte u32 LE discriminant):
      42             :      0 = Uninitialized       (no payload; total wire size = 8)
      43             :      1 = Initialized(Data)   (payload = 72 bytes; total wire size = 80)
      44             :    Data struct (72 bytes fixed):
      45             :      pubkey authority[32] | hash durable_nonce[32] | u64 lamports_per_signature
      46             : 
      47             :    Agave uses bincode 1.3.3 `DefaultOptions::with_fixint_encoding().
      48             :    allow_trailing_bytes()` via the top-level `bincode::deserialize` helper
      49             :    (TransactionContext::get_state).  Decoders must therefore accept trailing
      50             :    bytes beyond the parsed region. */
      51             : 
      52             : #define FD_NONCE_VERSION_LEGACY         (0U)
      53        1419 : #define FD_NONCE_VERSION_CURRENT        (1U)
      54             : 
      55        1022 : #define FD_NONCE_STATE_UNINITIALIZED    (0U)
      56        8396 : #define FD_NONCE_STATE_INITIALIZED      (1U)
      57             : 
      58          25 : #define FD_NONCE_STATE_UNINITIALIZED_SZ (8UL)
      59        1741 : #define FD_NONCE_STATE_INITIALIZED_SZ   (80UL)
      60             : 
      61             : /* https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L49-L53 */
      62           9 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN (-1)
      63        6364 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_SYSTEM  (0)
      64          21 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_NONCE   (1)
      65             : 
      66             : /* SystemInstruction discriminants (wire-format u32 values). */
      67             : 
      68        2932 : #define FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT               (0U)
      69        1207 : #define FD_SYSTEM_PROGRAM_INSTR_ASSIGN                       (1U)
      70        1310 : #define FD_SYSTEM_PROGRAM_INSTR_TRANSFER                     (2U)
      71        1067 : #define FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED     (3U)
      72        2215 : #define FD_SYSTEM_PROGRAM_INSTR_ADVANCE_NONCE_ACCOUNT        (4U)
      73        1460 : #define FD_SYSTEM_PROGRAM_INSTR_WITHDRAW_NONCE_ACCOUNT       (5U)
      74        1049 : #define FD_SYSTEM_PROGRAM_INSTR_INITIALIZE_NONCE_ACCOUNT     (6U)
      75        1492 : #define FD_SYSTEM_PROGRAM_INSTR_AUTHORIZE_NONCE_ACCOUNT      (7U)
      76        1748 : #define FD_SYSTEM_PROGRAM_INSTR_ALLOCATE                     (8U)
      77         650 : #define FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED           (9U)
      78        1032 : #define FD_SYSTEM_PROGRAM_INSTR_ASSIGN_WITH_SEED             (10U)
      79        1482 : #define FD_SYSTEM_PROGRAM_INSTR_TRANSFER_WITH_SEED           (11U)
      80        1016 : #define FD_SYSTEM_PROGRAM_INSTR_UPGRADE_NONCE_ACCOUNT        (12U)
      81        1347 : #define FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND (13U)
      82             : 
      83             : /* Per-variant structs. */
      84             : 
      85             : struct create_account {
      86             :   ulong       lamports;
      87             :   ulong       space;
      88             :   fd_pubkey_t owner;
      89             : };
      90             : typedef struct create_account create_account_t;
      91             : 
      92             : struct create_account_with_seed {
      93             :   fd_pubkey_t   base;
      94             :   uchar const * seed; /* points into caller-owned instr_data */
      95             :   ulong         seed_len;
      96             :   ulong         lamports;
      97             :   ulong         space;
      98             :   fd_pubkey_t   owner;
      99             : };
     100             : typedef struct create_account_with_seed create_account_with_seed_t;
     101             : 
     102             : struct allocate_with_seed {
     103             :   fd_pubkey_t   base;
     104             :   uchar const * seed;
     105             :   ulong         seed_len;
     106             :   ulong         space;
     107             :   fd_pubkey_t   owner;
     108             : };
     109             : typedef struct allocate_with_seed allocate_with_seed_t;
     110             : 
     111             : struct assign_with_seed {
     112             :   fd_pubkey_t   base;
     113             :   uchar const * seed;
     114             :   ulong         seed_len;
     115             :   fd_pubkey_t   owner;
     116             : };
     117             : typedef struct assign_with_seed assign_with_seed_t;
     118             : 
     119             : struct transfer_with_seed {
     120             :   ulong         lamports;
     121             :   uchar const * from_seed;
     122             :   ulong         from_seed_len;
     123             :   fd_pubkey_t   from_owner;
     124             : };
     125             : typedef struct transfer_with_seed transfer_with_seed_t;
     126             : 
     127             : /* Discriminated union. */
     128             : 
     129             : union fd_system_program_instruction_inner {
     130             :   create_account_t           create_account;
     131             :   fd_pubkey_t                assign;
     132             :   ulong                      transfer;
     133             :   create_account_with_seed_t create_account_with_seed;
     134             :   ulong                      withdraw_nonce_account;
     135             :   fd_pubkey_t                initialize_nonce_account;
     136             :   fd_pubkey_t                authorize_nonce_account;
     137             :   ulong                      allocate;
     138             :   allocate_with_seed_t       allocate_with_seed;
     139             :   assign_with_seed_t         assign_with_seed;
     140             :   transfer_with_seed_t       transfer_with_seed;
     141             :   create_account_t           create_account_allow_prefund;
     142             : };
     143             : typedef union fd_system_program_instruction_inner fd_system_program_instruction_inner_t;
     144             : 
     145             : struct fd_system_program_instruction {
     146             :   uint                                  discriminant;
     147             :   fd_system_program_instruction_inner_t inner;
     148             : };
     149             : typedef struct fd_system_program_instruction fd_system_program_instruction_t;
     150             : 
     151             : /* fd_system_program_instruction_decode reads a bincode-encoded
     152             :    SystemInstruction from [data, data+data_sz).  Variable-length seed
     153             :    fields in the output point directly into `data`, so the caller must
     154             :    keep that buffer alive.  Returns 0 on success, -1 on decode error.
     155             : 
     156             :    Only bytes up to FD_TXN_MTU_V0 are parsed, the rest are discarded,
     157             :    matching Agave's limited_deserialize(data, PACKET_DATA_SIZE). */
     158             : 
     159             : static inline int
     160             : fd_system_program_instruction_decode( fd_system_program_instruction_t * out,
     161             :                                       uchar const *                     data,
     162       10666 :                                       ulong                             data_sz ) {
     163       10666 :   uchar const * _payload    = data;
     164             :   /* limited_deserialize(data, PACKET_DATA_SIZE)
     165             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/system/src/system_processor.rs#L324 */
     166       10666 :   ulong const   _payload_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
     167       10666 :   ulong         _i          = 0UL;
     168             : 
     169       27089 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     170       24980 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     171       26999 : # define INC( n )        (_i += (ulong)(n))
     172       10666 : # define CURSOR          (_payload+_i)
     173             : 
     174       10666 :   CHECK_LEFT( 4UL );
     175       10278 :   uint disc = FD_LOAD( uint, CURSOR ); INC( 4UL );
     176       10278 :   out->discriminant = disc;
     177             : 
     178       10278 :   switch( disc ) {
     179             : 
     180         716 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT:
     181         913 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     182         913 :     create_account_t * ca =
     183         913 :         (disc==FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT)
     184         913 :           ? &out->inner.create_account
     185         913 :           : &out->inner.create_account_allow_prefund;
     186         913 :     CHECK_LEFT( 48UL );
     187         767 :     ca->lamports = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     188         767 :     ca->space    = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     189         767 :     fd_memcpy( ca->owner.key, CURSOR, 32UL ); INC( 32UL );
     190         767 :     return 0;
     191         913 :   }
     192             : 
     193         692 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN: {
     194         692 :     CHECK_LEFT( 32UL );
     195         650 :     fd_memcpy( out->inner.assign.key, CURSOR, 32UL ); INC( 32UL );
     196         650 :     return 0;
     197         692 :   }
     198             : 
     199         788 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER: {
     200         788 :     CHECK_LEFT( 8UL );
     201         781 :     out->inner.transfer = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     202         781 :     return 0;
     203         788 :   }
     204             : 
     205         567 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
     206         567 :     create_account_with_seed_t * cs = &out->inner.create_account_with_seed;
     207         567 :     CHECK_LEFT( 32UL ); fd_memcpy( cs->base.key, CURSOR, 32UL ); INC( 32UL );
     208         554 :     CHECK_LEFT( 8UL );  cs->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     209         550 :     CHECK_LEFT( cs->seed_len );
     210         535 :     if( cs->seed_len ) {
     211         515 :       CHECK( fd_utf8_verify( (char const *)CURSOR, cs->seed_len ) );
     212         492 :     }
     213         512 :     cs->seed = CURSOR; INC( cs->seed_len );
     214         512 :     CHECK_LEFT( 48UL );
     215         500 :     cs->lamports = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     216         500 :     cs->space    = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     217         500 :     fd_memcpy( cs->owner.key, CURSOR, 32UL ); INC( 32UL );
     218         500 :     return 0;
     219         512 :   }
     220             : 
     221        1418 :   case FD_SYSTEM_PROGRAM_INSTR_ADVANCE_NONCE_ACCOUNT: {
     222        1418 :     return 0;
     223         512 :   }
     224             : 
     225         764 :   case FD_SYSTEM_PROGRAM_INSTR_WITHDRAW_NONCE_ACCOUNT: {
     226         764 :     CHECK_LEFT( 8UL );
     227         758 :     out->inner.withdraw_nonce_account = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     228         758 :     return 0;
     229         764 :   }
     230             : 
     231         559 :   case FD_SYSTEM_PROGRAM_INSTR_INITIALIZE_NONCE_ACCOUNT: {
     232         559 :     CHECK_LEFT( 32UL );
     233         552 :     fd_memcpy( out->inner.initialize_nonce_account.key, CURSOR, 32UL ); INC( 32UL );
     234         552 :     return 0;
     235         559 :   }
     236             : 
     237         796 :   case FD_SYSTEM_PROGRAM_INSTR_AUTHORIZE_NONCE_ACCOUNT: {
     238         796 :     CHECK_LEFT( 32UL );
     239         783 :     fd_memcpy( out->inner.authorize_nonce_account.key, CURSOR, 32UL ); INC( 32UL );
     240         783 :     return 0;
     241         796 :   }
     242             : 
     243         876 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     244         876 :     CHECK_LEFT( 8UL );
     245         872 :     out->inner.allocate = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     246         872 :     return 0;
     247         876 :   }
     248             : 
     249         349 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
     250         349 :     allocate_with_seed_t * as_ = &out->inner.allocate_with_seed;
     251         349 :     CHECK_LEFT( 32UL ); fd_memcpy( as_->base.key, CURSOR, 32UL ); INC( 32UL );
     252         332 :     CHECK_LEFT( 8UL );  as_->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     253         328 :     CHECK_LEFT( as_->seed_len );
     254         322 :     if( as_->seed_len ) {
     255         293 :       CHECK( fd_utf8_verify( (char const *)CURSOR, as_->seed_len ) );
     256         283 :     }
     257         312 :     as_->seed = CURSOR; INC( as_->seed_len );
     258         312 :     CHECK_LEFT( 40UL );
     259         301 :     as_->space = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     260         301 :     fd_memcpy( as_->owner.key, CURSOR, 32UL ); INC( 32UL );
     261         301 :     return 0;
     262         312 :   }
     263             : 
     264         571 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN_WITH_SEED: {
     265         571 :     assign_with_seed_t * aw = &out->inner.assign_with_seed;
     266         571 :     CHECK_LEFT( 32UL ); fd_memcpy( aw->base.key, CURSOR, 32UL ); INC( 32UL );
     267         551 :     CHECK_LEFT( 8UL );  aw->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     268         547 :     CHECK_LEFT( aw->seed_len );
     269         540 :     if( aw->seed_len ) {
     270         526 :       CHECK( fd_utf8_verify( (char const *)CURSOR, aw->seed_len ) );
     271         517 :     }
     272         531 :     aw->seed = CURSOR; INC( aw->seed_len );
     273         531 :     CHECK_LEFT( 32UL );
     274         527 :     fd_memcpy( aw->owner.key, CURSOR, 32UL ); INC( 32UL );
     275         527 :     return 0;
     276         531 :   }
     277             : 
     278         817 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER_WITH_SEED: {
     279         817 :     transfer_with_seed_t * tw = &out->inner.transfer_with_seed;
     280         817 :     CHECK_LEFT( 8UL );  tw->lamports      = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     281         812 :     CHECK_LEFT( 8UL );  tw->from_seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     282         809 :     CHECK_LEFT( tw->from_seed_len );
     283         791 :     if( tw->from_seed_len ) {
     284         775 :       CHECK( fd_utf8_verify( (char const *)CURSOR, tw->from_seed_len ) );
     285         768 :     }
     286         784 :     tw->from_seed = CURSOR; INC( tw->from_seed_len );
     287         784 :     CHECK_LEFT( 32UL );
     288         773 :     fd_memcpy( tw->from_owner.key, CURSOR, 32UL ); INC( 32UL );
     289         773 :     return 0;
     290         784 :   }
     291             : 
     292         545 :   case FD_SYSTEM_PROGRAM_INSTR_UPGRADE_NONCE_ACCOUNT: {
     293         545 :     return 0;
     294         784 :   }
     295             : 
     296         646 :   default: return -1;
     297       10278 :   }
     298             : 
     299       10278 : # undef CHECK
     300       10278 : # undef CHECK_LEFT
     301       10278 : # undef INC
     302       10278 : # undef CURSOR
     303       10278 : }
     304             : 
     305             : /* fd_system_program_instruction_encode writes a bincode-encoded
     306             :    SystemInstruction into [buf, buf+bufsz).  On success stores the
     307             :    number of bytes written to *out_sz and returns 0.  Returns -1 on
     308             :    short buffer. */
     309             : 
     310             : static inline int
     311             : fd_system_program_instruction_encode( fd_system_program_instruction_t const * in,
     312             :                                       uchar *                                 buf,
     313             :                                       ulong                                   bufsz,
     314         242 :                                       ulong *                                 out_sz ) {
     315         242 :   uchar * const _payload    = buf;
     316         242 :   ulong const   _payload_sz = bufsz;
     317         242 :   ulong         _i          = 0UL;
     318             : 
     319         484 : # define CHECK_LEFT( n ) { if( FD_UNLIKELY( (n)>(_payload_sz-_i) ) ) { return -1; } }
     320         968 : # define INC( n )        (_i += (ulong)(n))
     321         242 : # define CURSOR          (_payload+_i)
     322             : 
     323         242 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->discriminant ); INC( 4UL );
     324             : 
     325         242 :   switch( in->discriminant ) {
     326             : 
     327         242 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT:
     328         242 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     329         242 :     create_account_t const * ca =
     330         242 :         (in->discriminant==FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT)
     331         242 :           ? &in->inner.create_account
     332         242 :           : &in->inner.create_account_allow_prefund;
     333         242 :     CHECK_LEFT( 48UL );
     334         242 :     FD_STORE( ulong, CURSOR, ca->lamports ); INC( 8UL );
     335         242 :     FD_STORE( ulong, CURSOR, ca->space ); INC( 8UL );
     336         242 :     fd_memcpy( CURSOR, ca->owner.key, 32UL ); INC( 32UL );
     337         242 :     break;
     338         242 :   }
     339             : 
     340           0 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN: {
     341           0 :     CHECK_LEFT( 32UL );
     342           0 :     fd_memcpy( CURSOR, in->inner.assign.key, 32UL ); INC( 32UL );
     343           0 :     break;
     344           0 :   }
     345             : 
     346           0 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER: {
     347           0 :     CHECK_LEFT( 8UL );
     348           0 :     FD_STORE( ulong, CURSOR, in->inner.transfer ); INC( 8UL );
     349           0 :     break;
     350           0 :   }
     351             : 
     352           0 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
     353           0 :     create_account_with_seed_t const * cs = &in->inner.create_account_with_seed;
     354           0 :     CHECK_LEFT( 32UL ); fd_memcpy( CURSOR, cs->base.key, 32UL ); INC( 32UL );
     355           0 :     CHECK_LEFT( 8UL );  FD_STORE( ulong, CURSOR, cs->seed_len ); INC( 8UL );
     356           0 :     if( cs->seed_len ) {
     357           0 :       CHECK_LEFT( cs->seed_len ); fd_memcpy( CURSOR, cs->seed, cs->seed_len ); INC( cs->seed_len );
     358           0 :     }
     359           0 :     CHECK_LEFT( 48UL );
     360           0 :     FD_STORE( ulong, CURSOR, cs->lamports ); INC( 8UL );
     361           0 :     FD_STORE( ulong, CURSOR, cs->space ); INC( 8UL );
     362           0 :     fd_memcpy( CURSOR, cs->owner.key, 32UL ); INC( 32UL );
     363           0 :     break;
     364           0 :   }
     365             : 
     366           0 :   case FD_SYSTEM_PROGRAM_INSTR_ADVANCE_NONCE_ACCOUNT: break;
     367             : 
     368           0 :   case FD_SYSTEM_PROGRAM_INSTR_WITHDRAW_NONCE_ACCOUNT: {
     369           0 :     CHECK_LEFT( 8UL );
     370           0 :     FD_STORE( ulong, CURSOR, in->inner.withdraw_nonce_account ); INC( 8UL );
     371           0 :     break;
     372           0 :   }
     373             : 
     374           0 :   case FD_SYSTEM_PROGRAM_INSTR_INITIALIZE_NONCE_ACCOUNT: {
     375           0 :     CHECK_LEFT( 32UL );
     376           0 :     fd_memcpy( CURSOR, in->inner.initialize_nonce_account.key, 32UL ); INC( 32UL );
     377           0 :     break;
     378           0 :   }
     379             : 
     380           0 :   case FD_SYSTEM_PROGRAM_INSTR_AUTHORIZE_NONCE_ACCOUNT: {
     381           0 :     CHECK_LEFT( 32UL );
     382           0 :     fd_memcpy( CURSOR, in->inner.authorize_nonce_account.key, 32UL ); INC( 32UL );
     383           0 :     break;
     384           0 :   }
     385             : 
     386           0 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     387           0 :     CHECK_LEFT( 8UL );
     388           0 :     FD_STORE( ulong, CURSOR, in->inner.allocate ); INC( 8UL );
     389           0 :     break;
     390           0 :   }
     391             : 
     392           0 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
     393           0 :     allocate_with_seed_t const * as_ = &in->inner.allocate_with_seed;
     394           0 :     CHECK_LEFT( 32UL ); fd_memcpy( CURSOR, as_->base.key, 32UL ); INC( 32UL );
     395           0 :     CHECK_LEFT( 8UL );  FD_STORE( ulong, CURSOR, as_->seed_len ); INC( 8UL );
     396           0 :     if( as_->seed_len ) {
     397           0 :       CHECK_LEFT( as_->seed_len ); fd_memcpy( CURSOR, as_->seed, as_->seed_len ); INC( as_->seed_len );
     398           0 :     }
     399           0 :     CHECK_LEFT( 40UL );
     400           0 :     FD_STORE( ulong, CURSOR, as_->space ); INC( 8UL );
     401           0 :     fd_memcpy( CURSOR, as_->owner.key, 32UL ); INC( 32UL );
     402           0 :     break;
     403           0 :   }
     404             : 
     405           0 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN_WITH_SEED: {
     406           0 :     assign_with_seed_t const * aw = &in->inner.assign_with_seed;
     407           0 :     CHECK_LEFT( 32UL ); fd_memcpy( CURSOR, aw->base.key, 32UL ); INC( 32UL );
     408           0 :     CHECK_LEFT( 8UL );  FD_STORE( ulong, CURSOR, aw->seed_len ); INC( 8UL );
     409           0 :     if( aw->seed_len ) {
     410           0 :       CHECK_LEFT( aw->seed_len ); fd_memcpy( CURSOR, aw->seed, aw->seed_len ); INC( aw->seed_len );
     411           0 :     }
     412           0 :     CHECK_LEFT( 32UL );
     413           0 :     fd_memcpy( CURSOR, aw->owner.key, 32UL ); INC( 32UL );
     414           0 :     break;
     415           0 :   }
     416             : 
     417           0 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER_WITH_SEED: {
     418           0 :     transfer_with_seed_t const * tw = &in->inner.transfer_with_seed;
     419           0 :     CHECK_LEFT( 8UL );  FD_STORE( ulong, CURSOR, tw->lamports ); INC( 8UL );
     420           0 :     CHECK_LEFT( 8UL );  FD_STORE( ulong, CURSOR, tw->from_seed_len ); INC( 8UL );
     421           0 :     if( tw->from_seed_len ) {
     422           0 :       CHECK_LEFT( tw->from_seed_len ); fd_memcpy( CURSOR, tw->from_seed, tw->from_seed_len ); INC( tw->from_seed_len );
     423           0 :     }
     424           0 :     CHECK_LEFT( 32UL );
     425           0 :     fd_memcpy( CURSOR, tw->from_owner.key, 32UL ); INC( 32UL );
     426           0 :     break;
     427           0 :   }
     428             : 
     429           0 :   case FD_SYSTEM_PROGRAM_INSTR_UPGRADE_NONCE_ACCOUNT: break;
     430             : 
     431           0 :   default: return -1;
     432         242 :   }
     433             : 
     434         242 :   *out_sz = _i;
     435             : 
     436         242 : # undef CHECK_LEFT
     437         242 : # undef INC
     438         242 : # undef CURSOR
     439             : 
     440         242 :   return 0;
     441         242 : }
     442             : 
     443             : /* fd_nonce_state_versions_t is the in-memory representation of a decoded
     444             :    nonce account state.  Mirrors Agave's `Versions(Box<State>)` wrapper
     445             :    flattened into a single struct with an explicit `version`/`kind`
     446             :    discriminant pair.  When `kind == FD_NONCE_STATE_UNINITIALIZED` the
     447             :    `authority`, `durable_nonce`, and `lamports_per_signature` fields are
     448             :    ignored on both encode and decode. */
     449             : 
     450             : struct fd_nonce_state_versions {
     451             :   uint        version;
     452             :   uint        kind;
     453             :   fd_pubkey_t authority;
     454             :   fd_hash_t   durable_nonce;
     455             :   ulong       lamports_per_signature;
     456             : };
     457             : typedef struct fd_nonce_state_versions fd_nonce_state_versions_t;
     458             : 
     459             : /* fd_nonce_state_versions_size returns the bincode-exact wire size of the
     460             :    given nonce state.  Matches Agave's `bincode::serialized_size` for
     461             :    `nonce::versions::Versions`. */
     462             : 
     463             : static inline ulong
     464        1766 : fd_nonce_state_versions_size( fd_nonce_state_versions_t const * in ) {
     465        1766 :   return ( in->kind==FD_NONCE_STATE_INITIALIZED )
     466        1766 :     ? FD_NONCE_STATE_INITIALIZED_SZ
     467        1766 :     : FD_NONCE_STATE_UNINITIALIZED_SZ;
     468        1766 : }
     469             : 
     470             : /* fd_nonce_state_versions_decode reads a bincode-encoded
     471             :    `nonce::versions::Versions` from [data, data+data_sz).  Trailing bytes
     472             :    beyond the parsed region are accepted (matches Agave's top-level
     473             :    `bincode::deserialize` which uses `allow_trailing_bytes()`).  Returns 0
     474             :    on success, -1 on any decode failure (short buffer, unknown
     475             :    discriminant).  Callers should map -1 to
     476             :    `FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA`. */
     477             : 
     478             : static inline int
     479             : fd_nonce_state_versions_decode( fd_nonce_state_versions_t * out,
     480             :                                 uchar const *               data,
     481        3085 :                                 ulong                       data_sz ) {
     482        3085 :   uchar const * _payload    = data;
     483        3085 :   ulong const   _payload_sz = data_sz;
     484        3085 :   ulong         _i          = 0UL;
     485             : 
     486       14411 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     487        8436 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     488       12839 : # define INC( n )        (_i += (ulong)(n))
     489        4576 : # define CURSOR          (_payload+_i)
     490             : 
     491        3085 :   CHECK_LEFT( 4UL ); uint version = FD_LOAD( uint, CURSOR ); INC( 4UL );
     492        3066 :   CHECK( version<=FD_NONCE_VERSION_CURRENT );
     493        2921 :   out->version = version;
     494             : 
     495        2921 :   CHECK_LEFT( 4UL ); uint kind = FD_LOAD( uint, CURSOR ); INC( 4UL );
     496        2909 :   CHECK( kind<=FD_NONCE_STATE_INITIALIZED );
     497        2867 :   out->kind = kind;
     498             : 
     499        2867 :   if( kind==FD_NONCE_STATE_INITIALIZED ) {
     500        2430 :     CHECK_LEFT( 72UL );
     501        2288 :     fd_memcpy( out->authority.key,     CURSOR, 32UL ); INC( 32UL );
     502        2288 :     fd_memcpy( out->durable_nonce.hash, CURSOR, 32UL ); INC( 32UL );
     503        2288 :     out->lamports_per_signature = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     504        2288 :   }
     505             : 
     506        2725 : # undef CHECK
     507        2725 : # undef CHECK_LEFT
     508        2725 : # undef INC
     509        2725 : # undef CURSOR
     510             : 
     511        2725 :   return 0;
     512        2867 : }
     513             : 
     514             : /* fd_nonce_state_versions_encode writes a bincode-encoded
     515             :    `nonce::versions::Versions` into [buf, buf+bufsz).  On success stores
     516             :    the number of bytes written to *out_sz and returns 0.  Returns -1 on
     517             :    short buffer or invalid discriminant. */
     518             : 
     519             : static inline int
     520             : fd_nonce_state_versions_encode( fd_nonce_state_versions_t const * in,
     521             :                                 uchar *                           buf,
     522             :                                 ulong                             bufsz,
     523        1616 :                                 ulong *                           out_sz ) {
     524        1616 :   uchar * const _payload    = buf;
     525        1616 :   ulong const   _payload_sz = bufsz;
     526        1616 :   ulong         _i          = 0UL;
     527             : 
     528        8055 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     529        4823 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     530        8005 : # define INC( n )        (_i += (ulong)(n))
     531        3182 : # define CURSOR          (_payload+_i)
     532             : 
     533        1616 :   CHECK( in->version<=FD_NONCE_VERSION_CURRENT );
     534        1616 :   CHECK( in->kind   <=FD_NONCE_STATE_INITIALIZED );
     535             : 
     536        1616 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->version ); INC( 4UL );
     537        1616 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->kind    ); INC( 4UL );
     538             : 
     539        1616 :   if( in->kind==FD_NONCE_STATE_INITIALIZED ) {
     540        1591 :     CHECK_LEFT( 72UL );
     541        1591 :     fd_memcpy( CURSOR, in->authority.key,      32UL ); INC( 32UL );
     542        1591 :     fd_memcpy( CURSOR, in->durable_nonce.hash, 32UL ); INC( 32UL );
     543        1591 :     FD_STORE( ulong, CURSOR, in->lamports_per_signature ); INC( 8UL );
     544        1591 :   }
     545             : 
     546        1616 :   *out_sz = _i;
     547             : 
     548        1616 : # undef CHECK
     549        1616 : # undef CHECK_LEFT
     550        1616 : # undef INC
     551        1616 : # undef CURSOR
     552             : 
     553        1616 :   return 0;
     554        1616 : }
     555             : 
     556             : FD_PROTOTYPES_BEGIN
     557             : 
     558             : /* fd_system_program_execute is the entrypoint for the system program */
     559             : 
     560             : int fd_system_program_execute( fd_exec_instr_ctx_t * ctx );
     561             : 
     562             : /* System program instruction handlers */
     563             : 
     564             : int fd_system_program_exec_create_account              ( fd_exec_instr_ctx_t * ctx, create_account_t const *           data     );
     565             : int fd_system_program_exec_assign                      ( fd_exec_instr_ctx_t * ctx, fd_pubkey_t const *                owner    );
     566             : int fd_system_program_exec_transfer                    ( fd_exec_instr_ctx_t * ctx, ulong                              lamports );
     567             : int fd_system_program_exec_create_account_with_seed    ( fd_exec_instr_ctx_t * ctx, create_account_with_seed_t const * data     );
     568             : int fd_system_program_exec_advance_nonce_account       ( fd_exec_instr_ctx_t * ctx                                              );
     569             : int fd_system_program_exec_withdraw_nonce_account      ( fd_exec_instr_ctx_t * ctx, ulong                              lamports );
     570             : int fd_system_program_exec_initialize_nonce_account    ( fd_exec_instr_ctx_t * ctx, fd_pubkey_t const *                pubkey   );
     571             : int fd_system_program_exec_authorize_nonce_account     ( fd_exec_instr_ctx_t * ctx, fd_pubkey_t const *                pubkey   );
     572             : int fd_system_program_exec_allocate                    ( fd_exec_instr_ctx_t * ctx, ulong                              space    );
     573             : int fd_system_program_exec_allocate_with_seed          ( fd_exec_instr_ctx_t * ctx, allocate_with_seed_t const *       data     );
     574             : int fd_system_program_exec_assign_with_seed            ( fd_exec_instr_ctx_t * ctx, assign_with_seed_t const *         data     );
     575             : int fd_system_program_exec_transfer_with_seed          ( fd_exec_instr_ctx_t * ctx, transfer_with_seed_t const *       data     );
     576             : int fd_system_program_exec_upgrade_nonce_account       ( fd_exec_instr_ctx_t * ctx                                              );
     577             : int fd_system_program_exec_create_account_allow_prefund( fd_exec_instr_ctx_t * ctx, create_account_t const *           data     );
     578             : 
     579             : /* User APIs */
     580             : 
     581             : /* fd_check_transaction_age returns 0 if the transactions age is valid,
     582             :    returns non-zero otherwise. This is determined by the age of the
     583             :    blockhash provided in the transaction message or by the validity of
     584             :    the nonce provided in the transaction. */
     585             : 
     586             : int
     587             : fd_check_transaction_age( fd_bank_t *         bank,
     588             :                           fd_txn_in_t const * txn_in,
     589             :                           fd_txn_out_t *      txn_out );
     590             : 
     591             : /* `fd_get_system_account_kind()` determines whether an account is
     592             :    a normal system program account or a nonce account. Returns:
     593             :    - FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_SYSTEM if the account is a
     594             :      normal system program account
     595             :    - FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_NONCE if the account is a
     596             :      nonce account
     597             :    - FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN otherwise
     598             :    https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L55-L71 */
     599             : 
     600             : int
     601             : fd_get_system_account_kind( fd_acc_t const * acc );
     602             : 
     603             : FD_PROTOTYPES_END
     604             : 
     605             : #endif /* HEADER_fd_src_flamenco_runtime_program_fd_system_program_h */

Generated by: LCOV version 1.14