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