From 4e32c18ce2a41b9417f6030a1bc184e351fee4b8 Mon Sep 17 00:00:00 2001 From: "ruslan.laishev" <ruslan.laishev@demlabs.net> Date: Thu, 31 Mar 2022 04:01:29 +0000 Subject: [PATCH] [+]feature-5899: ledger tx list -all -net ... -tx_num <NR> --- dap-sdk/core/include/dap_list.h | 9 +- dap-sdk/net/client/dap_client_pvt.c | 2 +- dap-sdk/net/core/dap_proc_thread.c | 3 + dap-sdk/net/core/dap_server.c | 6 +- dap-sdk/net/core/dap_worker.c | 11 +- modules/chain/include/dap_chain.h | 2 + modules/mempool/dap_chain_mempool.c | 2 + modules/net/dap_chain_node_cli.c | 2 +- modules/net/dap_chain_node_cli_cmd_tx.c | 275 +++++++++++++++++++++++- modules/type/dag/dap_chain_cs_dag.c | 50 +++++ 10 files changed, 349 insertions(+), 13 deletions(-) diff --git a/dap-sdk/core/include/dap_list.h b/dap-sdk/core/include/dap_list.h index 1bf990e7fe..3b82deca77 100755 --- a/dap-sdk/core/include/dap_list.h +++ b/dap-sdk/core/include/dap_list.h @@ -17,14 +17,13 @@ typedef void* (*dap_callback_copy_t)(const void * src, void* data); typedef int (*dap_callback_compare_t)(const void * a, const void * b); typedef int (*dap_callback_compare_data_t)(const void * a, const void * b, void* user_data); -typedef struct _dap_list dap_list_t; -struct _dap_list +typedef struct _dap_list { void* data; - dap_list_t *next; - dap_list_t *prev; -}; + struct _dap_list *next; + struct _dap_list *prev; +} dap_list_t; /* Doubly linked lists */ diff --git a/dap-sdk/net/client/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c index dc92421fe3..8a8e27a381 100644 --- a/dap-sdk/net/client/dap_client_pvt.c +++ b/dap-sdk/net/client/dap_client_pvt.c @@ -537,7 +537,7 @@ static bool s_stage_status_after(dap_client_pvt_t * a_client_pvt) strerror_r(l_err,l_errbuf,sizeof (l_errbuf)); else strncpy(l_errbuf,"Unknown Error",sizeof(l_errbuf)-1); - log_it(L_ERROR, "Remote address can't connect (%s:%hu) with sock_id %"DAP_FORMAT_SOCKET": \"%s\" (code %d)", a_client_pvt->uplink_addr, + log_it(L_ERROR, "Remote address can't connect (%s:%hu) with sd %"DAP_FORMAT_SOCKET": \"%s\" (code %d)", a_client_pvt->uplink_addr, a_client_pvt->uplink_port, a_client_pvt->stream_es->socket, l_errbuf, l_err); #ifdef DAP_OS_WINDOWS closesocket(a_client_pvt->stream_socket); diff --git a/dap-sdk/net/core/dap_proc_thread.c b/dap-sdk/net/core/dap_proc_thread.c index a46612b599..7415ee773e 100644 --- a/dap-sdk/net/core/dap_proc_thread.c +++ b/dap-sdk/net/core/dap_proc_thread.c @@ -578,6 +578,9 @@ static void * s_proc_thread_function(void * a_arg) l_thread->signal_exit = false; + + log_it(L_NOTICE, "Worker thread is running on CPU #%d... ", l_thread->cpu_id); + // Main loop while (!l_thread->signal_kill && !l_thread->signal_exit){ diff --git a/dap-sdk/net/core/dap_server.c b/dap-sdk/net/core/dap_server.c index 792af68632..8976c16ce6 100644 --- a/dap-sdk/net/core/dap_server.c +++ b/dap-sdk/net/core/dap_server.c @@ -381,8 +381,8 @@ static void s_es_server_accept(dap_events_socket_t *a_es, SOCKET a_remote_socket assert(l_server); dap_events_socket_t * l_es_new = NULL; - log_it(L_DEBUG, "Listening socket (binded on %s:%u) got new incomming connection",l_server->address,l_server->port); - log_it(L_DEBUG, "Accepted new connection (sock %"DAP_FORMAT_SOCKET" from %"DAP_FORMAT_SOCKET")", a_remote_socket, a_es->socket); + log_it(L_DEBUG, "Listening sd:%"DAP_FORMAT_SOCKET "(binded on %s:%u) got new incomming connection", a_es->socket, l_server->address,l_server->port); + log_it(L_DEBUG, "Accepted new connection sd: %"DAP_FORMAT_SOCKET"", a_es->socket); l_es_new = s_es_server_create(a_es->events,a_remote_socket,&l_server->client_callbacks,l_server); //l_es_new->is_dont_reset_write_flag = true; // By default all income connection has this flag getnameinfo(a_remote_addr,a_remote_addr_size, l_es_new->hostaddr @@ -393,6 +393,8 @@ static void s_es_server_accept(dap_events_socket_t *a_es, SOCKET a_remote_socket l_addr_remote.s_addr = ((struct sockaddr_in *) a_remote_addr)->sin_addr.s_addr; inet_ntop(AF_INET,&l_addr_remote,l_es_new->hostaddr,sizeof (l_addr_remote) ); } + + l_es_new->remote_addr_str = dap_strdup (l_es_new->hostaddr); log_it(L_INFO,"Connection accepted from %s (%s)", l_es_new->hostaddr, l_es_new->service ); dap_worker_add_events_socket_auto(l_es_new); } diff --git a/dap-sdk/net/core/dap_worker.c b/dap-sdk/net/core/dap_worker.c index 4726a1548d..1003ce70b0 100644 --- a/dap-sdk/net/core/dap_worker.c +++ b/dap-sdk/net/core/dap_worker.c @@ -169,6 +169,9 @@ void *dap_worker_thread(void *arg) pthread_cond_broadcast(&l_worker->started_cond); pthread_mutex_unlock(&l_worker->started_mutex); bool s_loop_is_active = true; + + log_it(L_NOTICE, "Worker thread %d is running ... ", l_worker->id); + while(s_loop_is_active) { int l_selected_sockets; size_t l_sockets_max; @@ -222,6 +225,7 @@ void *dap_worker_thread(void *arg) if (!l_cur_flags) // No events for this socket continue; + l_flag_hup = l_cur_flags& POLLHUP; l_flag_rdhup = l_cur_flags & POLLRDHUP; l_flag_write = (l_cur_flags & POLLOUT) || (l_cur_flags &POLLWRNORM)|| (l_cur_flags &POLLWRBAND ) ; @@ -231,6 +235,7 @@ void *dap_worker_thread(void *arg) l_flag_pri = l_cur_flags & POLLPRI; l_flag_msg = l_cur_flags & POLLMSG; l_cur = l_worker->poll_esocket[n]; + //log_it(L_DEBUG, "flags: returned events 0x%0X requested events 0x%0X",l_worker->poll[n].revents,l_worker->poll[n].events ); #elif defined (DAP_EVENTS_CAPS_KQUEUE) l_flag_hup=l_flag_rdhup=l_flag_read=l_flag_write=l_flag_error=l_flag_nval=l_flag_msg =l_flag_pri = false; @@ -319,12 +324,12 @@ void *dap_worker_thread(void *arg) } default: if(s_debug_reactor) - log_it(L_INFO,"RDHUP event on esocket %p (%"DAP_FORMAT_SOCKET") type %d", l_cur, l_cur->socket, l_cur->type ); + log_it(L_INFO,"RDHUP event on esocket %p (sd=%"DAP_FORMAT_SOCKET") type %d", l_cur, l_cur->socket, l_cur->type ); } } if(l_flag_nval ){ - log_it(L_WARNING, "NVAL flag armed for socket %p (%"DAP_FORMAT_SOCKET")", l_cur, l_cur->socket); + log_it(L_WARNING, "NVAL flag armed for socket %p (sd=%"DAP_FORMAT_SOCKET")", l_cur, l_cur->socket); l_cur->buf_out_size = 0; l_cur->buf_in_size = 0; l_cur->flags |= DAP_SOCK_SIGNAL_CLOSE; @@ -374,7 +379,7 @@ void *dap_worker_thread(void *arg) //log_it(L_DEBUG, "Comes connection with type %d", l_cur->type); if(l_cur->buf_in_size_max && l_cur->buf_in_size >= l_cur->buf_in_size_max ) { - log_it(L_WARNING, "Buffer is full when there is smth to read. Its dropped! esocket %p (%"DAP_FORMAT_SOCKET")", l_cur, l_cur->socket); + log_it(L_WARNING, "Buffer is full when there is smth to read. Its dropped! esocket %p (sd=%"DAP_FORMAT_SOCKET")", l_cur, l_cur->socket); l_cur->buf_in_size = 0; } diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h index e8f6f6bf7b..b364dea637 100644 --- a/modules/chain/include/dap_chain.h +++ b/modules/chain/include/dap_chain.h @@ -80,6 +80,7 @@ typedef dap_chain_datum_tx_t* (*dap_chain_callback_tx_find_by_hash_t)(dap_chain_ typedef dap_chain_atom_ptr_t * (*dap_chain_callback_atom_iter_get_atoms_t)(dap_chain_atom_iter_t * ,size_t* ,size_t**); typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_next_t)(dap_chain_atom_iter_t * ,size_t*); +typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_set_nlast_t) (dap_chain_atom_iter_t *, size_t *, size_t); typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t * ); typedef size_t (*dap_chain_callback_add_datums_t)(dap_chain_t * , dap_chain_datum_t **, size_t ); @@ -145,6 +146,7 @@ typedef struct dap_chain{ dap_chain_callback_atom_iter_find_by_hash_t callback_atom_find_by_hash; dap_chain_callback_tx_find_by_hash_t callback_tx_find_by_hash; dap_chain_callback_atom_iter_get_next_t callback_atom_iter_get_next; + dap_chain_callback_atom_iter_set_nlast_t callback_atom_iter_set_nlast; dap_chain_callback_atom_iter_get_atoms_t callback_atom_iter_get_links; dap_chain_callback_atom_iter_get_atoms_t callback_atom_iter_get_lasts; dap_chain_callback_atom_iter_delete_t callback_atom_iter_delete; diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index 34a93f668d..749b19926b 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -796,6 +796,8 @@ void chain_mempool_proc(struct dap_http_simple *cl_st, void * arg) } else{ *return_code = Http_Status_BadRequest; } + + DAP_DELETE(request_str); } else *return_code = Http_Status_BadRequest; diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index 8d70b8514e..ef95fc045b 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -379,7 +379,7 @@ static void* thread_one_client_func(void *args) size_t l_reply_rest = l_reply_len; while(l_reply_rest) { size_t l_send_bytes = min(l_reply_step, l_reply_rest); - int ret = send(newsockfd, reply_str + l_reply_len - l_reply_rest, l_send_bytes, 0); + int ret = send(newsockfd, reply_str + l_reply_len - l_reply_rest, l_send_bytes, MSG_NOSIGNAL); if(ret<=0) break; l_reply_rest-=l_send_bytes; diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index a31617d2f2..de7306b48e 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -25,6 +25,7 @@ #include <stdbool.h> #include <stddef.h> #include <pthread.h> +#include <errno.h> #include "dap_chain_wallet.h" #include "dap_common.h" @@ -1102,6 +1103,265 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger } + + +/** + * @brief dap_db_history_filter + * Get data according the history log + * + * return history string + * @param a_chain + * @param a_ledger + * @param a_filter_token_name + * @param a_filtr_addr_base58 + * @param a_hash_out_type + * @param a_datum_start + * @param a_datum_end + * @param a_total_datums + * @param a_tx_hash_processed + * @return char* + */ +static char* dap_db_history_filter_ext ( + dap_chain_t * a_chain, + dap_ledger_t *a_ledger, + const char *a_filter_token_name, + const char *a_filtr_addr_base58, + const char *a_hash_out_type, + long a_datum_start, + long a_datum_end, + long *a_total_datums, + dap_chain_tx_hash_processed_ht_t *a_tx_hash_processed, + size_t a_nr) +{ + dap_string_t *l_str_out; + dap_tx_data_t *l_tx_data_hash = NULL; + size_t l_atom_size; + size_t l_datum_num = 0, l_token_num = 0, l_emission_num = 0, l_tx_num = 0, l_datum_unproc_num = 0; + size_t l_datum_num_global = a_total_datums ? *a_total_datums : 0; + + dap_chain_atom_iter_t *l_atom_iter; + dap_chain_atom_ptr_t l_atom; + char l_time_str[128], l_hash_str[128]; + + if ( !(l_atom_iter = a_chain->callback_atom_iter_create(a_chain)) ) + return log_it(L_ERROR, "Cannot create iterator for chain \"%s\"", a_chain->name), NULL; + + if ( !(l_atom = a_chain->callback_atom_iter_set_nlast(l_atom_iter, &l_atom_size, a_nr)) ) + return log_it(L_ERROR, "Error retrieve chain \"%s\"", a_chain->name), NULL; + + if ( !(l_str_out = dap_string_new(NULL)) ) + return log_it(L_ERROR, "Error retrieve chain \"%s\", errno=%d", a_chain->name, errno), NULL; + + + /* + * Point <dap_chain_atom_iter_t> to <tail>-NR position + */ + while(l_atom && l_atom_size) { + size_t l_datums_count = 0; + dap_chain_datum_t **l_datums; + + l_datums = (a_chain->callback_atom_get_datums && l_atom && l_atom_size) ? + a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count) : NULL; + + if(!l_datums) + return log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name), NULL; + + for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) { + + dap_chain_datum_t *l_datum = l_datums[l_datum_n]; + if(!l_datum) + continue; + + // get time of create datum + if(dap_time_to_str_rfc822(l_time_str, 71, l_datum->header.ts_create) < 1) + l_time_str[0] = '\0'; + + switch (l_datum->header.type_id) { + + // token + case DAP_CHAIN_DATUM_TOKEN_DECL: { + + // no token necessary for addr + if(a_filtr_addr_base58) + break; + + dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data; + // datum out of page + if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < (size_t)a_datum_start || l_datum_num+l_datum_num_global >= (size_t)a_datum_end)){ + l_token_num++; + break; + } + if(!a_filter_token_name || !dap_strcmp(l_token->ticker, a_filter_token_name)) { + dap_string_append_printf(l_str_out, "token %s, created: %s\n", l_token->ticker, l_time_str); + switch (l_token->type) { + // Simple private token decl + case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: + dap_string_append_printf(l_str_out, " total_supply: %.0Lf(%"DAP_UINT64_FORMAT_U"), signs: valid/total %02d/%02d \n", + l_token->header_private.total_supply / DATOSHI_LD, + l_token->header_private.total_supply, + l_token->header_private.signs_valid, l_token->header_private.signs_total); + break; + case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_DECL: + dap_string_append_printf(l_str_out, " tsd_total_size: %"DAP_UINT64_FORMAT_U", flags: 0x%x \n", + l_token->header_private_decl.tsd_total_size, + l_token->header_private_decl.flags); + break; + case DAP_CHAIN_DATUM_TOKEN_TYPE_PRIVATE_UPDATE: + dap_string_append_printf(l_str_out, " tsd_total_size: %"DAP_UINT64_FORMAT_U", padding: 0x%x \n", + l_token->header_private_update.tsd_total_size, + l_token->header_private_update.padding); + break; + case DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC: { + char *l_addr = dap_chain_addr_to_str(&l_token->header_public.premine_address); + char * l_balance = dap_chain_balance_to_coins(l_token->header_public.total_supply); + dap_string_append_printf(l_str_out, + " total_supply: %s(%s), flags: 0x%x\n, premine_supply: %s, premine_address '%s'\n", + //l_token->header_public.total_supply / DATOSHI_LD, + dap_chain_balance_to_coins(l_token->header_public.total_supply), + dap_chain_balance_print(l_token->header_public.total_supply), + l_token->header_public.flags, + dap_chain_balance_print(l_token->header_public.premine_supply), + l_addr ? l_addr : "-"); + DAP_DELETE(l_addr); + DAP_DELETE(l_balance); + } + break; + default: + dap_string_append_printf(l_str_out, "unknown token type: 0x%x\n", l_token->type); + break; + + } + dap_string_append_printf(l_str_out, "\n"); + l_token_num++; + } + } + break; + + // emission + case DAP_CHAIN_DATUM_TOKEN_EMISSION: { + // datum out of page + if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < (size_t)a_datum_start || l_datum_num+l_datum_num_global >= (size_t)a_datum_end)) { + l_emission_num++; + break; + } + size_t l_emission_size = dap_chain_datum_emission_get_size(l_datum->data); + dap_chain_datum_token_emission_t *l_token_em = dap_chain_datum_emission_read(l_datum->data, &l_emission_size); + if(!a_filter_token_name || !dap_strcmp(l_token_em->hdr.ticker, a_filter_token_name)) { + char * l_token_emission_address_str = dap_chain_addr_to_str(&(l_token_em->hdr.address)); + // filter for addr + if (a_filtr_addr_base58 && dap_strcmp(a_filtr_addr_base58,l_token_emission_address_str)) { + break; + } + + dap_string_append_printf(l_str_out, "emission: %.0Lf(%"DAP_UINT64_FORMAT_U") %s, type: %s, version: %d\n", + l_token_em->hdr.value / DATOSHI_LD, l_token_em->hdr.value, l_token_em->hdr.ticker, + c_dap_chain_datum_token_emission_type_str[l_token_em->hdr.type], + l_token_em->hdr.version); + dap_string_append_printf(l_str_out, " to addr: %s\n", l_token_emission_address_str); + + DAP_DELETE(l_token_emission_address_str); + switch (l_token_em->hdr.type) { + case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_UNDEFINED: + break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH: + dap_string_append_printf(l_str_out, " signs_count: %d\n", l_token_em->data.type_auth.signs_count); + break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO: + dap_string_append_printf(l_str_out, " codename: %s\n", l_token_em->data.type_algo.codename); + break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER: + dap_string_append_printf(l_str_out, " value_start: %.0Lf(%"DAP_UINT64_FORMAT_U"), codename: %s\n", + l_token_em->data.type_atom_owner.value_start / DATOSHI_LD, + l_token_em->data.type_atom_owner.value_start, + l_token_em->data.type_atom_owner.value_change_algo_codename); + break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT: { + char *l_addr = dap_chain_addr_to_str(&l_token_em->data.type_presale.addr); + // get time of create datum + if(dap_time_to_str_rfc822(l_time_str, 71, l_token_em->data.type_presale.lock_time) < 1) + l_time_str[0] = '\0'; + dap_string_append_printf(l_str_out, " flags: 0x%x, lock_time: %s\n", l_token_em->data.type_presale.flags, l_time_str); + dap_string_append_printf(l_str_out, " addr: %s\n", l_addr); + DAP_DELETE(l_addr); + } + break; + } + dap_string_append_printf(l_str_out, "\n"); + l_emission_num++; + } + DAP_DELETE(l_token_em); + } break; + + // transaction + case DAP_CHAIN_DATUM_TX:{ + // datum out of page + if(a_datum_start >= 0 && (l_datum_num+l_datum_num_global < (size_t)a_datum_start || l_datum_num+l_datum_num_global >= (size_t)a_datum_end)) { + l_tx_num++; + break; + } + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)l_datum->data; + //calc tx hash + dap_chain_hash_fast_t l_tx_hash; + dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash); + dap_chain_tx_hash_processed_ht_t *l_sht = NULL; + HASH_FIND(hh, a_tx_hash_processed, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_sht); + if ( (l_sht != NULL) || !s_dap_chain_datum_tx_out_data(l_tx, a_ledger, l_str_out, a_hash_out_type, &l_tx_hash)) + { + l_datum_num--; + l_datum_unproc_num++; + + dap_hash_fast_to_str(&l_tx_hash, l_hash_str, sizeof(l_hash_str) ); + dap_string_append_printf(l_str_out, " %s - unprocessed\n", l_hash_str); + + break; + } + l_sht = DAP_NEW_Z(dap_chain_tx_hash_processed_ht_t); + memcpy(&l_sht->hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t)); + HASH_ADD(hh, a_tx_hash_processed, hash, sizeof(dap_chain_hash_fast_t), l_sht); + l_tx_num++; + } + break; + default: + dap_string_append_printf(l_str_out, "unknown datum type=%d\n", l_datum->header.type_id); + break; + } + l_datum_num++; + } + l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size); + } + a_chain->callback_atom_iter_delete(l_atom_iter); + //total + dap_string_append_printf(l_str_out, + "---------------\ntokens: %zu\nemissions: %zu\ntransactions: %zu\ntotal datums: %zu (%zu unprocessed)", l_token_num, + l_emission_num, l_tx_num, l_datum_num, l_datum_unproc_num); + + // return total datums + if(a_total_datums) + *a_total_datums = l_datum_num; + // delete hashes + dap_tx_data_t *l_iter_current, *l_item_tmp; + HASH_ITER(hh, l_tx_data_hash , l_iter_current, l_item_tmp) + { + HASH_DEL(l_tx_data_hash, l_iter_current); + // delete datum + DAP_DELETE(l_iter_current->datum); + // delete struct + DAP_DELETE(l_iter_current); + } + + // if no history + if(!l_str_out->len) + dap_string_append(l_str_out, "empty"); + char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL; + return l_ret_str; +} + + + + + + + /** * @brief com_ledger * ledger command @@ -1114,12 +1374,13 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger int com_ledger(int a_argc, char ** a_argv, char **a_str_reply) { enum { CMD_NONE, CMD_LIST, CMD_TX_HISTORY, CMD_TX_INFO }; - int arg_index = 1; + int arg_index = 1, l_nr = 0; const char *l_addr_base58 = NULL; const char *l_wallet_name = NULL; const char *l_net_str = NULL; const char *l_chain_str = NULL; const char *l_tx_hash_str = NULL; + const char *l_nr_str = NULL; dap_chain_t * l_chain = NULL; dap_chain_net_t * l_net = NULL; @@ -1149,6 +1410,10 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply) dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str); dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-chain", &l_chain_str); dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-tx", &l_tx_hash_str); + dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-tx_num", &l_nr_str); + + l_nr = l_nr_str ? strtoul(l_nr_str, NULL, 10) : 0; + dap_chain_tx_hash_processed_ht_t *l_list_tx_hash_processd = NULL; if(!l_is_all && !l_addr_base58 && !l_wallet_name && !l_tx_hash_str) { @@ -1238,9 +1503,17 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply) dap_string_append_printf(l_str_ret, "chain: %s\n", l_chain_cur->name); dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(l_net_str); if(l_is_all) { + if ( l_nr ) + { + l_str_out = dap_db_history_filter_ext(l_chain_cur, l_ledger, NULL, NULL, l_hash_out_type, -1, 0, NULL, l_list_tx_hash_processd, l_nr); + dap_string_append_printf(l_str_ret, "all history:\n%s\n", l_str_out ? l_str_out : " empty"); + } + else { + // without filters l_str_out = dap_db_history_filter(l_chain_cur, l_ledger, NULL, NULL, l_hash_out_type, -1, 0, NULL, l_list_tx_hash_processd); dap_string_append_printf(l_str_ret, "all history:\n%s\n", l_str_out ? l_str_out : " empty"); + } } else { l_str_out = l_tx_hash_str ? diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c index 1fd96ce954..15c8b394cd 100644 --- a/modules/type/dag/dap_chain_cs_dag.c +++ b/modules/type/dag/dap_chain_cs_dag.c @@ -109,6 +109,9 @@ static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_links( dap_chain_ato static dap_chain_atom_ptr_t *s_chain_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,size_t *a_links_size, size_t ** a_lasts_size_ptr ); // Get list of linked events +static dap_chain_atom_ptr_t s_chain_callback_atom_iter_set_nlast (dap_chain_atom_iter_t * a_atom_iter, size_t *a_ret_size, size_t a_count); + + // Delete iterator static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter ); // Get the fisrt event from dag @@ -233,6 +236,8 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg) a_chain->callback_add_datums = s_chain_callback_datums_pool_proc; + a_chain->callback_atom_iter_set_nlast = s_chain_callback_atom_iter_set_nlast; + // Datum operations callbacks /* a_chain->callback_datum_iter_create = s_chain_callback_datum_iter_create; // Datum iterator create @@ -1832,3 +1837,48 @@ static dap_list_t *s_dap_chain_callback_get_txs(dap_chain_t *a_chain, size_t a_c return l_list; } + +static dap_chain_atom_ptr_t s_chain_callback_atom_iter_set_nlast ( + dap_chain_atom_iter_t * a_atom_iter, + size_t * a_ret_size, + size_t a_count) +{ +const char *l_func = __FUNCTION__; +dap_chain_cs_dag_event_item_t *l_event_item; +dap_chain_cs_dag_t * l_dag; +dap_chain_cs_dag_pvt_t *l_dag_pvt; + + if ( !a_atom_iter ) + return log_it(L_ERROR, "NULL iterator on input for %s() function", l_func), NULL; + + assert ( (l_dag = DAP_CHAIN_CS_DAG(a_atom_iter->chain)) ); + assert ( (l_dag_pvt = PVT(l_dag)) ); + + /* Point <l_event_item> to first element in table */ + if ( !(l_event_item = (dap_chain_cs_dag_event_item_t *) l_dag_pvt->events) ) + return NULL; + + while ( l_event_item->hh.next ) /* Run over records to end of list */ + l_event_item = l_event_item->hh.next; + + + for (int i = a_count; i; i--) /* Rewind <l_event_item> to <a-count> elements */ + { + if ( !l_event_item->hh.prev ) /* Stop is no previous element */ + break; + + l_event_item = (dap_chain_cs_dag_event_item_t*) l_event_item->hh.prev;/* Point <l_event_item> to previous element */ + } + + + a_atom_iter->cur_item = l_event_item; /* So , reconstruct the iterator */ + + a_atom_iter->cur = l_event_item->event; + a_atom_iter->cur_size = a_atom_iter->cur ? l_event_item->event_size : 0; + a_atom_iter->cur_hash = &l_event_item->hash; + + if (a_ret_size) + *a_ret_size = a_atom_iter->cur_size; + + return a_atom_iter->cur; +} -- GitLab