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