LCOV - code coverage report
Current view: top level - flamenco/rpcserver - fd_block_to_json.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 676 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 21 0.0 %

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

Generated by: LCOV version 1.14