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