LCOV - code coverage report
Current view: top level - disco/gui - fd_gui_config_parse.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 48 53 90.6 %
Date: 2026-09-17 04:28:31 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "fd_gui_config_parse.h"
       2             : 
       3             : #include "../../ballet/json/fd_jtok.h"
       4             : 
       5             : /* parse_field consumes the pending string value of j into out (out_sz
       6             :    bytes).  A value that is not a string, or a string whose decoded
       7             :    form does not fit, leaves out empty and does not error j. */
       8             : 
       9             : static void
      10             : parse_field( fd_jtok_t * j,
      11             :              char *      out,
      12           9 :              ulong       out_sz ) {
      13           9 :   out[ 0 ] = '\0';
      14           9 :   if( FD_UNLIKELY( fd_jtok_peek( j )!=FD_JTOK_STR ) ) return;
      15             : 
      16           6 :   char const * raw = NULL; ulong raw_sz = 0UL;
      17           6 :   fd_jtok_raw( j, &raw, &raw_sz );
      18           6 :   if( FD_UNLIKELY( !raw ) ) return;
      19             : 
      20           6 :   fd_jtok_t s[1]; fd_jtok_init( s, raw, raw_sz );
      21           6 :   fd_jtok_cstr( s, out, out_sz );
      22           6 :   if( FD_UNLIKELY( fd_jtok_fini( s ) ) ) out[ 0 ] = '\0';
      23           6 : }
      24             : 
      25             : int
      26             : fd_gui_config_parse_validator_info( uchar const *                data,
      27             :                                     ulong                        sz,
      28          12 :                                     fd_gui_config_parse_info_t * info ) {
      29             :   /*
      30             :     pub struct ConfigKeys {
      31             :         #[cfg_attr(feature = "serde", serde(with = "short_vec"))]
      32             :         pub keys: Vec<(Pubkey, bool)>,
      33             :     }
      34             : 
      35             :     The memory layout of a ConfigProgram account is a bincode serialized
      36             :     ConfigKeys followed immediately by a stringified json object
      37             :     containing the desired info.
      38             : 
      39             :     The short_vec serialization format is a 1-3 bytes size field (where
      40             :     the highest bit in a given byte is a continuation bit) followed by
      41             :     serialized elements in the vector (in this case, each element is a
      42             :     32byte pubkey followed by a 1byte bool. For our simple parser, we
      43             :     only need to consider vectors smaller than 128 elements.
      44             : 
      45             :     The JSON schema for a validator info object is the following
      46             : 
      47             :     {
      48             :       "name": "<validator name>",
      49             :       "website": "<website url>",
      50             :       "details": "<validator details>",
      51             :       "iconUrl": "<icon url>"
      52             :     }
      53             : */
      54          12 :   ulong i = 0UL;
      55             : 
      56          48 : #define CHECK( cond )  do { \
      57          48 :     if( FD_UNLIKELY( !(cond) ) ) { \
      58           0 :       return 0; \
      59           0 :     } \
      60          48 :   } while( 0 )
      61             : 
      62             :   /* CHECK that it is safe to read at least n more bytes assuming i is
      63             :      the current location. n is untrusted and could trigger overflow, so
      64             :      don't do i+n<=payload_sz */
      65          48 : #define CHECK_LEFT( n ) CHECK( (n)<=(sz-i) )
      66             : 
      67          12 :   CHECK_LEFT( 1UL ); uchar ck_sz = FD_LOAD( uchar, data+i ); i++;
      68          12 :   if( FD_UNLIKELY( ck_sz!=2 ) ) return 0;
      69             : 
      70          12 :   struct __attribute__((packed, aligned(1))) config_keys {
      71          12 :     fd_pubkey_t pubkey;
      72          12 :     uchar       is_signer;
      73          12 :   };
      74             : 
      75          12 :   struct config_keys * data_config_keys = (struct config_keys *)(data + i);
      76          12 :   CHECK_LEFT( (sizeof(fd_pubkey_t) + 1UL)*ck_sz ); i += (sizeof(fd_pubkey_t) + 1UL)*ck_sz;
      77          12 :   CHECK_LEFT( FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_MAX_SZ );
      78             : 
      79             :   /* First entry should be Va1idator1nfo111111111111111111111111111111 */
      80          12 :   uchar expected[ 32UL ] = { 0x07, 0x51, 0x97, 0x01, 0x74, 0x48, 0xf2, 0xac, 0x5d, 0xc2, 0x3c, 0x9e, 0xbc, 0x7a, 0xc7, 0x8c, 0x0a, 0x27, 0x25, 0x7a, 0xc6, 0x14, 0x45, 0x8d, 0xe0, 0xa4, 0xf1, 0x6f, 0x80, 0x00, 0x00, 0x00 };
      81          12 :   if( FD_UNLIKELY( memcmp( data_config_keys[0].pubkey.uc, expected, sizeof(fd_pubkey_t) ) || data_config_keys[0].is_signer ) ) return 0;
      82             : 
      83             :   /* The config program only requires signatures from keys flagged
      84             :      is_signer, so an unsigned identity key could be anyone's */
      85          12 :   if( FD_UNLIKELY( data_config_keys[1].is_signer!=1 ) ) return 0;
      86             : 
      87           6 :   CHECK_LEFT( sizeof(ulong) ); ulong json_str_sz = FD_LOAD( ulong, data+i ); i += sizeof(ulong);
      88             : 
      89           6 :   CHECK_LEFT( json_str_sz );
      90             : 
      91           6 : #undef CHECK
      92           6 : #undef CHECK_LEFT
      93             : 
      94           6 :   info->name            [ 0 ] = '\0';
      95           6 :   info->website         [ 0 ] = '\0';
      96           6 :   info->details         [ 0 ] = '\0';
      97           6 :   info->icon_uri        [ 0 ] = '\0';
      98           6 :   info->keybase_username[ 0 ] = '\0';
      99             : 
     100           6 :   fd_jtok_t j[1]; fd_jtok_init( j, data+i, json_str_sz );
     101           6 :   fd_jtok_str_t key;
     102           6 :   fd_jtok_obj_enter( j );
     103          15 :   while( fd_jtok_obj_next( j, &key ) ) {
     104           9 :     if(      fd_jtok_str_eq( &key, "name"            ) ) parse_field( j, info->name,             sizeof(info->name)             );
     105           3 :     else if( fd_jtok_str_eq( &key, "website"         ) ) parse_field( j, info->website,          sizeof(info->website)          );
     106           0 :     else if( fd_jtok_str_eq( &key, "details"         ) ) parse_field( j, info->details,          sizeof(info->details)          );
     107           0 :     else if( fd_jtok_str_eq( &key, "iconUrl"         ) ) parse_field( j, info->icon_uri,         sizeof(info->icon_uri)         );
     108           0 :     else if( fd_jtok_str_eq( &key, "keybaseUsername" ) ) parse_field( j, info->keybase_username, sizeof(info->keybase_username) );
     109           9 :   }
     110           6 :   if( FD_UNLIKELY( fd_jtok_fini( j ) ) ) return 0;
     111             : 
     112           3 :   fd_memcpy( info->pubkey.uc, data_config_keys[1].pubkey.uc, sizeof(fd_pubkey_t) );
     113           3 :   return 1;
     114           6 : }

Generated by: LCOV version 1.14