LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_system_program.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 157 315 49.8 %
Date: 2026-08-19 04:32:02 Functions: 12 395 3.0 %

          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          12 : #define FD_SYSTEM_PROGRAM_ERR_ACCT_ALREADY_IN_USE              (0)  /* SystemError::AccountAlreadyInUse */
      22           3 : #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           3 : #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           0 : #define FD_SYSTEM_PROGRAM_ERR_ADDR_WITH_SEED_MISMATCH          (5)  /* SystemError::AddressWithSeedMismatch */
      27           0 : #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          36 : #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          48 : #define FD_NONCE_VERSION_CURRENT        (1U)
      54             : 
      55           9 : #define FD_NONCE_STATE_UNINITIALIZED    (0U)
      56         153 : #define FD_NONCE_STATE_INITIALIZED      (1U)
      57             : 
      58           0 : #define FD_NONCE_STATE_UNINITIALIZED_SZ (8UL)
      59          24 : #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           0 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN (-1)
      63         396 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_SYSTEM  (0)
      64           3 : #define FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_NONCE   (1)
      65             : 
      66             : /* SystemInstruction discriminants (wire-format u32 values). */
      67             : 
      68         234 : #define FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT               (0U)
      69           0 : #define FD_SYSTEM_PROGRAM_INSTR_ASSIGN                       (1U)
      70          66 : #define FD_SYSTEM_PROGRAM_INSTR_TRANSFER                     (2U)
      71           0 : #define FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED     (3U)
      72          27 : #define FD_SYSTEM_PROGRAM_INSTR_ADVANCE_NONCE_ACCOUNT        (4U)
      73           0 : #define FD_SYSTEM_PROGRAM_INSTR_WITHDRAW_NONCE_ACCOUNT       (5U)
      74           9 : #define FD_SYSTEM_PROGRAM_INSTR_INITIALIZE_NONCE_ACCOUNT     (6U)
      75           0 : #define FD_SYSTEM_PROGRAM_INSTR_AUTHORIZE_NONCE_ACCOUNT      (7U)
      76         156 : #define FD_SYSTEM_PROGRAM_INSTR_ALLOCATE                     (8U)
      77           0 : #define FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED           (9U)
      78           0 : #define FD_SYSTEM_PROGRAM_INSTR_ASSIGN_WITH_SEED             (10U)
      79           0 : #define FD_SYSTEM_PROGRAM_INSTR_TRANSFER_WITH_SEED           (11U)
      80           0 : #define FD_SYSTEM_PROGRAM_INSTR_UPGRADE_NONCE_ACCOUNT        (12U)
      81         258 : #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         264 :                                       ulong                             data_sz ) {
     163         264 :   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         264 :   ulong const   _payload_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
     167         264 :   ulong         _i          = 0UL;
     168             : 
     169         504 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     170         504 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     171         759 : # define INC( n )        (_i += (ulong)(n))
     172         264 : # define CURSOR          (_payload+_i)
     173             : 
     174         264 :   CHECK_LEFT( 4UL );
     175         261 :   uint disc = FD_LOAD( uint, CURSOR ); INC( 4UL );
     176         261 :   out->discriminant = disc;
     177             : 
     178         261 :   switch( disc ) {
     179             : 
     180          21 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT:
     181         129 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     182         129 :     create_account_t * ca =
     183         129 :         (disc==FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT)
     184         129 :           ? &out->inner.create_account
     185         129 :           : &out->inner.create_account_allow_prefund;
     186         129 :     CHECK_LEFT( 48UL );
     187         129 :     ca->lamports = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     188         129 :     ca->space    = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     189         129 :     fd_memcpy( ca->owner.key, CURSOR, 32UL ); INC( 32UL );
     190         129 :     return 0;
     191         129 :   }
     192             : 
     193           0 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN: {
     194           0 :     CHECK_LEFT( 32UL );
     195           0 :     fd_memcpy( out->inner.assign.key, CURSOR, 32UL ); INC( 32UL );
     196           0 :     return 0;
     197           0 :   }
     198             : 
     199          36 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER: {
     200          36 :     CHECK_LEFT( 8UL );
     201          36 :     out->inner.transfer = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     202          36 :     return 0;
     203          36 :   }
     204             : 
     205           0 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_WITH_SEED: {
     206           0 :     create_account_with_seed_t * cs = &out->inner.create_account_with_seed;
     207           0 :     CHECK_LEFT( 32UL ); fd_memcpy( cs->base.key, CURSOR, 32UL ); INC( 32UL );
     208           0 :     CHECK_LEFT( 8UL );  cs->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     209           0 :     CHECK_LEFT( cs->seed_len );
     210           0 :     if( cs->seed_len ) {
     211           0 :       CHECK( fd_utf8_verify( (char const *)CURSOR, cs->seed_len ) );
     212           0 :     }
     213           0 :     cs->seed = CURSOR; INC( cs->seed_len );
     214           0 :     CHECK_LEFT( 48UL );
     215           0 :     cs->lamports = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     216           0 :     cs->space    = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     217           0 :     fd_memcpy( cs->owner.key, CURSOR, 32UL ); INC( 32UL );
     218           0 :     return 0;
     219           0 :   }
     220             : 
     221          21 :   case FD_SYSTEM_PROGRAM_INSTR_ADVANCE_NONCE_ACCOUNT: {
     222          21 :     return 0;
     223           0 :   }
     224             : 
     225           0 :   case FD_SYSTEM_PROGRAM_INSTR_WITHDRAW_NONCE_ACCOUNT: {
     226           0 :     CHECK_LEFT( 8UL );
     227           0 :     out->inner.withdraw_nonce_account = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     228           0 :     return 0;
     229           0 :   }
     230             : 
     231           6 :   case FD_SYSTEM_PROGRAM_INSTR_INITIALIZE_NONCE_ACCOUNT: {
     232           6 :     CHECK_LEFT( 32UL );
     233           6 :     fd_memcpy( out->inner.initialize_nonce_account.key, CURSOR, 32UL ); INC( 32UL );
     234           6 :     return 0;
     235           6 :   }
     236             : 
     237           0 :   case FD_SYSTEM_PROGRAM_INSTR_AUTHORIZE_NONCE_ACCOUNT: {
     238           0 :     CHECK_LEFT( 32UL );
     239           0 :     fd_memcpy( out->inner.authorize_nonce_account.key, CURSOR, 32UL ); INC( 32UL );
     240           0 :     return 0;
     241           0 :   }
     242             : 
     243          69 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     244          69 :     CHECK_LEFT( 8UL );
     245          69 :     out->inner.allocate = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     246          69 :     return 0;
     247          69 :   }
     248             : 
     249           0 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE_WITH_SEED: {
     250           0 :     allocate_with_seed_t * as_ = &out->inner.allocate_with_seed;
     251           0 :     CHECK_LEFT( 32UL ); fd_memcpy( as_->base.key, CURSOR, 32UL ); INC( 32UL );
     252           0 :     CHECK_LEFT( 8UL );  as_->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     253           0 :     CHECK_LEFT( as_->seed_len );
     254           0 :     if( as_->seed_len ) {
     255           0 :       CHECK( fd_utf8_verify( (char const *)CURSOR, as_->seed_len ) );
     256           0 :     }
     257           0 :     as_->seed = CURSOR; INC( as_->seed_len );
     258           0 :     CHECK_LEFT( 40UL );
     259           0 :     as_->space = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     260           0 :     fd_memcpy( as_->owner.key, CURSOR, 32UL ); INC( 32UL );
     261           0 :     return 0;
     262           0 :   }
     263             : 
     264           0 :   case FD_SYSTEM_PROGRAM_INSTR_ASSIGN_WITH_SEED: {
     265           0 :     assign_with_seed_t * aw = &out->inner.assign_with_seed;
     266           0 :     CHECK_LEFT( 32UL ); fd_memcpy( aw->base.key, CURSOR, 32UL ); INC( 32UL );
     267           0 :     CHECK_LEFT( 8UL );  aw->seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     268           0 :     CHECK_LEFT( aw->seed_len );
     269           0 :     if( aw->seed_len ) {
     270           0 :       CHECK( fd_utf8_verify( (char const *)CURSOR, aw->seed_len ) );
     271           0 :     }
     272           0 :     aw->seed = CURSOR; INC( aw->seed_len );
     273           0 :     CHECK_LEFT( 32UL );
     274           0 :     fd_memcpy( aw->owner.key, CURSOR, 32UL ); INC( 32UL );
     275           0 :     return 0;
     276           0 :   }
     277             : 
     278           0 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER_WITH_SEED: {
     279           0 :     transfer_with_seed_t * tw = &out->inner.transfer_with_seed;
     280           0 :     CHECK_LEFT( 8UL );  tw->lamports      = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     281           0 :     CHECK_LEFT( 8UL );  tw->from_seed_len = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     282           0 :     CHECK_LEFT( tw->from_seed_len );
     283           0 :     if( tw->from_seed_len ) {
     284           0 :       CHECK( fd_utf8_verify( (char const *)CURSOR, tw->from_seed_len ) );
     285           0 :     }
     286           0 :     tw->from_seed = CURSOR; INC( tw->from_seed_len );
     287           0 :     CHECK_LEFT( 32UL );
     288           0 :     fd_memcpy( tw->from_owner.key, CURSOR, 32UL ); INC( 32UL );
     289           0 :     return 0;
     290           0 :   }
     291             : 
     292           0 :   case FD_SYSTEM_PROGRAM_INSTR_UPGRADE_NONCE_ACCOUNT: {
     293           0 :     return 0;
     294           0 :   }
     295             : 
     296           0 :   default: return -1;
     297         261 :   }
     298             : 
     299         261 : # undef CHECK
     300         261 : # undef CHECK_LEFT
     301         261 : # undef INC
     302         261 : # undef CURSOR
     303         261 : }
     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          36 :                                       ulong *                                 out_sz ) {
     315          36 :   uchar * const _payload    = buf;
     316          36 :   ulong const   _payload_sz = bufsz;
     317          36 :   ulong         _i          = 0UL;
     318             : 
     319          72 : # define CHECK_LEFT( n ) { if( FD_UNLIKELY( (n)>(_payload_sz-_i) ) ) { return -1; } }
     320         114 : # define INC( n )        (_i += (ulong)(n))
     321          36 : # define CURSOR          (_payload+_i)
     322             : 
     323          36 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->discriminant ); INC( 4UL );
     324             : 
     325          36 :   switch( in->discriminant ) {
     326             : 
     327          21 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT:
     328          21 :   case FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT_ALLOW_PREFUND: {
     329          21 :     create_account_t const * ca =
     330          21 :         (in->discriminant==FD_SYSTEM_PROGRAM_INSTR_CREATE_ACCOUNT)
     331          21 :           ? &in->inner.create_account
     332          21 :           : &in->inner.create_account_allow_prefund;
     333          21 :     CHECK_LEFT( 48UL );
     334          21 :     FD_STORE( ulong, CURSOR, ca->lamports ); INC( 8UL );
     335          21 :     FD_STORE( ulong, CURSOR, ca->space ); INC( 8UL );
     336          21 :     fd_memcpy( CURSOR, ca->owner.key, 32UL ); INC( 32UL );
     337          21 :     break;
     338          21 :   }
     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           6 :   case FD_SYSTEM_PROGRAM_INSTR_TRANSFER: {
     347           6 :     CHECK_LEFT( 8UL );
     348           6 :     FD_STORE( ulong, CURSOR, in->inner.transfer ); INC( 8UL );
     349           6 :     break;
     350           6 :   }
     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           9 :   case FD_SYSTEM_PROGRAM_INSTR_ALLOCATE: {
     387           9 :     CHECK_LEFT( 8UL );
     388           9 :     FD_STORE( ulong, CURSOR, in->inner.allocate ); INC( 8UL );
     389           9 :     break;
     390           9 :   }
     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          36 :   }
     433             : 
     434          36 :   *out_sz = _i;
     435             : 
     436          36 : # undef CHECK_LEFT
     437          36 : # undef INC
     438          36 : # undef CURSOR
     439             : 
     440          36 :   return 0;
     441          36 : }
     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          24 : fd_nonce_state_versions_size( fd_nonce_state_versions_t const * in ) {
     465          24 :   return ( in->kind==FD_NONCE_STATE_INITIALIZED )
     466          24 :     ? FD_NONCE_STATE_INITIALIZED_SZ
     467          24 :     : FD_NONCE_STATE_UNINITIALIZED_SZ;
     468          24 : }
     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          33 :                                 ulong                       data_sz ) {
     482          33 :   uchar const * _payload    = data;
     483          33 :   ulong const   _payload_sz = data_sz;
     484          33 :   ulong         _i          = 0UL;
     485             : 
     486         162 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     487          96 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     488         156 : # define INC( n )        (_i += (ulong)(n))
     489          60 : # define CURSOR          (_payload+_i)
     490             : 
     491          33 :   CHECK_LEFT( 4UL ); uint version = FD_LOAD( uint, CURSOR ); INC( 4UL );
     492          33 :   CHECK( version<=FD_NONCE_VERSION_CURRENT );
     493          33 :   out->version = version;
     494             : 
     495          33 :   CHECK_LEFT( 4UL ); uint kind = FD_LOAD( uint, CURSOR ); INC( 4UL );
     496          33 :   CHECK( kind<=FD_NONCE_STATE_INITIALIZED );
     497          33 :   out->kind = kind;
     498             : 
     499          33 :   if( kind==FD_NONCE_STATE_INITIALIZED ) {
     500          30 :     CHECK_LEFT( 72UL );
     501          30 :     fd_memcpy( out->authority.key,     CURSOR, 32UL ); INC( 32UL );
     502          30 :     fd_memcpy( out->durable_nonce.hash, CURSOR, 32UL ); INC( 32UL );
     503          30 :     out->lamports_per_signature = FD_LOAD( ulong, CURSOR ); INC( 8UL );
     504          30 :   }
     505             : 
     506          33 : # undef CHECK
     507          33 : # undef CHECK_LEFT
     508          33 : # undef INC
     509          33 : # undef CURSOR
     510             : 
     511          33 :   return 0;
     512          33 : }
     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          48 :                                 ulong *                           out_sz ) {
     524          48 :   uchar * const _payload    = buf;
     525          48 :   ulong const   _payload_sz = bufsz;
     526          48 :   ulong         _i          = 0UL;
     527             : 
     528         237 : # define CHECK( cond )   { if( FD_UNLIKELY( !(cond) ) ) { return -1; } }
     529         141 : # define CHECK_LEFT( n ) CHECK( (n)<=(_payload_sz-_i) )
     530         231 : # define INC( n )        (_i += (ulong)(n))
     531          90 : # define CURSOR          (_payload+_i)
     532             : 
     533          48 :   CHECK( in->version<=FD_NONCE_VERSION_CURRENT );
     534          48 :   CHECK( in->kind   <=FD_NONCE_STATE_INITIALIZED );
     535             : 
     536          48 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->version ); INC( 4UL );
     537          48 :   CHECK_LEFT( 4UL ); FD_STORE( uint, CURSOR, in->kind    ); INC( 4UL );
     538             : 
     539          48 :   if( in->kind==FD_NONCE_STATE_INITIALIZED ) {
     540          45 :     CHECK_LEFT( 72UL );
     541          45 :     fd_memcpy( CURSOR, in->authority.key,      32UL ); INC( 32UL );
     542          45 :     fd_memcpy( CURSOR, in->durable_nonce.hash, 32UL ); INC( 32UL );
     543          45 :     FD_STORE( ulong, CURSOR, in->lamports_per_signature ); INC( 8UL );
     544          45 :   }
     545             : 
     546          48 :   *out_sz = _i;
     547             : 
     548          48 : # undef CHECK
     549          48 : # undef CHECK_LEFT
     550          48 : # undef INC
     551          48 : # undef CURSOR
     552             : 
     553          48 :   return 0;
     554          48 : }
     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