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