LCOV - code coverage report
Current view: top level - discof/rpcserver - fd_block_to_json.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 671 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 21 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include <unistd.h>
       3             : #include "../../ballet/nanopb/pb_decode.h"
       4             : #include "fd_webserver.h"
       5             : #include "../../ballet/txn/fd_txn.h"
       6             : #include "../../ballet/block/fd_microblock.h"
       7             : #include "../../ballet/base58/fd_base58.h"
       8             : #include "../../ballet/zstd/fd_zstd.h"
       9             : #include "../../flamenco/types/fd_types.h"
      10             : #include "../../flamenco/types/fd_solana_block.pb.h"
      11             : #include "../../flamenco/runtime/fd_executor_err.h"
      12             : #include "../../flamenco/runtime/fd_system_ids.h"
      13             : #include "fd_block_to_json.h"
      14             : #include "fd_stub_to_json.h"
      15             : 
      16             : #if FD_HAS_ZSTD
      17             : #define ZSTD_STATIC_LINKING_ONLY
      18             : #include <zstd.h>
      19             : #endif
      20             : 
      21           0 : #define EMIT_SIMPLE(_str_) fd_web_reply_append(ws, _str_, sizeof(_str_)-1)
      22             : 
      23             : void
      24           0 : fd_tokenbalance_to_json( fd_webserver_t * ws, struct _fd_solblock_TokenBalance * b ) {
      25           0 :   fd_web_reply_sprintf(ws, "{\"accountIndex\":%u,\"mint\":\"%s\",\"owner\":\"%s\",\"programId\":\"%s\",\"uiTokenAmount\":{",
      26           0 :                        b->account_index, b->mint, b->owner, b->program_id);
      27           0 :   fd_web_reply_sprintf(ws, "\"amount\":\"%s\",", b->ui_token_amount.amount);
      28           0 :   int dec;
      29           0 :   if (b->ui_token_amount.has_decimals) {
      30           0 :     fd_web_reply_sprintf(ws, "\"decimals\":%u,", b->ui_token_amount.decimals);
      31           0 :     dec = (int)b->ui_token_amount.decimals;
      32           0 :   } else
      33           0 :     dec = 0;
      34           0 :   if (b->ui_token_amount.has_ui_amount)
      35           0 :     fd_web_reply_sprintf(ws, "\"uiAmount\":%.*f,", dec, b->ui_token_amount.ui_amount);
      36           0 :   fd_web_reply_sprintf(ws, "\"uiAmountString\":\"%s\"}}", b->ui_token_amount.ui_amount_string);
      37           0 : }
      38             : 
      39             : static char const *
      40           0 : instr_strerror( int err ) {
      41           0 :   switch( err ) {
      42           0 :   case FD_EXECUTOR_INSTR_SUCCESS                                : return ""; // not used
      43           0 :   case FD_EXECUTOR_INSTR_ERR_FATAL                              : return ""; // not used
      44           0 :   case FD_EXECUTOR_INSTR_ERR_GENERIC_ERR                        : return "GenericError";
      45           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_ARG                        : return "InvalidArgument";
      46           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA                 : return "InvalidInstructionData";
      47           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA                   : return "InvalidAccountData";
      48           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL                 : return "AccountDataTooSmall";
      49           0 :   case FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS                 : return "InsufficientFunds";
      50           0 :   case FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID               : return "IncorrectProgramId";
      51           0 :   case FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE         : return "MissingRequiredSignature";
      52           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED            : return "AccountAlreadyInitialized";
      53           0 :   case FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT              : return "UninitializedAccount";
      54           0 :   case FD_EXECUTOR_INSTR_ERR_UNBALANCED_INSTR                   : return "UnbalancedInstruction";
      55           0 :   case FD_EXECUTOR_INSTR_ERR_MODIFIED_PROGRAM_ID                : return "ModifiedProgramId";
      56           0 :   case FD_EXECUTOR_INSTR_ERR_EXTERNAL_ACCOUNT_LAMPORT_SPEND     : return "ExternalAccountLamportSpend";
      57           0 :   case FD_EXECUTOR_INSTR_ERR_EXTERNAL_DATA_MODIFIED             : return "ExternalAccountDataModified";
      58           0 :   case FD_EXECUTOR_INSTR_ERR_READONLY_LAMPORT_CHANGE            : return "ReadonlyLamportChange";
      59           0 :   case FD_EXECUTOR_INSTR_ERR_READONLY_DATA_MODIFIED             : return "ReadonlyDataModified";
      60           0 :   case FD_EXECUTOR_INSTR_ERR_DUPLICATE_ACCOUNT_IDX              : return "DuplicateAccountIndex";
      61           0 :   case FD_EXECUTOR_INSTR_ERR_EXECUTABLE_MODIFIED                : return "ExecutableModified";
      62           0 :   case FD_EXECUTOR_INSTR_ERR_RENT_EPOCH_MODIFIED                : return "RentEpochModified";
      63           0 :   case FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS                : return "NotEnoughAccountKeys";
      64           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_DATA_SIZE_CHANGED              : return "AccountDataSizeChanged";
      65           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_NOT_EXECUTABLE                 : return "AccountNotExecutable";
      66           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED                  : return "AccountBorrowFailed";
      67           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_BORROW_OUTSTANDING             : return "AccountBorrowOutstanding";
      68           0 :   case FD_EXECUTOR_INSTR_ERR_DUPLICATE_ACCOUNT_OUT_OF_SYNC      : return "DuplicateAccountOutOfSync";
      69           0 :   case FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR                         : return "Custom(u32)";
      70           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_ERR                        : return "InvalidError";
      71           0 :   case FD_EXECUTOR_INSTR_ERR_EXECUTABLE_DATA_MODIFIED           : return "ExecutableDataModified";
      72           0 :   case FD_EXECUTOR_INSTR_ERR_EXECUTABLE_LAMPORT_CHANGE          : return "ExecutableLamportChange";
      73           0 :   case FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT : return "ExecutableAccountNotRentExempt";
      74           0 :   case FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID             : return "UnsupportedProgramId";
      75           0 :   case FD_EXECUTOR_INSTR_ERR_CALL_DEPTH                         : return "CallDepth";
      76           0 :   case FD_EXECUTOR_INSTR_ERR_MISSING_ACC                        : return "MissingAccount";
      77           0 :   case FD_EXECUTOR_INSTR_ERR_REENTRANCY_NOT_ALLOWED             : return "ReentrancyNotAllowed";
      78           0 :   case FD_EXECUTOR_INSTR_ERR_MAX_SEED_LENGTH_EXCEEDED           : return "MaxSeedLengthExceeded";
      79           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_SEEDS                      : return "InvalidSeeds";
      80           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC                    : return "InvalidRealloc";
      81           0 :   case FD_EXECUTOR_INSTR_ERR_COMPUTE_BUDGET_EXCEEDED            : return "ComputationalBudgetExceeded";
      82           0 :   case FD_EXECUTOR_INSTR_ERR_PRIVILEGE_ESCALATION               : return "PrivilegeEscalation";
      83           0 :   case FD_EXECUTOR_INSTR_ERR_PROGRAM_ENVIRONMENT_SETUP_FAILURE  : return "ProgramEnvironmentSetupFailure";
      84           0 :   case FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPLETE         : return "ProgramFailedToComplete";
      85           0 :   case FD_EXECUTOR_INSTR_ERR_PROGRAM_FAILED_TO_COMPILE          : return "ProgramFailedToCompile";
      86           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_IMMUTABLE                      : return "Immutable";
      87           0 :   case FD_EXECUTOR_INSTR_ERR_INCORRECT_AUTHORITY                : return "IncorrectAuthority";
      88           0 :   case FD_EXECUTOR_INSTR_ERR_BORSH_IO_ERROR                     : return "BorshIoError(String)";
      89           0 :   case FD_EXECUTOR_INSTR_ERR_ACC_NOT_RENT_EXEMPT                : return "AccountNotRentExempt";
      90           0 :   case FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER                  : return "InvalidAccountOwner";
      91           0 :   case FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW                : return "ArithmeticOverflow";
      92           0 :   case FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR                 : return "UnsupportedSysvar";
      93           0 :   case FD_EXECUTOR_INSTR_ERR_ILLEGAL_OWNER                      : return "IllegalOwner";
      94           0 :   case FD_EXECUTOR_INSTR_ERR_MAX_ACCS_DATA_ALLOCS_EXCEEDED      : return "MaxAccountsDataAllocationsExceeded";
      95           0 :   case FD_EXECUTOR_INSTR_ERR_MAX_ACCS_EXCEEDED                  : return "MaxAccountsExceeded";
      96           0 :   case FD_EXECUTOR_INSTR_ERR_MAX_INSN_TRACE_LENS_EXCEEDED       : return "MaxInstructionTraceLengthExceeded";
      97           0 :   case FD_EXECUTOR_INSTR_ERR_BUILTINS_MUST_CONSUME_CUS          : return "BuiltinProgramsMustConsumeComputeUnits";
      98           0 :   default: break;
      99           0 :   }
     100             : 
     101           0 :   return "";
     102           0 : }
     103             : 
     104             : void
     105             : fd_error_to_json( fd_webserver_t * ws,
     106             :                   const uchar* bytes,
     107           0 :                   ulong size ) {
     108           0 :   const uchar* orig_bytes = bytes;
     109           0 :   ulong orig_size = size;
     110             : 
     111           0 :   if (size < sizeof(uint) )
     112           0 :     goto dump_as_hex;
     113           0 :   uint kind = *(const uint*)bytes;
     114           0 :   bytes += sizeof(uint);
     115           0 :   size -= sizeof(uint);
     116             : 
     117           0 :   if( kind == 8 /* Instruction error */ ) {
     118           0 :     if( size < 1 )
     119           0 :       goto dump_as_hex;
     120           0 :     uint index = *(bytes++); /* Instruction index */
     121           0 :     size--;
     122             : 
     123           0 :     if (size < sizeof(uint))
     124           0 :       goto dump_as_hex;
     125           0 :     int cnum =  *(const int*)bytes;
     126           0 :     bytes += sizeof(uint);
     127           0 :     size -= sizeof(uint);
     128             : 
     129           0 :     if( cnum == FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR ) {
     130           0 :       if (size < sizeof(uint))
     131           0 :         goto dump_as_hex;
     132           0 :       uint code = *(const uint*)bytes; /* Custom code? */
     133           0 :       fd_web_reply_sprintf(ws, "{\"InstructionError\":[%u,{\"Custom\":%u}]}", index, code);
     134           0 :       return;
     135           0 :     } else {
     136           0 :       fd_web_reply_sprintf(ws, "{\"InstructionError\":[%u,\"%s\"]}", index, instr_strerror( cnum ));
     137           0 :       return;
     138           0 :     }
     139           0 :   }
     140             : 
     141           0 :  dump_as_hex:
     142           0 :   EMIT_SIMPLE("\"");
     143           0 :   fd_web_reply_encode_hex(ws, orig_bytes, orig_size);
     144           0 :   EMIT_SIMPLE("\"");
     145           0 : }
     146             : 
     147             : void fd_inner_instructions_to_json( fd_webserver_t * ws,
     148           0 :                                     struct _fd_solblock_InnerInstructions * insts ) {
     149           0 :   fd_web_reply_sprintf(ws, "{\"index\":%u,\"instructions\":[", insts->index);
     150           0 :   for ( pb_size_t i = 0; i < insts->instructions_count; ++i ) {
     151           0 :     struct _fd_solblock_InnerInstruction * inst = insts->instructions + i;
     152           0 :     fd_web_reply_sprintf(ws, "%s{\"data\":\"", (i == 0 ? "" : ","));
     153           0 :     fd_web_reply_encode_base58(ws, inst->data->bytes, inst->data->size);
     154           0 :     fd_web_reply_sprintf(ws, "\",\"programIdIndex:\":%u}", inst->program_id_index);
     155           0 :   }
     156           0 :   EMIT_SIMPLE("]}");
     157           0 : }
     158             : 
     159             : struct decode_return_data_buf {
     160             :   uchar data[256];
     161             :   ulong sz;
     162             : };
     163             : 
     164             : static bool
     165           0 : decode_return_data(pb_istream_t *stream, const pb_field_t *field, void **arg) {
     166           0 :   (void)field;
     167           0 :   struct decode_return_data_buf * buf = (struct decode_return_data_buf *)(*arg);
     168           0 :   buf->sz = fd_ulong_min( sizeof(buf->data), stream->bytes_left );
     169           0 :   pb_read( stream, buf->data, buf->sz );
     170           0 :   return 1;
     171           0 : }
     172             : 
     173             : const char *
     174             : fd_txn_meta_to_json( fd_webserver_t * ws,
     175             :                      const void * meta_raw,
     176           0 :                      ulong meta_raw_sz ) {
     177           0 :   if( meta_raw==NULL || meta_raw_sz==0 ) {
     178           0 :     EMIT_SIMPLE("\"meta\":null,");
     179           0 :     return NULL;
     180           0 :   }
     181             : 
     182           0 :   fd_solblock_TransactionStatusMeta txn_status = {0};
     183           0 :   struct decode_return_data_buf return_data_buf;
     184           0 :   pb_callback_t return_data_cb = { .funcs.decode = decode_return_data, .arg = &return_data_buf };
     185           0 :   txn_status.return_data.data = return_data_cb;
     186             : 
     187           0 :   pb_istream_t stream = pb_istream_from_buffer( meta_raw, meta_raw_sz );
     188           0 :   if( FD_UNLIKELY( !pb_decode( &stream, fd_solblock_TransactionStatusMeta_fields, &txn_status ) ) ) {
     189           0 :     FD_LOG_ERR(( "failed to decode txn status: %s", PB_GET_ERROR( &stream ) ));
     190           0 :   }
     191             : 
     192           0 :   EMIT_SIMPLE("\"meta\":{");
     193           0 :   if (txn_status.has_compute_units_consumed)
     194           0 :     fd_web_reply_sprintf(ws, "\"computeUnitsConsumed\":%lu,", txn_status.compute_units_consumed);
     195           0 :   EMIT_SIMPLE("\"err\":");
     196           0 :   if (txn_status.has_err)
     197           0 :     fd_error_to_json(ws, txn_status.err.err->bytes, txn_status.err.err->size);
     198           0 :   else
     199           0 :     EMIT_SIMPLE("null");
     200           0 :   fd_web_reply_sprintf(ws, ",\"fee\":%lu,\"innerInstructions\":[", txn_status.fee);
     201           0 :   if (!txn_status.inner_instructions_none) {
     202           0 :     for (pb_size_t i = 0; i < txn_status.inner_instructions_count; ++i) {
     203           0 :       if ( i > 0 ) EMIT_SIMPLE(",");
     204           0 :       fd_inner_instructions_to_json(ws, txn_status.inner_instructions + i);
     205           0 :     }
     206           0 :   }
     207           0 :   EMIT_SIMPLE("],\"loadedAddresses\":{\"readonly\":[");
     208           0 :   for (pb_size_t i = 0; i < txn_status.loaded_readonly_addresses_count; ++i) {
     209           0 :     pb_bytes_array_t * ba = txn_status.loaded_readonly_addresses[i];
     210           0 :     if (ba->size == 32) {
     211           0 :       char buf32[FD_BASE58_ENCODED_32_SZ];
     212           0 :       fd_base58_encode_32(ba->bytes, NULL, buf32);
     213           0 :       fd_web_reply_sprintf(ws, "%s\"%s\"", (i == 0 ? "" : ","), buf32);
     214           0 :     } else
     215           0 :       fd_web_reply_sprintf(ws, "%s\"\"", (i == 0 ? "" : ","));
     216           0 :   }
     217           0 :   EMIT_SIMPLE("],\"writable\":[");
     218           0 :   for (pb_size_t i = 0; i < txn_status.loaded_writable_addresses_count; ++i) {
     219           0 :     pb_bytes_array_t * ba = txn_status.loaded_writable_addresses[i];
     220           0 :     if (ba->size == 32) {
     221           0 :       char buf32[FD_BASE58_ENCODED_32_SZ];
     222           0 :       fd_base58_encode_32(ba->bytes, NULL, buf32);
     223           0 :       fd_web_reply_sprintf(ws, "%s\"%s\"", (i == 0 ? "" : ","), buf32);
     224           0 :     } else
     225           0 :       fd_web_reply_sprintf(ws, "%s\"\"", (i == 0 ? "" : ","));
     226           0 :   }
     227           0 :   EMIT_SIMPLE("]},\"logMessages\":[");
     228           0 :   for (pb_size_t i = 0; i < txn_status.log_messages_count; ++i) {
     229           0 :     if( i ) EMIT_SIMPLE(",");
     230           0 :     fd_web_reply_encode_json_string(ws, txn_status.log_messages[i]);
     231           0 :   }
     232           0 :   EMIT_SIMPLE("],\"postBalances\":[");
     233           0 :   for (pb_size_t i = 0; i < txn_status.post_balances_count; ++i)
     234           0 :     fd_web_reply_sprintf(ws, "%s%lu", (i == 0 ? "" : ","), txn_status.post_balances[i]);
     235           0 :   EMIT_SIMPLE("],\"postTokenBalances\":[");
     236           0 :   for (pb_size_t i = 0; i < txn_status.post_token_balances_count; ++i) {
     237           0 :     if (i > 0) EMIT_SIMPLE(",");
     238           0 :     fd_tokenbalance_to_json(ws, txn_status.post_token_balances + i);
     239           0 :   }
     240           0 :   EMIT_SIMPLE("],\"preBalances\":[");
     241           0 :   for (pb_size_t i = 0; i < txn_status.pre_balances_count; ++i)
     242           0 :     fd_web_reply_sprintf(ws, "%s%lu", (i == 0 ? "" : ","), txn_status.pre_balances[i]);
     243           0 :   EMIT_SIMPLE("],\"preTokenBalances\":[");
     244           0 :   for (pb_size_t i = 0; i < txn_status.pre_token_balances_count; ++i) {
     245           0 :     if (i > 0) EMIT_SIMPLE(",");
     246           0 :     fd_tokenbalance_to_json(ws, txn_status.pre_token_balances + i);
     247           0 :   }
     248           0 :   EMIT_SIMPLE("]");
     249           0 :   if( txn_status.has_return_data ) {
     250           0 :     EMIT_SIMPLE(",\"returnData\":{\"data\":[\"");
     251           0 :     fd_web_reply_encode_base64( ws, return_data_buf.data, return_data_buf.sz );
     252           0 :     EMIT_SIMPLE("\",\"base64\"]");
     253           0 :     if( txn_status.return_data.has_program_id ) {
     254           0 :       char buf32[FD_BASE58_ENCODED_32_SZ];
     255           0 :       fd_base58_encode_32(txn_status.return_data.program_id, NULL, buf32);
     256           0 :       fd_web_reply_sprintf(ws, ",\"programId\":\"%s\"", buf32);
     257           0 :     }
     258           0 :     EMIT_SIMPLE("}");
     259           0 :   }
     260           0 :   EMIT_SIMPLE(",\"rewards\":[],\"status\":{\"Ok\":null}");
     261           0 :   EMIT_SIMPLE("},");
     262             : 
     263           0 :   pb_release( fd_solblock_TransactionStatusMeta_fields, &txn_status );
     264             : 
     265           0 :   return NULL;
     266           0 : }
     267             : 
     268             : static const char *
     269             : generic_program_to_json( fd_webserver_t * ws,
     270             :                          fd_txn_t * txn,
     271             :                          fd_txn_instr_t * instr,
     272             :                          const uchar * raw,
     273             :                          int * need_comma,
     274           0 :                          fd_spad_t * spad) {
     275           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
     276           0 :     if( *need_comma ) EMIT_SIMPLE(",");
     277           0 :     EMIT_SIMPLE("{\"accounts\":[");
     278           0 :     const uchar * instr_acc_idxs = raw + instr->acct_off;
     279           0 :     const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
     280           0 :     for (ushort j = 0; j < instr->acct_cnt; j++) {
     281           0 :       char buf32[FD_BASE58_ENCODED_32_SZ];
     282           0 :       fd_base58_encode_32((const uchar*)(accts + instr_acc_idxs[j]), NULL, buf32);
     283           0 :       fd_web_reply_sprintf(ws, "%s\"%s\"", (j == 0 ? "" : ","), buf32);
     284           0 :     }
     285           0 :     EMIT_SIMPLE("],\"data\":\"");
     286           0 :     fd_web_reply_encode_base58(ws, raw + instr->data_off, instr->data_sz);
     287           0 :     char buf32[FD_BASE58_ENCODED_32_SZ];
     288           0 :     fd_base58_encode_32((const uchar*)(accts + instr->program_id), NULL, buf32);
     289           0 :     fd_web_reply_sprintf(ws, "\",\"program\":\"unknown\",\"programId\":\"%s\",\"stackHeight\":null}", buf32);
     290           0 :     *need_comma = 1;
     291           0 :   } FD_SPAD_FRAME_END;
     292           0 :   return NULL;
     293           0 : }
     294             : 
     295             : static const char *
     296             : vote_program_to_json( fd_webserver_t * ws,
     297             :                       fd_txn_t * txn,
     298             :                       fd_txn_instr_t * instr,
     299             :                       const uchar * raw,
     300             :                       int * need_comma,
     301           0 :                       fd_spad_t * spad ) {
     302           0 :   (void)txn;
     303           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
     304           0 :     if( *need_comma ) EMIT_SIMPLE(",");
     305             : 
     306           0 :     int decode_result;
     307           0 :     fd_vote_instruction_t * instruction = fd_bincode_decode_spad(
     308           0 :         vote_instruction,
     309           0 :         spad,
     310           0 :         raw + instr->data_off,
     311           0 :         instr->data_sz,
     312           0 :         &decode_result );
     313           0 :     if( FD_UNLIKELY( decode_result != FD_BINCODE_SUCCESS ) ) {
     314           0 :       EMIT_SIMPLE("null");
     315           0 :       return NULL;
     316           0 :     }
     317             : 
     318           0 :     EMIT_SIMPLE("{\"parsed\":");
     319             : 
     320           0 :     fd_rpc_json_t * json = fd_rpc_json_init( fd_rpc_json_new( fd_spad_alloc( spad, fd_rpc_json_align(), fd_rpc_json_footprint() ) ), ws );
     321           0 :     fd_vote_instruction_walk( json, instruction, fd_rpc_json_walk, NULL, 0, 0 );
     322             : 
     323           0 :     EMIT_SIMPLE(",\"program\":\"vote\",\"programId\":\"Vote111111111111111111111111111111111111111\",\"stackHeight\":null}");
     324           0 :     *need_comma = 1;
     325           0 :   } FD_SPAD_FRAME_END;
     326           0 :   return NULL;
     327           0 : }
     328             : 
     329             : static const char *
     330             : system_program_to_json( fd_webserver_t * ws,
     331             :                         fd_txn_t * txn,
     332             :                         fd_txn_instr_t * instr,
     333             :                         const uchar * raw,
     334             :                         int * need_comma,
     335           0 :                         fd_spad_t * spad ) {
     336           0 :   (void)txn;
     337           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
     338           0 :     if( *need_comma ) EMIT_SIMPLE(",");
     339             : 
     340           0 :     int decode_result;
     341           0 :     fd_system_program_instruction_t * instruction = fd_bincode_decode_spad(
     342           0 :         system_program_instruction,
     343           0 :         spad,
     344           0 :         raw + instr->data_off,
     345           0 :         instr->data_sz,
     346           0 :         &decode_result );
     347           0 :     if( FD_UNLIKELY( decode_result != FD_BINCODE_SUCCESS ) ) {
     348           0 :       EMIT_SIMPLE("null");
     349           0 :       return NULL;
     350           0 :     }
     351             : 
     352           0 :     EMIT_SIMPLE("{\"parsed\":");
     353             : 
     354           0 :     fd_rpc_json_t * json = fd_rpc_json_init( fd_rpc_json_new( fd_spad_alloc( spad, fd_rpc_json_align(), fd_rpc_json_footprint() ) ), ws );
     355           0 :     fd_system_program_instruction_walk( json, instruction, fd_rpc_json_walk, NULL, 0, 0 );
     356             : 
     357           0 :     EMIT_SIMPLE(",\"program\":\"system\",\"programId\":\"11111111111111111111111111111111\",\"stackHeight\":null}");
     358           0 :     *need_comma = 1;
     359           0 :   } FD_SPAD_FRAME_END;
     360           0 :   return NULL;
     361           0 : }
     362             : 
     363             : static const char *
     364             : config_program_to_json( fd_webserver_t * ws,
     365             :                         fd_txn_t * txn,
     366             :                         fd_txn_instr_t * instr,
     367             :                         const uchar * raw,
     368             :                         int * need_comma,
     369           0 :                         fd_spad_t * spad ) {
     370           0 :   FD_LOG_WARNING(( "config_program_to_json not implemented" ));
     371           0 :   generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     372           0 :   return NULL;
     373           0 : }
     374             : 
     375             : static const char *
     376             : stake_program_to_json( fd_webserver_t * ws,
     377             :                        fd_txn_t * txn,
     378             :                        fd_txn_instr_t * instr,
     379             :                        const uchar * raw,
     380             :                        int * need_comma,
     381           0 :                        fd_spad_t * spad ) {
     382           0 :   FD_LOG_WARNING(( "stake_program_to_json not implemented" ));
     383           0 :   generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     384           0 :   return NULL;
     385           0 : }
     386             : 
     387             : static const char *
     388             : compute_budget_program_to_json( fd_webserver_t * ws,
     389             :                                 fd_txn_t * txn,
     390             :                                 fd_txn_instr_t * instr,
     391             :                                 const uchar * raw,
     392             :                                 int * need_comma,
     393           0 :                                 fd_spad_t * spad ) {
     394           0 :   (void)txn;
     395           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
     396           0 :     if( *need_comma ) EMIT_SIMPLE(",");
     397             : 
     398           0 :     int decode_result;
     399           0 :     fd_compute_budget_program_instruction_t * instruction = fd_bincode_decode_spad(
     400           0 :         compute_budget_program_instruction,
     401           0 :         spad,
     402           0 :         raw + instr->data_off,
     403           0 :         instr->data_sz,
     404           0 :         &decode_result );
     405           0 :     if( FD_UNLIKELY( decode_result != FD_BINCODE_SUCCESS ) ) {
     406           0 :       EMIT_SIMPLE("null");
     407           0 :       return NULL;
     408           0 :     }
     409             : 
     410           0 :     EMIT_SIMPLE("{\"parsed\":");
     411             : 
     412           0 :     fd_rpc_json_t * json = fd_rpc_json_init( fd_rpc_json_new( fd_spad_alloc( spad, fd_rpc_json_align(), fd_rpc_json_footprint() ) ), ws );
     413           0 :     fd_compute_budget_program_instruction_walk( json, instruction, fd_rpc_json_walk, NULL, 0, 0 );
     414             : 
     415           0 :     EMIT_SIMPLE(",\"program\":\"compute_budget\",\"programId\":\"ComputeBudget111111111111111111111111111111\",\"stackHeight\":null}");
     416           0 :     *need_comma = 1;
     417           0 :   } FD_SPAD_FRAME_END;
     418           0 :   return NULL;
     419           0 : }
     420             : 
     421             : static const char *
     422             : address_lookup_table_program_to_json( fd_webserver_t * ws,
     423             :                                       fd_txn_t * txn,
     424             :                                       fd_txn_instr_t * instr,
     425             :                                       const uchar * raw,
     426             :                                       int * need_comma,
     427           0 :                                       fd_spad_t * spad ) {
     428           0 :   FD_LOG_WARNING(( "address_lookup_table_program_to_json not implemented" ));
     429           0 :   generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     430           0 :   return NULL;
     431           0 : }
     432             : 
     433             : static const char *
     434             : executor_zk_elgamal_proof_program_to_json( fd_webserver_t * ws,
     435             :                                            fd_txn_t * txn,
     436             :                                            fd_txn_instr_t * instr,
     437             :                                            const uchar * raw,
     438             :                                            int * need_comma,
     439           0 :                                            fd_spad_t * spad ) {
     440           0 :   FD_LOG_WARNING(( "executor_zk_elgamal_proof_program_to_json not implemented" ));
     441           0 :   generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     442           0 :   return NULL;
     443           0 : }
     444             : 
     445             : static const char *
     446             : bpf_loader_program_to_json( fd_webserver_t * ws,
     447             :                             fd_txn_t * txn,
     448             :                             fd_txn_instr_t * instr,
     449             :                             const uchar * raw,
     450             :                             int * need_comma,
     451           0 :                             fd_spad_t * spad ) {
     452           0 :   FD_LOG_WARNING(( "bpf_loader_program_to_json not implemented" ));
     453           0 :   generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     454           0 :   return NULL;
     455           0 : }
     456             : 
     457             : const char*
     458             : fd_instr_to_json( fd_webserver_t * ws,
     459             :                   fd_txn_t * txn,
     460             :                   fd_txn_instr_t * instr,
     461             :                   const uchar * raw,
     462             :                   fd_rpc_encoding_t encoding,
     463             :                   int * need_comma,
     464           0 :                   fd_spad_t * spad ) {
     465           0 :   if( encoding == FD_ENC_JSON ) {
     466           0 :     if( *need_comma ) EMIT_SIMPLE(",");
     467           0 :     EMIT_SIMPLE("{\"accounts\":[");
     468           0 :     const uchar * instr_acc_idxs = raw + instr->acct_off;
     469           0 :     for (ushort j = 0; j < instr->acct_cnt; j++) {
     470           0 :       fd_web_reply_sprintf(ws, "%s%u", (j == 0 ? "" : ","), (uint)instr_acc_idxs[j]);
     471           0 :     }
     472           0 :     EMIT_SIMPLE("],\"data\":\"");
     473           0 :     fd_web_reply_encode_base58(ws, raw + instr->data_off, instr->data_sz);
     474           0 :     fd_web_reply_sprintf(ws, "\",\"programIdIndex\":%u,\"stackHeight\":null}", (uint)instr->program_id);
     475           0 :     *need_comma = 1;
     476             : 
     477           0 :   } else if( encoding == FD_ENC_JSON_PARSED ) {
     478           0 :     ushort acct_cnt = txn->acct_addr_cnt;
     479           0 :     const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
     480           0 :     if( instr->program_id >= acct_cnt ) {
     481           0 :       return NULL;
     482           0 :     }
     483           0 :     const fd_pubkey_t * prog = accts + instr->program_id;
     484           0 :     if ( !memcmp( prog, fd_solana_vote_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     485           0 :       return vote_program_to_json( ws, txn, instr, raw, need_comma, spad );
     486           0 :     } else if ( !memcmp( prog, fd_solana_system_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     487           0 :       return system_program_to_json( ws, txn, instr, raw, need_comma, spad );
     488           0 :     } else if ( !memcmp( prog, fd_solana_config_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     489           0 :       return config_program_to_json( ws, txn, instr, raw, need_comma, spad );
     490           0 :     } else if ( !memcmp( prog, fd_solana_stake_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     491           0 :       return stake_program_to_json( ws, txn, instr, raw, need_comma, spad );
     492           0 :     } else if ( !memcmp( prog, fd_solana_compute_budget_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     493           0 :       return compute_budget_program_to_json( ws, txn, instr, raw, need_comma, spad );
     494           0 :     } else if( !memcmp( prog, fd_solana_address_lookup_table_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     495           0 :       return address_lookup_table_program_to_json( ws, txn, instr, raw, need_comma, spad );
     496           0 :     } else if( !memcmp( prog, fd_solana_zk_elgamal_proof_program_id.key, sizeof( fd_pubkey_t ) ) ) {
     497           0 :       return executor_zk_elgamal_proof_program_to_json( ws, txn, instr, raw, need_comma, spad );
     498           0 :     } else if( !memcmp( prog, fd_solana_bpf_loader_deprecated_program_id.key, sizeof( fd_pubkey_t ))) {
     499           0 :       return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma, spad );
     500           0 :     } else if( !memcmp( prog, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ) {
     501           0 :       return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma, spad );
     502           0 :     } else if( !memcmp( prog, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
     503           0 :       return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma, spad );
     504           0 :     } else {
     505           0 :       generic_program_to_json( ws, txn, instr, raw, need_comma, spad );
     506           0 :     }
     507           0 :   }
     508           0 :   return NULL;
     509           0 : }
     510             : 
     511             : const char*
     512             : fd_txn_to_json_full( fd_webserver_t * ws,
     513             :                      fd_txn_t* txn,
     514             :                      const uchar* raw,
     515             :                      ulong raw_sz,
     516             :                      fd_rpc_encoding_t encoding,
     517             :                      long maxvers,
     518           0 :                      fd_spad_t * spad ) {
     519           0 :   (void)maxvers;
     520             : 
     521           0 :   if( encoding == FD_ENC_BASE64 ) {
     522           0 :     EMIT_SIMPLE("\"transaction\":[\"");
     523           0 :     if (fd_web_reply_encode_base64(ws, raw, raw_sz)) {
     524           0 :       return "failed to encode data in base64";
     525           0 :     }
     526           0 :     EMIT_SIMPLE("\",\"base64\"]");
     527           0 :     return NULL;
     528           0 :   }
     529             : 
     530           0 :   if( encoding == FD_ENC_BASE58 ) {
     531           0 :     EMIT_SIMPLE("\"transaction\":[\"");
     532           0 :     if (fd_web_reply_encode_base58(ws, raw, raw_sz)) {
     533           0 :       return "failed to encode data in base58";
     534           0 :     }
     535           0 :     EMIT_SIMPLE("\",\"base58\"]");
     536           0 :     return NULL;
     537           0 :   }
     538             : 
     539           0 :   const char * err = fd_txn_meta_to_json( ws, NULL, 0 );
     540           0 :   if ( err ) return err;
     541             : 
     542           0 :   EMIT_SIMPLE("\"transaction\":{\"message\":{\"accountKeys\":[");
     543             : 
     544           0 :   ushort acct_cnt = txn->acct_addr_cnt;
     545           0 :   const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
     546           0 :   char buf32[FD_BASE58_ENCODED_32_SZ];
     547             : 
     548           0 :   if( encoding == FD_ENC_JSON ) {
     549           0 :     for (ushort idx = 0; idx < acct_cnt; idx++) {
     550           0 :       fd_base58_encode_32(accts[idx].uc, NULL, buf32);
     551           0 :       fd_web_reply_sprintf(ws, "%s\"%s\"", (idx == 0 ? "" : ","), buf32);
     552           0 :     }
     553           0 :   } else if( encoding == FD_ENC_JSON_PARSED ) {
     554           0 :     for (ushort idx = 0; idx < acct_cnt; idx++) {
     555           0 :       fd_base58_encode_32(accts[idx].uc, NULL, buf32);
     556           0 :       bool signer = (idx < txn->signature_cnt);
     557           0 :       bool writable = ((idx < txn->signature_cnt - txn->readonly_signed_cnt) ||
     558           0 :                        ((idx >= txn->signature_cnt) && (idx < acct_cnt - txn->readonly_unsigned_cnt)));
     559           0 :       fd_web_reply_sprintf(ws, "%s{\"pubkey\":\"%s\",\"signer\":%s,\"source\":\"transaction\",\"writable\":%s}",
     560           0 :                            (idx == 0 ? "" : ","), buf32, (signer ? "true" : "false"), (writable ? "true" : "false"));
     561           0 :     }
     562           0 :   }
     563             : 
     564           0 :   EMIT_SIMPLE("],");
     565             : 
     566           0 :   if( txn->transaction_version == FD_TXN_V0 ) {
     567           0 :     EMIT_SIMPLE("\"addressTableLookups\":[");
     568           0 :     fd_txn_acct_addr_lut_t const * addr_luts = fd_txn_get_address_tables_const( txn );
     569           0 :     for( ulong i = 0; i < txn->addr_table_lookup_cnt; i++ ) {
     570           0 :       if( i ) EMIT_SIMPLE(",");
     571           0 :       fd_txn_acct_addr_lut_t const * addr_lut = &addr_luts[i];
     572           0 :       fd_pubkey_t const * addr_lut_acc = (fd_pubkey_t *)(raw + addr_lut->addr_off);
     573           0 :       fd_base58_encode_32(addr_lut_acc->uc, NULL, buf32);
     574           0 :       fd_web_reply_sprintf(ws, "{\"accountKey\":\"%s\",\"readonlyIndexes\":[", buf32);
     575           0 :       uchar const * idxs = raw + addr_lut->readonly_off;
     576           0 :       for( uchar j = 0; j < addr_lut->readonly_cnt; j++ ) {
     577           0 :         if( j ) EMIT_SIMPLE(",");
     578           0 :         fd_web_reply_sprintf(ws, "%u", (uint)idxs[j]);
     579           0 :       }
     580           0 :       EMIT_SIMPLE("],\"writableIndexes\":[");
     581           0 :       idxs = raw + addr_lut->writable_off;
     582           0 :       for( uchar j = 0; j < addr_lut->writable_cnt; j++ ) {
     583           0 :         if( j ) EMIT_SIMPLE(",");
     584           0 :         fd_web_reply_sprintf(ws, "%u", (uint)idxs[j]);
     585           0 :       }
     586           0 :       EMIT_SIMPLE("]}");
     587           0 :     }
     588           0 :     EMIT_SIMPLE("],");
     589           0 :   }
     590             : 
     591           0 :   fd_web_reply_sprintf(ws, "\"header\":{\"numReadonlySignedAccounts\":%u,\"numReadonlyUnsignedAccounts\":%u,\"numRequiredSignatures\":%u},\"instructions\":[",
     592           0 :                        (uint)txn->readonly_signed_cnt, (uint)txn->readonly_unsigned_cnt, (uint)txn->signature_cnt);
     593             : 
     594           0 :   ushort instr_cnt = txn->instr_cnt;
     595           0 :   int need_comma = 0;
     596           0 :   for (ushort idx = 0; idx < instr_cnt; idx++) {
     597           0 :     const char * res = fd_instr_to_json( ws, txn, &txn->instr[idx], raw, encoding, &need_comma, spad );
     598           0 :     if( res ) return res;
     599           0 :   }
     600             : 
     601           0 :   const fd_hash_t * recent = (const fd_hash_t *)(raw + txn->recent_blockhash_off);
     602           0 :   fd_base58_encode_32(recent->uc, NULL, buf32);
     603           0 :   fd_web_reply_sprintf(ws, "],\"recentBlockhash\":\"%s\"},\"signatures\":[", buf32);
     604             : 
     605           0 :   fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
     606           0 :   for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
     607           0 :     char buf64[FD_BASE58_ENCODED_64_SZ];
     608           0 :     fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
     609           0 :     fd_web_reply_sprintf(ws, "%s\"%s\"", (j == 0 ? "" : ","), buf64);
     610           0 :   }
     611             : 
     612           0 :   const char* vers;
     613           0 :   switch (txn->transaction_version) {
     614           0 :   case FD_TXN_VLEGACY: vers = "\"legacy\""; break;
     615           0 :   case FD_TXN_V0:      vers = "0";          break;
     616           0 :   default:             vers = "\"?\"";      break;
     617           0 :   }
     618           0 :   fd_web_reply_sprintf(ws, "]},\"version\":%s", vers);
     619             : 
     620             : 
     621           0 :   return NULL;
     622           0 : }
     623             : 
     624             : const char*
     625             : fd_txn_to_json_accts( fd_webserver_t * ws,
     626             :                       fd_txn_t* txn,
     627             :                       const uchar* raw,
     628             :                       fd_rpc_encoding_t encoding,
     629           0 :                       long maxvers ) {
     630           0 :   (void)encoding;
     631           0 :   (void)maxvers;
     632             : 
     633           0 :   EMIT_SIMPLE("\"transaction\":{\"accountKeys\":[");
     634             : 
     635           0 :   ushort acct_cnt = txn->acct_addr_cnt;
     636           0 :   const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
     637           0 :   char buf32[FD_BASE58_ENCODED_32_SZ];
     638           0 :   for (ushort idx = 0; idx < acct_cnt; idx++) {
     639           0 :     fd_base58_encode_32(accts[idx].uc, NULL, buf32);
     640           0 :     bool signer = (idx < txn->signature_cnt);
     641           0 :     bool writable = ((idx < txn->signature_cnt - txn->readonly_signed_cnt) ||
     642           0 :                      ((idx >= txn->signature_cnt) && (idx < acct_cnt - txn->readonly_unsigned_cnt)));
     643           0 :     fd_web_reply_sprintf(ws, "%s{\"pubkey\":\"%s\",\"signer\":%s,\"source\":\"transaction\",\"writable\":%s}",
     644           0 :                          (idx == 0 ? "" : ","), buf32, (signer ? "true" : "false"), (writable ? "true" : "false"));
     645           0 :   }
     646             : 
     647           0 :   fd_web_reply_sprintf(ws, "],\"signatures\":[");
     648           0 :   fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
     649           0 :   for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
     650           0 :     char buf64[FD_BASE58_ENCODED_64_SZ];
     651           0 :     fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
     652           0 :     fd_web_reply_sprintf(ws, "%s\"%s\"", (j == 0 ? "" : ","), buf64);
     653           0 :   }
     654           0 :   EMIT_SIMPLE("]}");
     655             : 
     656           0 :   return NULL;
     657           0 : }
     658             : 
     659             : const char *
     660             : fd_txn_to_json( fd_webserver_t * ws,
     661             :                 fd_txn_t* txn,
     662             :                 const uchar* raw,
     663             :                 ulong raw_sz,
     664             :                 fd_rpc_encoding_t encoding,
     665             :                 long maxvers,
     666             :                 enum fd_block_detail detail,
     667           0 :                 fd_spad_t * spad ) {
     668           0 :   if( detail == FD_BLOCK_DETAIL_FULL )
     669           0 :     return fd_txn_to_json_full( ws, txn, raw, raw_sz, encoding, maxvers, spad );
     670           0 :   else if( detail == FD_BLOCK_DETAIL_ACCTS )
     671           0 :     return fd_txn_to_json_accts( ws, txn, raw, encoding, maxvers );
     672           0 :   return "unsupported detail parameter";
     673           0 : }
     674             : 
     675             : const char*
     676             : fd_block_to_json( fd_webserver_t * ws,
     677             :                   const char * call_id,
     678             :                   const uchar * blk_data,
     679             :                   ulong blk_sz,
     680             :                   fd_replay_notif_msg_t * info,
     681             :                   fd_replay_notif_msg_t * parent_info,
     682             :                   fd_rpc_encoding_t encoding,
     683             :                   long maxvers,
     684             :                   enum fd_block_detail detail,
     685             :                   fd_block_rewards_t * rewards,
     686           0 :                   fd_spad_t * spad ) {
     687           0 :   EMIT_SIMPLE("{\"jsonrpc\":\"2.0\",\"result\":{");
     688             : 
     689           0 :   char hash[50];
     690           0 :   fd_base58_encode_32(info->slot_exec.block_hash.uc, 0, hash);
     691           0 :   char phash[50];
     692           0 :   if( parent_info ) {
     693           0 :     fd_base58_encode_32(parent_info->slot_exec.block_hash.uc, 0, phash);
     694           0 :   } else {
     695           0 :     phash[0] = '\0';
     696           0 :   }
     697           0 :   fd_web_reply_sprintf(ws, "\"blockHeight\":%lu,\"blockTime\":%lu,\"parentSlot\":%lu,\"blockhash\":\"%s\",\"previousBlockhash\":\"%s\"",
     698           0 :                        info->slot_exec.height, info->slot_exec.ts/(ulong)1e9, info->slot_exec.parent, hash, phash);
     699             : 
     700           0 :   if( rewards ) {
     701           0 :     fd_base58_encode_32(rewards->leader.uc, 0, hash);
     702           0 :     fd_web_reply_sprintf(ws, ",\"rewards\":[{\"commission\":null,\"lamports\":%lu,\"postBalance\":%lu,\"pubkey\":\"%s\",\"rewardType\":\"Fee\"}]",
     703           0 :                          rewards->collected_fees,
     704           0 :                          rewards->post_balance,
     705           0 :                          hash);
     706           0 :   }
     707             : 
     708           0 :   if( detail == FD_BLOCK_DETAIL_NONE ) {
     709           0 :     fd_web_reply_sprintf(ws, "},\"id\":%s}", call_id);
     710           0 :     return 0;
     711           0 :   }
     712             : 
     713           0 :   EMIT_SIMPLE(",");
     714             : 
     715           0 :   if( detail == FD_BLOCK_DETAIL_SIGS ) {
     716           0 :     EMIT_SIMPLE("\"signatures\":[");
     717             : 
     718           0 :     int first_sig = 1;
     719           0 :     ulong blockoff = 0;
     720           0 :     while (blockoff < blk_sz) {
     721           0 :       if ( blockoff + sizeof(ulong) > blk_sz )
     722           0 :         FD_LOG_ERR(("premature end of block"));
     723           0 :       ulong mcount = *(const ulong *)(blk_data + blockoff);
     724           0 :       blockoff += sizeof(ulong);
     725             : 
     726             :       /* Loop across microblocks */
     727           0 :       for (ulong mblk = 0; mblk < mcount; ++mblk) {
     728           0 :         if ( blockoff + sizeof(fd_microblock_hdr_t) > blk_sz )
     729           0 :           FD_LOG_ERR(("premature end of block"));
     730           0 :         fd_microblock_hdr_t * hdr = (fd_microblock_hdr_t *)((const uchar *)blk_data + blockoff);
     731           0 :         blockoff += sizeof(fd_microblock_hdr_t);
     732             : 
     733             :         /* Loop across transactions */
     734           0 :         for ( ulong txn_idx = 0; txn_idx < hdr->txn_cnt; txn_idx++ ) {
     735           0 :           uchar txn_out[FD_TXN_MAX_SZ];
     736           0 :           ulong pay_sz = 0;
     737           0 :           const uchar* raw = (const uchar *)blk_data + blockoff;
     738           0 :           ulong txn_sz = fd_txn_parse_core(raw, fd_ulong_min(blk_sz - blockoff, FD_TXN_MTU), txn_out, NULL, &pay_sz);
     739           0 :           if ( txn_sz == 0 || txn_sz > FD_TXN_MAX_SZ ) {
     740           0 :             FD_LOG_WARNING( ( "failed to parse transaction %lu in microblock %lu",
     741           0 :                               txn_idx,
     742           0 :                               mblk ) );
     743           0 :             return "failed to parse transaction";
     744           0 :           }
     745           0 :           fd_txn_t * txn = (fd_txn_t *)txn_out;
     746             : 
     747             :           /* Loop across signatures */
     748           0 :           fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
     749           0 :           for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
     750           0 :             char buf64[FD_BASE58_ENCODED_64_SZ];
     751           0 :             fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
     752           0 :             fd_web_reply_sprintf(ws, "%s\"%s\"", (first_sig ? "" : ","), buf64);
     753           0 :             first_sig = 0;
     754           0 :           }
     755             : 
     756           0 :           blockoff += pay_sz;
     757           0 :         }
     758           0 :       }
     759           0 :     }
     760           0 :     if ( blockoff != blk_sz )
     761           0 :       FD_LOG_ERR(("garbage at end of block"));
     762             : 
     763           0 :     fd_web_reply_sprintf(ws, "]},\"id\":%s}", call_id);
     764           0 :     return NULL;
     765           0 :   }
     766             : 
     767           0 :   EMIT_SIMPLE("\"transactions\":[");
     768             : 
     769           0 :   int first_txn = 1;
     770           0 :   ulong blockoff = 0;
     771           0 :   while (blockoff < blk_sz) {
     772           0 :     if ( blockoff + sizeof(ulong) > blk_sz )
     773           0 :       FD_LOG_ERR(("premature end of block"));
     774           0 :     ulong mcount = *(const ulong *)(blk_data + blockoff);
     775           0 :     blockoff += sizeof(ulong);
     776             : 
     777             :     /* Loop across microblocks */
     778           0 :     for (ulong mblk = 0; mblk < mcount; ++mblk) {
     779           0 :       if ( blockoff + sizeof(fd_microblock_hdr_t) > blk_sz )
     780           0 :         FD_LOG_ERR(("premature end of block"));
     781           0 :       fd_microblock_hdr_t * hdr = (fd_microblock_hdr_t *)((const uchar *)blk_data + blockoff);
     782           0 :       blockoff += sizeof(fd_microblock_hdr_t);
     783             : 
     784             :       /* Loop across transactions */
     785           0 :       for ( ulong txn_idx = 0; txn_idx < hdr->txn_cnt; txn_idx++ ) {
     786           0 :         uchar txn_out[FD_TXN_MAX_SZ];
     787           0 :         ulong pay_sz = 0;
     788           0 :         const uchar* raw = (const uchar *)blk_data + blockoff;
     789           0 :         ulong txn_sz = fd_txn_parse_core(raw, fd_ulong_min(blk_sz - blockoff, FD_TXN_MTU), txn_out, NULL, &pay_sz);
     790           0 :         if ( txn_sz == 0 || txn_sz > FD_TXN_MAX_SZ ) {
     791           0 :           FD_LOG_WARNING( ( "failed to parse transaction %lu in microblock %lu",
     792           0 :                             txn_idx,
     793           0 :                             mblk ) );
     794           0 :           return "failed to parse transaction";
     795           0 :         }
     796           0 :         if (first_txn) {
     797           0 :           first_txn = 0;
     798           0 :           EMIT_SIMPLE("{");
     799           0 :         } else
     800           0 :           EMIT_SIMPLE(",{");
     801             : 
     802           0 :         const char * err = fd_txn_to_json( ws, (fd_txn_t *)txn_out, raw, pay_sz, encoding, maxvers, detail, spad );
     803           0 :         if ( err ) return err;
     804             : 
     805           0 :         EMIT_SIMPLE("}");
     806             : 
     807           0 :         blockoff += pay_sz;
     808           0 :       }
     809           0 :     }
     810           0 :   }
     811           0 :   if ( blockoff != blk_sz )
     812           0 :     FD_LOG_ERR(("garbage at end of block"));
     813             : 
     814           0 :   fd_web_reply_sprintf(ws, "]},\"id\":%s}", call_id);
     815             : 
     816           0 :   return NULL;
     817           0 : }
     818             : 
     819             : const char*
     820             : fd_account_to_json( fd_webserver_t * ws,
     821             :                     fd_pubkey_t acct,
     822             :                     fd_rpc_encoding_t enc,
     823             :                     uchar const * val,
     824             :                     ulong val_sz,
     825             :                     long off,
     826             :                     long len,
     827           0 :                     fd_spad_t * spad ) {
     828           0 :   fd_web_reply_sprintf(ws, "{\"data\":[\"");
     829             : 
     830           0 :   fd_account_meta_t * metadata = (fd_account_meta_t *)val;
     831           0 :   if (val_sz < sizeof(fd_account_meta_t) && val_sz < metadata->hlen) {
     832           0 :     return "failed to load account data";
     833           0 :   }
     834           0 :   val = (uchar*)val + metadata->hlen;
     835           0 :   val_sz = val_sz - metadata->hlen;
     836           0 :   if (val_sz > metadata->dlen)
     837           0 :     val_sz = metadata->dlen;
     838             : 
     839           0 :   if (len != FD_LONG_UNSET && off != FD_LONG_UNSET) {
     840           0 :     if (enc == FD_ENC_JSON) {
     841           0 :       return "cannot use jsonParsed encoding with slice";
     842           0 :     }
     843           0 :     if (off < 0 || (ulong)off >= val_sz) {
     844           0 :       val = NULL;
     845           0 :       val_sz = 0;
     846           0 :     } else {
     847           0 :       val = (uchar*)val + (ulong)off;
     848           0 :       val_sz = val_sz - (ulong)off;
     849           0 :     }
     850           0 :     if (len < 0) {
     851           0 :       val = NULL;
     852           0 :       val_sz = 0;
     853           0 :     } else if ((ulong)len < val_sz)
     854           0 :       val_sz = (ulong)len;
     855           0 :   }
     856             : 
     857           0 :   const char* encstr;
     858           0 :   switch (enc) {
     859           0 :   case FD_ENC_BASE58:
     860           0 :     if (fd_web_reply_encode_base58(ws, val, val_sz)) {
     861           0 :       return "failed to encode data in base58";
     862           0 :     }
     863           0 :     encstr = "base58";
     864           0 :     break;
     865           0 :   case FD_ENC_BASE64:
     866           0 :   case FD_ENC_JSON:
     867           0 :     if (fd_web_reply_encode_base64(ws, val, val_sz)) {
     868           0 :       return "failed to encode data in base64";
     869           0 :     }
     870           0 :     encstr = "base64";
     871           0 :     break;
     872           0 : # if FD_HAS_ZSTD
     873           0 :   case FD_ENC_BASE64_ZSTD: {
     874           0 :     size_t const cBuffSize = ZSTD_compressBound( val_sz );
     875           0 :     void * cBuff = fd_spad_alloc( spad, 1, cBuffSize );
     876           0 :     size_t const cSize = ZSTD_compress( cBuff, cBuffSize, val, val_sz, 1 );
     877           0 :     if (fd_web_reply_encode_base64(ws, cBuff, cSize)) {
     878           0 :       return "failed to encode data in base64";
     879           0 :     }
     880           0 :     encstr = "base64+zstd";
     881           0 :     break;
     882           0 :   }
     883             : # else
     884             :   (void)spad;
     885             : # endif /* FD_HAS_ZSTD */
     886           0 :   default:
     887           0 :     return "unsupported encoding";
     888           0 :   }
     889             : 
     890           0 :   char owner[50];
     891           0 :   fd_base58_encode_32((uchar*)metadata->info.owner, 0, owner);
     892           0 :   char addr[50];
     893           0 :   fd_base58_encode_32(acct.uc, 0, addr);
     894           0 :   fd_web_reply_sprintf(ws, "\",\"%s\"],\"executable\":%s,\"lamports\":%lu,\"owner\":\"%s\",\"address\":\"%s\",\"rentEpoch\":%lu,\"space\":%lu}",
     895           0 :                        encstr,
     896           0 :                        (metadata->info.executable ? "true" : "false"),
     897           0 :                        metadata->info.lamports,
     898           0 :                        owner,
     899           0 :                        addr,
     900           0 :                        metadata->info.rent_epoch,
     901           0 :                        val_sz);
     902             : 
     903             :   return NULL;
     904           0 : }

Generated by: LCOV version 1.14