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_vote_instruction_t instruction;
306 0 : fd_bincode_decode_ctx_t decode = {
307 0 : .data = raw + instr->data_off,
308 0 : .dataend = raw + instr->data_off + instr->data_sz,
309 0 : .valloc = fd_scratch_virtual()
310 0 : };
311 0 : int decode_result = fd_vote_instruction_decode( &instruction, &decode );
312 0 : if( decode_result != FD_BINCODE_SUCCESS ) {
313 0 : EMIT_SIMPLE("null");
314 0 : return NULL;
315 0 : }
316 :
317 0 : EMIT_SIMPLE("{\"parsed\":");
318 :
319 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 );
320 0 : fd_vote_instruction_walk( json, &instruction, fd_rpc_json_walk, NULL, 0 );
321 :
322 0 : EMIT_SIMPLE(",\"program\":\"vote\",\"programId\":\"Vote111111111111111111111111111111111111111\",\"stackHeight\":null}");
323 0 : *need_comma = 1;
324 0 : } FD_SCRATCH_SCOPE_END;
325 0 : return NULL;
326 0 : }
327 :
328 : const char *
329 : system_program_to_json( fd_webserver_t * ws,
330 : fd_txn_t * txn,
331 : fd_txn_instr_t * instr,
332 : const uchar * raw,
333 0 : int * need_comma ) {
334 0 : (void)txn;
335 0 : FD_SCRATCH_SCOPE_BEGIN { /* read_epoch consumes a ton of scratch space! */
336 0 : if( *need_comma ) EMIT_SIMPLE(",");
337 0 : fd_system_program_instruction_t instruction;
338 0 : fd_bincode_decode_ctx_t decode = {
339 0 : .data = raw + instr->data_off,
340 0 : .dataend = raw + instr->data_off + instr->data_sz,
341 0 : .valloc = fd_scratch_virtual()
342 0 : };
343 0 : int decode_result = fd_system_program_instruction_decode( &instruction, &decode );
344 0 : if( decode_result != FD_BINCODE_SUCCESS ) {
345 0 : EMIT_SIMPLE("null");
346 0 : return NULL;
347 0 : }
348 :
349 0 : EMIT_SIMPLE("{\"parsed\":");
350 :
351 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 );
352 0 : fd_system_program_instruction_walk( json, &instruction, fd_rpc_json_walk, NULL, 0 );
353 :
354 0 : EMIT_SIMPLE(",\"program\":\"system\",\"programId\":\"11111111111111111111111111111111\",\"stackHeight\":null}");
355 0 : *need_comma = 1;
356 0 : } FD_SCRATCH_SCOPE_END;
357 0 : return NULL;
358 0 : }
359 :
360 : const char*
361 : config_program_to_json( fd_webserver_t * ws,
362 : fd_txn_t * txn,
363 : fd_txn_instr_t * instr,
364 : const uchar * raw,
365 0 : int * need_comma ) {
366 0 : FD_LOG_WARNING(( "config_program_to_json not implemented" ));
367 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
368 0 : return NULL;
369 0 : }
370 :
371 : const char*
372 : stake_program_to_json( fd_webserver_t * ws,
373 : fd_txn_t * txn,
374 : fd_txn_instr_t * instr,
375 : const uchar * raw,
376 0 : int * need_comma ) {
377 0 : FD_LOG_WARNING(( "stake_program_to_json not implemented" ));
378 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
379 0 : return NULL;
380 0 : }
381 :
382 : const char*
383 : compute_budget_program_to_json( fd_webserver_t * ws,
384 : fd_txn_t * txn,
385 : fd_txn_instr_t * instr,
386 : const uchar * raw,
387 0 : int * need_comma ) {
388 0 : (void)txn;
389 0 : FD_SCRATCH_SCOPE_BEGIN { /* read_epoch consumes a ton of scratch space! */
390 0 : if( *need_comma ) EMIT_SIMPLE(",");
391 0 : fd_compute_budget_program_instruction_t instruction;
392 0 : fd_bincode_decode_ctx_t decode = {
393 0 : .data = raw + instr->data_off,
394 0 : .dataend = raw + instr->data_off + instr->data_sz,
395 0 : .valloc = fd_scratch_virtual()
396 0 : };
397 0 : int decode_result = fd_compute_budget_program_instruction_decode( &instruction, &decode );
398 0 : if( decode_result != FD_BINCODE_SUCCESS ) {
399 0 : EMIT_SIMPLE("null");
400 0 : return NULL;
401 0 : }
402 :
403 0 : EMIT_SIMPLE("{\"parsed\":");
404 :
405 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 );
406 0 : fd_compute_budget_program_instruction_walk( json, &instruction, fd_rpc_json_walk, NULL, 0 );
407 :
408 0 : EMIT_SIMPLE(",\"program\":\"compute_budget\",\"programId\":\"ComputeBudget111111111111111111111111111111\",\"stackHeight\":null}");
409 0 : *need_comma = 1;
410 0 : } FD_SCRATCH_SCOPE_END;
411 0 : return NULL;
412 0 : }
413 :
414 : const char*
415 : address_lookup_table_program_to_json( fd_webserver_t * ws,
416 : fd_txn_t * txn,
417 : fd_txn_instr_t * instr,
418 : const uchar * raw,
419 0 : int * need_comma ) {
420 0 : FD_LOG_WARNING(( "address_lookup_table_program_to_json not implemented" ));
421 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
422 0 : return NULL;
423 0 : }
424 :
425 : const char*
426 : executor_zk_elgamal_proof_program_to_json( fd_webserver_t * ws,
427 : fd_txn_t * txn,
428 : fd_txn_instr_t * instr,
429 : const uchar * raw,
430 0 : int * need_comma ) {
431 0 : FD_LOG_WARNING(( "executor_zk_elgamal_proof_program_to_json not implemented" ));
432 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
433 0 : return NULL;
434 0 : }
435 :
436 : const char*
437 : bpf_loader_program_to_json( fd_webserver_t * ws,
438 : fd_txn_t * txn,
439 : fd_txn_instr_t * instr,
440 : const uchar * raw,
441 0 : int * need_comma ) {
442 0 : FD_LOG_WARNING(( "bpf_loader_program_to_json not implemented" ));
443 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
444 0 : return NULL;
445 0 : }
446 :
447 : const char*
448 : fd_instr_to_json( fd_webserver_t * ws,
449 : fd_txn_t * txn,
450 : fd_txn_instr_t * instr,
451 : const uchar * raw,
452 : fd_rpc_encoding_t encoding,
453 0 : int * need_comma ) {
454 0 : if( encoding == FD_ENC_JSON ) {
455 0 : if( *need_comma ) EMIT_SIMPLE(",");
456 0 : EMIT_SIMPLE("{\"accounts\":[");
457 0 : const uchar * instr_acc_idxs = raw + instr->acct_off;
458 0 : for (ushort j = 0; j < instr->acct_cnt; j++) {
459 0 : fd_web_reply_sprintf(ws, "%s%u", (j == 0 ? "" : ","), (uint)instr_acc_idxs[j]);
460 0 : }
461 0 : EMIT_SIMPLE("],\"data\":\"");
462 0 : fd_web_reply_encode_base58(ws, raw + instr->data_off, instr->data_sz);
463 0 : fd_web_reply_sprintf(ws, "\",\"programIdIndex\":%u,\"stackHeight\":null}", (uint)instr->program_id);
464 0 : *need_comma = 1;
465 :
466 0 : } else if( encoding == FD_ENC_JSON_PARSED ) {
467 0 : ushort acct_cnt = txn->acct_addr_cnt;
468 0 : const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
469 0 : if( instr->program_id >= acct_cnt ) {
470 0 : return NULL;
471 0 : }
472 0 : const fd_pubkey_t * prog = accts + instr->program_id;
473 0 : if ( !memcmp( prog, fd_solana_vote_program_id.key, sizeof( fd_pubkey_t ) ) ) {
474 0 : return vote_program_to_json( ws, txn, instr, raw, need_comma );
475 0 : } else if ( !memcmp( prog, fd_solana_system_program_id.key, sizeof( fd_pubkey_t ) ) ) {
476 0 : return system_program_to_json( ws, txn, instr, raw, need_comma );
477 0 : } else if ( !memcmp( prog, fd_solana_config_program_id.key, sizeof( fd_pubkey_t ) ) ) {
478 0 : return config_program_to_json( ws, txn, instr, raw, need_comma );
479 0 : } else if ( !memcmp( prog, fd_solana_stake_program_id.key, sizeof( fd_pubkey_t ) ) ) {
480 0 : return stake_program_to_json( ws, txn, instr, raw, need_comma );
481 0 : } else if ( !memcmp( prog, fd_solana_compute_budget_program_id.key, sizeof( fd_pubkey_t ) ) ) {
482 0 : return compute_budget_program_to_json( ws, txn, instr, raw, need_comma );
483 0 : } else if( !memcmp( prog, fd_solana_address_lookup_table_program_id.key, sizeof( fd_pubkey_t ) ) ) {
484 0 : return address_lookup_table_program_to_json( ws, txn, instr, raw, need_comma );
485 0 : } else if( !memcmp( prog, fd_solana_zk_elgamal_proof_program_id.key, sizeof( fd_pubkey_t ) ) ) {
486 0 : return executor_zk_elgamal_proof_program_to_json( ws, txn, instr, raw, need_comma );
487 0 : } else if( !memcmp( prog, fd_solana_bpf_loader_deprecated_program_id.key, sizeof( fd_pubkey_t ))) {
488 0 : return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma );
489 0 : } else if( !memcmp( prog, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ) {
490 0 : return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma );
491 0 : } else if( !memcmp( prog, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
492 0 : return bpf_loader_program_to_json( ws, txn, instr, raw, need_comma );
493 0 : } else {
494 0 : generic_program_to_json( ws, txn, instr, raw, need_comma );
495 0 : }
496 0 : }
497 0 : return NULL;
498 0 : }
499 :
500 : const char*
501 : fd_txn_to_json_full( fd_webserver_t * ws,
502 : fd_txn_t* txn,
503 : const uchar* raw,
504 : ulong raw_sz,
505 : fd_rpc_encoding_t encoding,
506 0 : long maxvers ) {
507 0 : (void)maxvers;
508 :
509 0 : if( encoding == FD_ENC_BASE64 ) {
510 0 : EMIT_SIMPLE("\"transaction\":[\"");
511 0 : if (fd_web_reply_encode_base64(ws, raw, raw_sz)) {
512 0 : return "failed to encode data in base64";
513 0 : }
514 0 : EMIT_SIMPLE("\",\"base64\"]");
515 0 : return NULL;
516 0 : }
517 :
518 0 : if( encoding == FD_ENC_BASE58 ) {
519 0 : EMIT_SIMPLE("\"transaction\":[\"");
520 0 : if (fd_web_reply_encode_base58(ws, raw, raw_sz)) {
521 0 : return "failed to encode data in base58";
522 0 : }
523 0 : EMIT_SIMPLE("\",\"base58\"]");
524 0 : return NULL;
525 0 : }
526 :
527 0 : EMIT_SIMPLE("\"transaction\":{\"message\":{\"accountKeys\":[");
528 :
529 0 : ushort acct_cnt = txn->acct_addr_cnt;
530 0 : const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
531 0 : char buf32[FD_BASE58_ENCODED_32_SZ];
532 :
533 0 : if( encoding == FD_ENC_JSON ) {
534 0 : for (ushort idx = 0; idx < acct_cnt; idx++) {
535 0 : fd_base58_encode_32(accts[idx].uc, NULL, buf32);
536 0 : fd_web_reply_sprintf(ws, "%s\"%s\"", (idx == 0 ? "" : ","), buf32);
537 0 : }
538 0 : } else if( encoding == FD_ENC_JSON_PARSED ) {
539 0 : for (ushort idx = 0; idx < acct_cnt; idx++) {
540 0 : fd_base58_encode_32(accts[idx].uc, NULL, buf32);
541 0 : bool signer = (idx < txn->signature_cnt);
542 0 : bool writable = ((idx < txn->signature_cnt - txn->readonly_signed_cnt) ||
543 0 : ((idx >= txn->signature_cnt) && (idx < acct_cnt - txn->readonly_unsigned_cnt)));
544 0 : fd_web_reply_sprintf(ws, "%s{\"pubkey\":\"%s\",\"signer\":%s,\"source\":\"transaction\",\"writable\":%s}",
545 0 : (idx == 0 ? "" : ","), buf32, (signer ? "true" : "false"), (writable ? "true" : "false"));
546 0 : }
547 0 : }
548 :
549 0 : EMIT_SIMPLE("],");
550 :
551 0 : if( txn->transaction_version == FD_TXN_V0 ) {
552 0 : EMIT_SIMPLE("\"addressTableLookups\":[");
553 0 : fd_txn_acct_addr_lut_t const * addr_luts = fd_txn_get_address_tables_const( txn );
554 0 : for( ulong i = 0; i < txn->addr_table_lookup_cnt; i++ ) {
555 0 : if( i ) EMIT_SIMPLE(",");
556 0 : fd_txn_acct_addr_lut_t const * addr_lut = &addr_luts[i];
557 0 : fd_pubkey_t const * addr_lut_acc = (fd_pubkey_t *)(raw + addr_lut->addr_off);
558 0 : fd_base58_encode_32(addr_lut_acc->uc, NULL, buf32);
559 0 : fd_web_reply_sprintf(ws, "{\"accountKey\":\"%s\",\"readonlyIndexes\":[", buf32);
560 0 : uchar const * idxs = raw + addr_lut->readonly_off;
561 0 : for( uchar j = 0; j < addr_lut->readonly_cnt; j++ ) {
562 0 : if( j ) EMIT_SIMPLE(",");
563 0 : fd_web_reply_sprintf(ws, "%u", (uint)idxs[j]);
564 0 : }
565 0 : EMIT_SIMPLE("],\"writableIndexes\":[");
566 0 : idxs = raw + addr_lut->writable_off;
567 0 : for( uchar j = 0; j < addr_lut->writable_cnt; j++ ) {
568 0 : if( j ) EMIT_SIMPLE(",");
569 0 : fd_web_reply_sprintf(ws, "%u", (uint)idxs[j]);
570 0 : }
571 0 : EMIT_SIMPLE("]}");
572 0 : }
573 0 : EMIT_SIMPLE("],");
574 0 : }
575 :
576 0 : fd_web_reply_sprintf(ws, "\"header\":{\"numReadonlySignedAccounts\":%u,\"numReadonlyUnsignedAccounts\":%u,\"numRequiredSignatures\":%u},\"instructions\":[",
577 0 : (uint)txn->readonly_signed_cnt, (uint)txn->readonly_unsigned_cnt, (uint)txn->signature_cnt);
578 :
579 0 : ushort instr_cnt = txn->instr_cnt;
580 0 : int need_comma = 0;
581 0 : for (ushort idx = 0; idx < instr_cnt; idx++) {
582 0 : const char * res = fd_instr_to_json( ws, txn, &txn->instr[idx], raw, encoding, &need_comma );
583 0 : if( res ) return res;
584 0 : }
585 :
586 0 : const fd_hash_t * recent = (const fd_hash_t *)(raw + txn->recent_blockhash_off);
587 0 : fd_base58_encode_32(recent->uc, NULL, buf32);
588 0 : fd_web_reply_sprintf(ws, "],\"recentBlockhash\":\"%s\"},\"signatures\":[", buf32);
589 :
590 0 : fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
591 0 : for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
592 0 : char buf64[FD_BASE58_ENCODED_64_SZ];
593 0 : fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
594 0 : fd_web_reply_sprintf(ws, "%s\"%s\"", (j == 0 ? "" : ","), buf64);
595 0 : }
596 :
597 0 : const char* vers;
598 0 : switch (txn->transaction_version) {
599 0 : case FD_TXN_VLEGACY: vers = "\"legacy\""; break;
600 0 : case FD_TXN_V0: vers = "0"; break;
601 0 : default: vers = "\"?\""; break;
602 0 : }
603 0 : fd_web_reply_sprintf(ws, "]},\"version\":%s", vers);
604 :
605 :
606 0 : return NULL;
607 0 : }
608 :
609 : const char*
610 : fd_txn_to_json_accts( fd_webserver_t * ws,
611 : fd_txn_t* txn,
612 : const uchar* raw,
613 : fd_rpc_encoding_t encoding,
614 0 : long maxvers ) {
615 0 : (void)encoding;
616 0 : (void)maxvers;
617 :
618 0 : EMIT_SIMPLE("\"transaction\":{\"accountKeys\":[");
619 :
620 0 : ushort acct_cnt = txn->acct_addr_cnt;
621 0 : const fd_pubkey_t * accts = (const fd_pubkey_t *)(raw + txn->acct_addr_off);
622 0 : char buf32[FD_BASE58_ENCODED_32_SZ];
623 0 : for (ushort idx = 0; idx < acct_cnt; idx++) {
624 0 : fd_base58_encode_32(accts[idx].uc, NULL, buf32);
625 0 : bool signer = (idx < txn->signature_cnt);
626 0 : bool writable = ((idx < txn->signature_cnt - txn->readonly_signed_cnt) ||
627 0 : ((idx >= txn->signature_cnt) && (idx < acct_cnt - txn->readonly_unsigned_cnt)));
628 0 : fd_web_reply_sprintf(ws, "%s{\"pubkey\":\"%s\",\"signer\":%s,\"source\":\"transaction\",\"writable\":%s}",
629 0 : (idx == 0 ? "" : ","), buf32, (signer ? "true" : "false"), (writable ? "true" : "false"));
630 0 : }
631 :
632 0 : fd_web_reply_sprintf(ws, "],\"signatures\":[");
633 0 : fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
634 0 : for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
635 0 : char buf64[FD_BASE58_ENCODED_64_SZ];
636 0 : fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
637 0 : fd_web_reply_sprintf(ws, "%s\"%s\"", (j == 0 ? "" : ","), buf64);
638 0 : }
639 0 : EMIT_SIMPLE("]}");
640 :
641 0 : return NULL;
642 0 : }
643 :
644 : const char *
645 : fd_txn_to_json( fd_webserver_t * ws,
646 : fd_txn_t* txn,
647 : const uchar* raw,
648 : ulong raw_sz,
649 : fd_rpc_encoding_t encoding,
650 : long maxvers,
651 0 : enum fd_block_detail detail ) {
652 0 : if( detail == FD_BLOCK_DETAIL_FULL )
653 0 : return fd_txn_to_json_full( ws, txn, raw, raw_sz, encoding, maxvers );
654 0 : else if( detail == FD_BLOCK_DETAIL_ACCTS )
655 0 : return fd_txn_to_json_accts( ws, txn, raw, encoding, maxvers );
656 0 : return "unsupported detail parameter";
657 0 : }
658 :
659 : const char*
660 : fd_block_to_json( fd_webserver_t * ws,
661 : fd_blockstore_t * blockstore,
662 : int blockstore_fd,
663 : const char * call_id,
664 : const uchar * blk_data,
665 : ulong blk_sz,
666 : fd_block_map_t * meta,
667 : fd_hash_t * parent_hash,
668 : fd_rpc_encoding_t encoding,
669 : long maxvers,
670 : enum fd_block_detail detail,
671 0 : fd_block_rewards_t * rewards ) {
672 0 : EMIT_SIMPLE("{\"jsonrpc\":\"2.0\",\"result\":{");
673 :
674 0 : char hash[50];
675 0 : fd_base58_encode_32(meta->block_hash.uc, 0, hash);
676 0 : char phash[50];
677 0 : fd_base58_encode_32(parent_hash->uc, 0, phash);
678 0 : fd_web_reply_sprintf(ws, "\"blockHeight\":%lu,\"blockTime\":%ld,\"parentSlot\":%lu,\"blockhash\":\"%s\",\"previousBlockhash\":\"%s\"",
679 0 : meta->height, meta->ts/(long)1e9, meta->parent_slot, hash, phash);
680 :
681 0 : if( rewards ) {
682 0 : fd_base58_encode_32(rewards->leader.uc, 0, hash);
683 0 : fd_web_reply_sprintf(ws, ",\"rewards\":[{\"commission\":null,\"lamports\":%lu,\"postBalance\":%lu,\"pubkey\":\"%s\",\"rewardType\":\"Fee\"}]",
684 0 : rewards->collected_fees,
685 0 : rewards->post_balance,
686 0 : hash);
687 0 : }
688 :
689 0 : if( detail == FD_BLOCK_DETAIL_NONE ) {
690 0 : fd_web_reply_sprintf(ws, "},\"id\":%s}", call_id);
691 0 : return 0;
692 0 : }
693 :
694 0 : EMIT_SIMPLE(",");
695 :
696 0 : if( detail == FD_BLOCK_DETAIL_SIGS ) {
697 0 : EMIT_SIMPLE("\"signatures\":[");
698 :
699 0 : int first_sig = 1;
700 0 : ulong blockoff = 0;
701 0 : while (blockoff < blk_sz) {
702 0 : if ( blockoff + sizeof(ulong) > blk_sz )
703 0 : FD_LOG_ERR(("premature end of block"));
704 0 : ulong mcount = *(const ulong *)(blk_data + blockoff);
705 0 : blockoff += sizeof(ulong);
706 :
707 : /* Loop across microblocks */
708 0 : for (ulong mblk = 0; mblk < mcount; ++mblk) {
709 0 : if ( blockoff + sizeof(fd_microblock_hdr_t) > blk_sz )
710 0 : FD_LOG_ERR(("premature end of block"));
711 0 : fd_microblock_hdr_t * hdr = (fd_microblock_hdr_t *)((const uchar *)blk_data + blockoff);
712 0 : blockoff += sizeof(fd_microblock_hdr_t);
713 :
714 : /* Loop across transactions */
715 0 : for ( ulong txn_idx = 0; txn_idx < hdr->txn_cnt; txn_idx++ ) {
716 0 : uchar txn_out[FD_TXN_MAX_SZ];
717 0 : ulong pay_sz = 0;
718 0 : const uchar* raw = (const uchar *)blk_data + blockoff;
719 0 : ulong txn_sz = fd_txn_parse_core(raw, fd_ulong_min(blk_sz - blockoff, FD_TXN_MTU), txn_out, NULL, &pay_sz);
720 0 : if ( txn_sz == 0 || txn_sz > FD_TXN_MAX_SZ ) {
721 0 : FD_LOG_WARNING( ( "failed to parse transaction %lu in microblock %lu",
722 0 : txn_idx,
723 0 : mblk ) );
724 0 : return "failed to parse transaction";
725 0 : }
726 0 : fd_txn_t * txn = (fd_txn_t *)txn_out;
727 :
728 : /* Loop across signatures */
729 0 : fd_ed25519_sig_t const * sigs = (fd_ed25519_sig_t const *)(raw + txn->signature_off);
730 0 : for ( uchar j = 0; j < txn->signature_cnt; j++ ) {
731 0 : char buf64[FD_BASE58_ENCODED_64_SZ];
732 0 : fd_base58_encode_64((const uchar*)&sigs[j], NULL, buf64);
733 0 : fd_web_reply_sprintf(ws, "%s\"%s\"", (first_sig ? "" : ","), buf64);
734 0 : first_sig = 0;
735 0 : }
736 :
737 0 : blockoff += pay_sz;
738 0 : }
739 0 : }
740 0 : }
741 0 : if ( blockoff != blk_sz )
742 0 : FD_LOG_ERR(("garbage at end of block"));
743 :
744 0 : fd_web_reply_sprintf(ws, "]},\"id\":%s}", call_id);
745 0 : return NULL;
746 0 : }
747 :
748 0 : EMIT_SIMPLE("\"transactions\":[");
749 :
750 0 : fd_wksp_t * blockstore_wksp = fd_blockstore_wksp( blockstore );
751 :
752 0 : int first_txn = 1;
753 0 : ulong blockoff = 0;
754 0 : while (blockoff < blk_sz) {
755 0 : if ( blockoff + sizeof(ulong) > blk_sz )
756 0 : FD_LOG_ERR(("premature end of block"));
757 0 : ulong mcount = *(const ulong *)(blk_data + blockoff);
758 0 : blockoff += sizeof(ulong);
759 :
760 : /* Loop across microblocks */
761 0 : for (ulong mblk = 0; mblk < mcount; ++mblk) {
762 0 : if ( blockoff + sizeof(fd_microblock_hdr_t) > blk_sz )
763 0 : FD_LOG_ERR(("premature end of block"));
764 0 : fd_microblock_hdr_t * hdr = (fd_microblock_hdr_t *)((const uchar *)blk_data + blockoff);
765 0 : blockoff += sizeof(fd_microblock_hdr_t);
766 :
767 : /* Loop across transactions */
768 0 : for ( ulong txn_idx = 0; txn_idx < hdr->txn_cnt; txn_idx++ ) {
769 0 : uchar txn_out[FD_TXN_MAX_SZ];
770 0 : ulong pay_sz = 0;
771 0 : const uchar* raw = (const uchar *)blk_data + blockoff;
772 0 : ulong txn_sz = fd_txn_parse_core(raw, fd_ulong_min(blk_sz - blockoff, FD_TXN_MTU), txn_out, NULL, &pay_sz);
773 0 : if ( txn_sz == 0 || txn_sz > FD_TXN_MAX_SZ ) {
774 0 : FD_LOG_WARNING( ( "failed to parse transaction %lu in microblock %lu",
775 0 : txn_idx,
776 0 : mblk ) );
777 0 : return "failed to parse transaction";
778 0 : }
779 0 : if (first_txn) {
780 0 : first_txn = 0;
781 0 : EMIT_SIMPLE("{");
782 0 : } else
783 0 : EMIT_SIMPLE(",{");
784 :
785 0 : uchar const * sig_p = raw + ((fd_txn_t *)txn_out)->signature_off;
786 0 : fd_txn_map_t elem;
787 0 : uchar flags;
788 0 : if( !fd_blockstore_txn_query_volatile( blockstore, blockstore_fd, sig_p, &elem, NULL, &flags, NULL ) ) {
789 0 : const void * meta = fd_wksp_laddr_fast( blockstore_wksp, elem.meta_gaddr );
790 0 : const char * err = fd_txn_meta_to_json( ws, meta, elem.meta_sz );
791 0 : if ( err ) return err;
792 0 : }
793 :
794 0 : const char * err = fd_txn_to_json( ws, (fd_txn_t *)txn_out, raw, pay_sz, encoding, maxvers, detail );
795 0 : if ( err ) return err;
796 :
797 0 : EMIT_SIMPLE("}");
798 :
799 0 : blockoff += pay_sz;
800 0 : }
801 0 : }
802 0 : }
803 0 : if ( blockoff != blk_sz )
804 0 : FD_LOG_ERR(("garbage at end of block"));
805 :
806 0 : fd_web_reply_sprintf(ws, "]},\"id\":%s}", call_id);
807 :
808 0 : return NULL;
809 0 : }
810 :
811 : const char*
812 : fd_account_to_json( fd_webserver_t * ws,
813 : fd_pubkey_t acct,
814 : fd_rpc_encoding_t enc,
815 : uchar const * val,
816 : ulong val_sz,
817 : long off,
818 0 : long len ) {
819 0 : fd_web_reply_sprintf(ws, "{\"data\":[\"");
820 :
821 0 : fd_account_meta_t * metadata = (fd_account_meta_t *)val;
822 0 : if (val_sz < sizeof(fd_account_meta_t) && val_sz < metadata->hlen) {
823 0 : return "failed to load account data";
824 0 : }
825 0 : val = (uchar*)val + metadata->hlen;
826 0 : val_sz = val_sz - metadata->hlen;
827 0 : if (val_sz > metadata->dlen)
828 0 : val_sz = metadata->dlen;
829 :
830 0 : if (len != FD_LONG_UNSET && off != FD_LONG_UNSET) {
831 0 : if (enc == FD_ENC_JSON) {
832 0 : return "cannot use jsonParsed encoding with slice";
833 0 : }
834 0 : if (off < 0 || (ulong)off >= val_sz) {
835 0 : val = NULL;
836 0 : val_sz = 0;
837 0 : } else {
838 0 : val = (uchar*)val + (ulong)off;
839 0 : val_sz = val_sz - (ulong)off;
840 0 : }
841 0 : if (len < 0) {
842 0 : val = NULL;
843 0 : val_sz = 0;
844 0 : } else if ((ulong)len < val_sz)
845 0 : val_sz = (ulong)len;
846 0 : }
847 :
848 0 : const char* encstr;
849 0 : switch (enc) {
850 0 : case FD_ENC_BASE58:
851 0 : if (fd_web_reply_encode_base58(ws, val, val_sz)) {
852 0 : return "failed to encode data in base58";
853 0 : }
854 0 : encstr = "base58";
855 0 : break;
856 0 : case FD_ENC_BASE64:
857 0 : case FD_ENC_JSON:
858 0 : if (fd_web_reply_encode_base64(ws, val, val_sz)) {
859 0 : return "failed to encode data in base64";
860 0 : }
861 0 : encstr = "base64";
862 0 : break;
863 0 : # if FD_HAS_ZSTD
864 0 : case FD_ENC_BASE64_ZSTD: {
865 0 : size_t const cBuffSize = ZSTD_compressBound( val_sz );
866 0 : void * cBuff = fd_scratch_alloc( 1, cBuffSize );
867 0 : size_t const cSize = ZSTD_compress( cBuff, cBuffSize, val, val_sz, 1 );
868 0 : if (fd_web_reply_encode_base64(ws, cBuff, cSize)) {
869 0 : return "failed to encode data in base64";
870 0 : }
871 0 : encstr = "base64+zstd";
872 0 : break;
873 0 : }
874 0 : # endif /* FD_HAS_ZSTD */
875 0 : default:
876 0 : return "unsupported encoding";
877 0 : }
878 :
879 0 : char owner[50];
880 0 : fd_base58_encode_32((uchar*)metadata->info.owner, 0, owner);
881 0 : char addr[50];
882 0 : fd_base58_encode_32(acct.uc, 0, addr);
883 0 : fd_web_reply_sprintf(ws, "\",\"%s\"],\"executable\":%s,\"lamports\":%lu,\"owner\":\"%s\",\"address\":\"%s\",\"rentEpoch\":%lu,\"space\":%lu}",
884 0 : encstr,
885 0 : (metadata->info.executable ? "true" : "false"),
886 0 : metadata->info.lamports,
887 0 : owner,
888 0 : addr,
889 0 : metadata->info.rent_epoch,
890 0 : val_sz);
891 :
892 0 : return NULL;
893 0 : }
|