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

Generated by: LCOV version 1.14