From 4d003c55e6b21ff69d9115da61c5fdc28bac3c69 Mon Sep 17 00:00:00 2001 From: "daniil.frolov" <daniil.frolov@demlabs.net> Date: Sat, 25 Jan 2025 11:48:34 +0000 Subject: [PATCH] Unspent outs cache --- modules/chain/dap_chain.c | 7 +- modules/chain/include/dap_chain.h | 4 +- modules/net/dap_chain_node_cli.c | 2 +- modules/net/dap_chain_node_cli_cmd.c | 4 +- modules/net/dap_chain_node_cli_cmd_tx.c | 20 +- modules/type/blocks/dap_chain_cs_blocks.c | 2 +- modules/wallet/dap_chain_wallet_cache.c | 562 ++++++++++-------- .../wallet/include/dap_chain_wallet_cache.h | 4 +- 8 files changed, 344 insertions(+), 261 deletions(-) diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 38f4865fd7..6a31319fb6 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -777,6 +777,7 @@ struct chain_thread_datum_removed_notifier { dap_chain_t *chain; dap_chain_cell_id_t cell_id; dap_hash_fast_t hash; + dap_chain_datum_t *datum; int ret_code; }; @@ -807,7 +808,7 @@ static bool s_notify_datum_removed_on_thread(void *a_arg) { struct chain_thread_datum_removed_notifier *l_arg = a_arg; assert(l_arg->callback); - l_arg->callback(l_arg->callback_arg, &l_arg->hash); + l_arg->callback(l_arg->callback_arg, &l_arg->hash, l_arg->datum); DAP_DELETE(l_arg); return false; } @@ -928,7 +929,7 @@ void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_ } } -void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash) { +void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, dap_chain_datum_t *a_datum) { #ifdef DAP_CHAIN_BLOCKS_TEST return; #endif @@ -946,7 +947,7 @@ void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fa *l_arg = (struct chain_thread_datum_removed_notifier) { .callback = l_notifier->callback, .callback_arg = l_notifier->arg, .chain = a_chain_cell->chain, .cell_id = a_chain_cell->id, - .hash = *a_hash}; + .hash = *a_hash, .datum = a_datum}; dap_proc_thread_callback_add_pri(l_notifier->proc_thread, s_notify_datum_removed_on_thread, l_arg, DAP_QUEUE_MSG_PRIORITY_LOW); } } diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h index 3e3076c702..348b5a071e 100644 --- a/modules/chain/include/dap_chain.h +++ b/modules/chain/include/dap_chain.h @@ -128,7 +128,7 @@ typedef size_t (*dap_chain_callback_add_datums_t)(dap_chain_t * , dap_chain_datu typedef void (*dap_chain_callback_notify_t)(void *a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, dap_chain_hash_fast_t *a_atom_hash, void *a_atom, size_t a_atom_size); //change in chain happened typedef void (*dap_chain_callback_datum_notify_t)(void *a_arg, dap_chain_hash_fast_t *a_datum_hash, dap_chain_hash_fast_t *a_atom_hash, void *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_net_srv_uid_t a_uid); //change in chain happened -typedef void (*dap_chain_callback_datum_removed_notify_t)(void *a_arg, dap_chain_hash_fast_t *a_datum_hash); //change in chain happened +typedef void (*dap_chain_callback_datum_removed_notify_t)(void *a_arg, dap_chain_hash_fast_t *a_datum_hash, dap_chain_datum_t *a_datum); //change in chain happened typedef uint64_t (*dap_chain_callback_get_count)(dap_chain_t *a_chain); typedef dap_list_t *(*dap_chain_callback_get_list)(dap_chain_t *a_chain, size_t a_count, size_t a_page, bool a_reverse); @@ -313,7 +313,7 @@ void dap_chain_add_callback_datum_removed_from_index_notify(dap_chain_t *a_chain void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, void *a_arg, uint64_t a_conf_cnt); void dap_chain_atom_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size); void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, dap_hash_fast_t *a_atom_hash, const uint8_t *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_net_srv_uid_t a_uid); -void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash); +void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, dap_chain_datum_t *a_datum); void dap_chain_atom_add_from_threshold(dap_chain_t *a_chain); dap_chain_atom_ptr_t dap_chain_get_atom_by_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size); bool dap_chain_get_atom_last_hash_num(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_atom_hash, uint64_t *a_atom_num); diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index a5df1f47e4..5faac29320 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -159,7 +159,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n" "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n" "wallet deactivate -w <wallet_name>>\n" - "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]" + "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]\n" "wallet convert -w <wallet_name> {-password <password> | -remove_password }\n"); diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index b8cee60244..9cea97c522 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -1795,8 +1795,10 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); dap_list_t *l_outs_list = NULL; - uint256_t l_value_sum = uint256_0; + + + if (l_value_str){ uint256_t l_value_datoshi = dap_chain_balance_scan(l_value_str); if (dap_chain_wallet_cache_tx_find_outs_with_val(l_net, l_token_tiker, l_addr, &l_outs_list, l_value_datoshi, &l_value_sum)) diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index ec97601064..afb5d99d28 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -404,11 +404,7 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t uint256_t l_corr_value = {}, l_cond_value = {}; bool l_recv_from_cond = false, l_send_to_same_cond = false; json_object *l_corr_object = NULL, *l_cond_recv_object = NULL, *l_cond_send_object = NULL; - dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_ALL, NULL); - if (!l_list_in_items) // a bad tx - goto next_step; - // all in items should be from the same address - + dap_chain_addr_t *l_src_addr = NULL; bool l_base_tx = false, l_reward_collect = false; const char *l_noaddr_token = NULL; @@ -421,23 +417,26 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t dap_hash_fast_t l_atom_hash = l_from_cache ? *l_wallet_cache_iter->cur_atom_hash : *l_datum_iter->cur_atom_hash; int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED; - for (dap_list_t *it = l_list_in_items; it; it = it->next) { + uint8_t *l_tx_item = NULL; + size_t l_size; int i, q = 0; + // Проход по входам + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_IN_ALL, l_size, i, l_tx) { dap_chain_hash_fast_t *l_tx_prev_hash = NULL; int l_tx_prev_out_idx; dap_chain_datum_tx_t *l_tx_prev = NULL; - switch (*(byte_t *)it->data) { + switch (*l_tx_item) { case TX_ITEM_TYPE_IN: { - dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data; + dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)l_tx_item; l_tx_prev_hash = &l_tx_in->header.tx_prev_hash; l_tx_prev_out_idx = l_tx_in->header.tx_out_prev_idx; } break; case TX_ITEM_TYPE_IN_COND: { - dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)it->data; + dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)l_tx_item; l_tx_prev_hash = &l_tx_in_cond->header.tx_prev_hash; l_tx_prev_out_idx = l_tx_in_cond->header.tx_out_prev_idx; } break; case TX_ITEM_TYPE_IN_EMS: { - dap_chain_tx_in_ems_t *l_tx_in_ems = (dap_chain_tx_in_ems_t *)it->data; + dap_chain_tx_in_ems_t *l_tx_in_ems = (dap_chain_tx_in_ems_t *)l_tx_item; l_base_tx = true; l_noaddr_token = l_tx_in_ems->header.ticker; } break; @@ -482,7 +481,6 @@ json_object* dap_db_history_addr(json_object* a_json_arr_reply, dap_chain_addr_t break; //it's not our addr } - dap_list_free(l_list_in_items); // find OUT items bool l_header_printed = false; diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 14df28a1a6..f12cf616b2 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -1625,7 +1625,7 @@ static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block HASH_DEL(PVT(a_blocks)->datum_index, l_datum_index); // notify datum removed dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_blocks->chain, a_blocks->chain->active_cell_id); - dap_chain_datum_removed_notify(l_cell, l_datum_hash); + dap_chain_datum_removed_notify(l_cell, l_datum_hash, l_datum); } } debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str, diff --git a/modules/wallet/dap_chain_wallet_cache.c b/modules/wallet/dap_chain_wallet_cache.c index 79d8b3725e..7406ade2f6 100644 --- a/modules/wallet/dap_chain_wallet_cache.c +++ b/modules/wallet/dap_chain_wallet_cache.c @@ -58,13 +58,13 @@ typedef enum dap_s_wallets_cache_type{ typedef struct dap_wallet_tx_cache_input{ dap_chain_hash_fast_t tx_prev_hash; - uint32_t tx_out_prev_idx; + int tx_out_prev_idx; uint256_t value; } dap_wallet_tx_cache_input_t; typedef struct dap_wallet_tx_cache_output{ void* tx_out; - uint32_t tx_out_idx; + int tx_out_idx; } dap_wallet_tx_cache_output_t; typedef struct dap_wallet_tx_cache { @@ -81,9 +81,24 @@ typedef struct dap_wallet_tx_cache { UT_hash_handle hh; } dap_wallet_tx_cache_t; +typedef struct unspent_cache_hh_key { + dap_hash_fast_t tx_hash; + int out_idx; +} DAP_ALIGN_PACKED unspent_cache_hh_key; + +typedef struct dap_wallet_cache_unspent_outs { + unspent_cache_hh_key key; + dap_wallet_tx_cache_output_t *output; + char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; + + UT_hash_handle hh; +} dap_wallet_cache_unspent_outs_t; + typedef struct dap_s_wallets_cache { dap_chain_addr_t wallet_addr; dap_wallet_tx_cache_t *wallet_txs; + dap_wallet_cache_unspent_outs_t *unspent_outputs; + _Atomic bool is_loading; UT_hash_handle hh; } dap_wallet_cache_t; @@ -105,7 +120,7 @@ static int s_save_cache_for_addr_in_net(dap_chain_net_t *a_net, dap_chain_addr_t static void s_callback_datum_notify(void *a_arg, dap_chain_hash_fast_t *a_datum_hash, dap_hash_fast_t *a_atom_hash, void *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_net_srv_uid_t a_uid); -static void s_callback_datum_removed_notify(void *a_arg, dap_chain_hash_fast_t *a_datum_hash); +static void s_callback_datum_removed_notify(void *a_arg, dap_chain_hash_fast_t *a_datum_hash, dap_chain_datum_t *a_datum); static void s_wallet_opened_callback(dap_chain_wallet_t *a_wallet, void *a_arg); static char * s_wallet_cache_type_to_str(dap_s_wallets_cache_type_t a_type) @@ -347,19 +362,14 @@ int dap_chain_wallet_cache_tx_find_in_history(dap_chain_addr_t *a_addr, char **a return 0; } - -int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, - dap_list_t **a_outs_list, uint256_t a_value_need, uint256_t *a_value_transfer) +int dap_chain_wallet_cache_tx_find_outs(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, + dap_list_t **a_outs_list, uint256_t *a_value_transfer) { dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items uint256_t l_value_transfer = { }; dap_chain_datum_tx_t *l_tx; - if (s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_DISABLED){ - return -101; - } - if (!a_token_ticker){ log_it(L_ERROR, "Token ticker is not specified."); return -100; @@ -370,11 +380,6 @@ int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const c return -100; } - if (IS_ZERO_256(a_value_need)){ - log_it(L_ERROR, "Needed value is zero."); - return -100; - } - if (a_outs_list == NULL){ log_it(L_ERROR, "a_outs_list is NULL"); return -100; @@ -383,129 +388,73 @@ int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const c dap_wallet_cache_t *l_wallet_item = NULL; pthread_rwlock_rdlock(&s_wallet_cache_rwlock); HASH_FIND(hh, s_wallets_cache, a_addr, sizeof(dap_chain_addr_t), l_wallet_item); - if (!l_wallet_item || l_wallet_item->is_loading){ + if (!l_wallet_item){ log_it(L_ERROR, "Can't find wallet with address %s", dap_chain_addr_to_str_static(a_addr)); pthread_rwlock_unlock(&s_wallet_cache_rwlock); return -101; } - dap_wallet_tx_cache_t *l_current_wallet_tx = l_wallet_item->wallet_txs; - // Go iterate wallet txs - dap_wallet_tx_cache_t *l_current_wallet_tx_iter = NULL, *l_tmp = NULL; - HASH_ITER(hh, l_current_wallet_tx, l_current_wallet_tx_iter, l_tmp) { - if (l_current_wallet_tx_iter->ret_code != DAP_LEDGER_CHECK_OK) - continue; + dap_wallet_cache_unspent_outs_t *l_item_cur = NULL, *l_tmp = NULL; + HASH_ITER(hh, l_wallet_item->unspent_outputs, l_item_cur, l_tmp){ - - if (*l_current_wallet_tx_iter->token_ticker && - dap_strcmp(l_current_wallet_tx_iter->token_ticker, a_token_ticker) && - !l_current_wallet_tx_iter->multichannel) + if (dap_strcmp(l_item_cur->token_ticker, a_token_ticker)) continue; - else if (*l_current_wallet_tx_iter->token_ticker && dap_strcmp(l_current_wallet_tx_iter->token_ticker, a_token_ticker) && - l_current_wallet_tx_iter->multichannel){ - - bool skip = true; - for (dap_list_t *l_temp = l_current_wallet_tx_iter->tx_wallet_outputs; l_temp; l_temp=l_temp->next){ - dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_temp->data; - dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; - uint256_t l_value = { }; - switch (l_type) { - case TX_ITEM_TYPE_OUT_EXT: { - dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; - if (dap_strcmp(l_out_ext->token, a_token_ticker)) - continue; - if (IS_ZERO_256(l_out_ext->header.value) ) - continue; - l_value = l_out_ext->header.value; - } break; - default: + else { + dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_item_cur->output; + dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; + uint256_t l_value = { }; + switch (l_type) { + case TX_ITEM_TYPE_OUT_OLD: { + dap_chain_tx_out_old_t *l_out = (dap_chain_tx_out_old_t*)l_out_cur->tx_out; + if (!l_out->header.value) continue; - } - // Check whether used 'out' items - if ( !dap_ledger_tx_hash_is_used_out_item (a_net->pub.ledger, &l_current_wallet_tx_iter->tx_hash, l_out_cur->tx_out_idx, NULL) ) { - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_current_wallet_tx_iter->tx_hash, (uint32_t)l_out_cur->tx_out_idx, l_value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - // already accumulated the required value, finish the search for 'out' items - if ( compare256(l_value_transfer, a_value_need) >= 0 ) { - break; - } - } - } - } else { - bool skip = true; - for (dap_list_t *l_temp = l_current_wallet_tx_iter->tx_wallet_outputs; l_temp; l_temp=l_temp->next){ - dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_temp->data; - dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; - uint256_t l_value = { }; - switch (l_type) { - case TX_ITEM_TYPE_OUT_OLD: { - dap_chain_tx_out_old_t *l_out = (dap_chain_tx_out_old_t*)l_out_cur->tx_out; - if (!l_out->header.value) - continue; - l_value = GET_256_FROM_64(l_out->header.value); - } break; - case TX_ITEM_TYPE_OUT: { - dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t*)l_out_cur->tx_out; - if (IS_ZERO_256(l_out->header.value) ) - continue; - l_value = l_out->header.value; - } break; - case TX_ITEM_TYPE_OUT_EXT: { - // TODO: check ticker - dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; - if (dap_strcmp(l_out_ext->token, a_token_ticker)) - continue; - if (IS_ZERO_256(l_out_ext->header.value) ) - continue; - l_value = l_out_ext->header.value; - } break; - default: + l_value = GET_256_FROM_64(l_out->header.value); + } break; + case TX_ITEM_TYPE_OUT: { + dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t*)l_out_cur->tx_out; + if (IS_ZERO_256(l_out->header.value) ) continue; - } - // Check whether used 'out' items - - if ( !dap_ledger_tx_hash_is_used_out_item (a_net->pub.ledger, &l_current_wallet_tx_iter->tx_hash, l_out_cur->tx_out_idx, NULL) ) { - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_current_wallet_tx_iter->tx_hash, (uint32_t)l_out_cur->tx_out_idx, l_value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - // already accumulated the required value, finish the search for 'out' items - if ( compare256(l_value_transfer, a_value_need) >= 0 ) { - break; - } - } + l_value = l_out->header.value; + } break; + case TX_ITEM_TYPE_OUT_EXT: { + dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; + if (dap_strcmp(l_out_ext->token, a_token_ticker)) + continue; + if (IS_ZERO_256(l_out_ext->header.value) ) + continue; + l_value = l_out_ext->header.value; + } break; + default: + continue; } - } - if ( compare256(l_value_transfer, a_value_need) >= 0 ) { - break; - } + + dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); + *l_item = (dap_chain_tx_used_out_item_t) { l_item_cur->key.tx_hash, (uint32_t)l_item_cur->key.out_idx, l_value}; + l_list_used_out = dap_list_append(l_list_used_out, l_item); + SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); + } } pthread_rwlock_unlock(&s_wallet_cache_rwlock); - if (compare256(l_value_transfer, a_value_need) >= 0 && l_list_used_out){ - *a_outs_list = l_list_used_out; - if (a_value_transfer) - *a_value_transfer = l_value_transfer; - } else { - *a_outs_list = NULL; - dap_list_free(l_list_used_out); - if (a_value_transfer) - *a_value_transfer = uint256_0; - } + *a_outs_list = l_list_used_out; + if (a_value_transfer) + *a_value_transfer = l_value_transfer; return 0; } -int dap_chain_wallet_cache_tx_find_outs(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, - dap_list_t **a_outs_list, uint256_t *a_value_transfer) +int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, + dap_list_t **a_outs_list, uint256_t a_value_need, uint256_t *a_value_transfer) { dap_list_t *l_list_used_out = NULL; // list of transaction with 'out' items uint256_t l_value_transfer = { }; dap_chain_datum_tx_t *l_tx; + if (s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_DISABLED){ + return -101; + } + if (!a_token_ticker){ log_it(L_ERROR, "Token ticker is not specified."); return -100; @@ -516,6 +465,11 @@ int dap_chain_wallet_cache_tx_find_outs(dap_chain_net_t *a_net, const char *a_to return -100; } + if (IS_ZERO_256(a_value_need)){ + log_it(L_ERROR, "Needed value is zero."); + return -100; + } + if (a_outs_list == NULL){ log_it(L_ERROR, "a_outs_list is NULL"); return -100; @@ -529,94 +483,62 @@ int dap_chain_wallet_cache_tx_find_outs(dap_chain_net_t *a_net, const char *a_to pthread_rwlock_unlock(&s_wallet_cache_rwlock); return -101; } - dap_wallet_tx_cache_t *l_current_wallet_tx = l_wallet_item->wallet_txs; - // Go iterate wallet txs - dap_wallet_tx_cache_t *l_current_wallet_tx_iter = NULL, *l_tmp = NULL; - HASH_ITER(hh, l_current_wallet_tx, l_current_wallet_tx_iter, l_tmp) { - if (l_current_wallet_tx_iter->ret_code != DAP_LEDGER_CHECK_OK) - continue; + dap_wallet_cache_unspent_outs_t *l_item_cur = NULL, *l_tmp = NULL; + HASH_ITER(hh, l_wallet_item->unspent_outputs, l_item_cur, l_tmp){ - - if (*l_current_wallet_tx_iter->token_ticker && - dap_strcmp(l_current_wallet_tx_iter->token_ticker, a_token_ticker) && - !l_current_wallet_tx_iter->multichannel) + if (dap_strcmp(l_item_cur->token_ticker, a_token_ticker)) continue; - else if (*l_current_wallet_tx_iter->token_ticker && dap_strcmp(l_current_wallet_tx_iter->token_ticker, a_token_ticker) && - l_current_wallet_tx_iter->multichannel){ - - bool skip = true; - for (dap_list_t *l_temp = l_current_wallet_tx_iter->tx_wallet_outputs; l_temp; l_temp=l_temp->next){ - dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_temp->data; - dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; - uint256_t l_value = { }; - switch (l_type) { - case TX_ITEM_TYPE_OUT_EXT: { - dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; - if (dap_strcmp(l_out_ext->token, a_token_ticker)) - continue; - if (IS_ZERO_256(l_out_ext->header.value) ) - continue; - l_value = l_out_ext->header.value; - } break; - default: + else { + dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_item_cur->output; + dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; + uint256_t l_value = { }; + switch (l_type) { + case TX_ITEM_TYPE_OUT_OLD: { + dap_chain_tx_out_old_t *l_out = (dap_chain_tx_out_old_t*)l_out_cur->tx_out; + if (!l_out->header.value) continue; - } - // Check whether used 'out' items - if ( !dap_ledger_tx_hash_is_used_out_item (a_net->pub.ledger, &l_current_wallet_tx_iter->tx_hash, l_out_cur->tx_out_idx, NULL) ) { - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_current_wallet_tx_iter->tx_hash, (uint32_t)l_out_cur->tx_out_idx, l_value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - } - } - } else { - bool skip = true; - for (dap_list_t *l_temp = l_current_wallet_tx_iter->tx_wallet_outputs; l_temp; l_temp=l_temp->next){ - dap_wallet_tx_cache_output_t *l_out_cur = (dap_wallet_tx_cache_output_t*)l_temp->data; - dap_chain_tx_item_type_t l_type = *(dap_chain_tx_item_type_t*)l_out_cur->tx_out; - uint256_t l_value = { }; - switch (l_type) { - case TX_ITEM_TYPE_OUT_OLD: { - dap_chain_tx_out_old_t *l_out = (dap_chain_tx_out_old_t*)l_out_cur->tx_out; - if (!l_out->header.value) - continue; - l_value = GET_256_FROM_64(l_out->header.value); - } break; - case TX_ITEM_TYPE_OUT: { - dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t*)l_out_cur->tx_out; - if (IS_ZERO_256(l_out->header.value) ) - continue; - l_value = l_out->header.value; - } break; - case TX_ITEM_TYPE_OUT_EXT: { - // TODO: check ticker - dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; - if (dap_strcmp(l_out_ext->token, a_token_ticker)) - continue; - if (IS_ZERO_256(l_out_ext->header.value) ) - continue; - l_value = l_out_ext->header.value; - } break; - default: + l_value = GET_256_FROM_64(l_out->header.value); + } break; + case TX_ITEM_TYPE_OUT: { + dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t*)l_out_cur->tx_out; + if (IS_ZERO_256(l_out->header.value) ) continue; - } - // Check whether used 'out' items - - if ( !dap_ledger_tx_hash_is_used_out_item (a_net->pub.ledger, &l_current_wallet_tx_iter->tx_hash, l_out_cur->tx_out_idx, NULL) ) { - dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); - *l_item = (dap_chain_tx_used_out_item_t) { l_current_wallet_tx_iter->tx_hash, (uint32_t)l_out_cur->tx_out_idx, l_value }; - l_list_used_out = dap_list_append(l_list_used_out, l_item); - SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); - } + l_value = l_out->header.value; + } break; + case TX_ITEM_TYPE_OUT_EXT: { + dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t*)l_out_cur->tx_out; + if (dap_strcmp(l_out_ext->token, a_token_ticker)) + continue; + if (IS_ZERO_256(l_out_ext->header.value) ) + continue; + l_value = l_out_ext->header.value; + } break; + default: + continue; } + + dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); + *l_item = (dap_chain_tx_used_out_item_t) { l_item_cur->key.tx_hash, (uint32_t)l_item_cur->key.out_idx, l_value}; + l_list_used_out = dap_list_append(l_list_used_out, l_item); + SUM_256_256(l_value_transfer, l_item->value, &l_value_transfer); + } + if ( compare256(l_value_transfer, a_value_need) >= 0 ) { + break; } } pthread_rwlock_unlock(&s_wallet_cache_rwlock); - *a_outs_list = l_list_used_out; - if (a_value_transfer) - *a_value_transfer = l_value_transfer; + if (compare256(l_value_transfer, a_value_need) >= 0 && l_list_used_out){ + *a_outs_list = l_list_used_out; + if (a_value_transfer) + *a_value_transfer = l_value_transfer; + } else { + *a_outs_list = NULL; + dap_list_free_full(l_list_used_out, NULL); + if (a_value_transfer) + *a_value_transfer = uint256_0; + } return 0; } @@ -627,25 +549,30 @@ static int s_save_tx_into_wallet_cache(dap_chain_t *a_chain, dap_chain_datum_tx_ int l_ret_val = 0; int l_items_cnt = 0; - dap_list_t *l_out_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, &l_items_cnt); + bool l_multichannel = false; - int l_out_idx = 0; - for (dap_list_t *it=l_out_list; it; it=it->next, l_out_idx++){ - uint8_t l_out_type = *(uint8_t *)it->data; + int l_out_idx = 0, i = 0; + uint8_t *l_tx_item = NULL; + size_t l_size; + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, a_tx) { + uint8_t l_out_type = *l_tx_item; dap_chain_addr_t l_addr = {}; switch(l_out_type){ case TX_ITEM_TYPE_OUT_OLD: { - l_addr = ((dap_chain_tx_out_old_t*)it->data)->addr; + l_addr = ((dap_chain_tx_out_old_t*)l_tx_item)->addr; } break; case TX_ITEM_TYPE_OUT: { - l_addr = ((dap_chain_tx_out_t*)it->data)->addr; + l_addr = ((dap_chain_tx_out_t*)l_tx_item)->addr; } break; case TX_ITEM_TYPE_OUT_EXT: { - l_addr = ((dap_chain_tx_out_ext_t*)it->data)->addr; + l_addr = ((dap_chain_tx_out_ext_t*)l_tx_item)->addr; l_multichannel = true; } break; - default: + default:{ + l_out_idx++; continue; + } + } if(!dap_chain_addr_is_blank(&l_addr) && @@ -676,21 +603,33 @@ static int s_save_tx_into_wallet_cache(dap_chain_t *a_chain, dap_chain_datum_tx_ } l_wallet_tx_item->multichannel = l_multichannel; dap_wallet_tx_cache_output_t *l_out = DAP_NEW_Z(dap_wallet_tx_cache_output_t); - l_out->tx_out = it->data; + l_out->tx_out = l_tx_item; l_out->tx_out_idx = l_out_idx; l_wallet_tx_item->tx_wallet_outputs = dap_list_append(l_wallet_tx_item->tx_wallet_outputs, l_out); + // Add unspent out into cache + if (!a_ret_code){ + dap_wallet_cache_unspent_outs_t *l_unspent_out = DAP_NEW_Z(dap_wallet_cache_unspent_outs_t); + l_unspent_out->key.tx_hash = *a_tx_hash; + l_unspent_out->key.out_idx = l_out_idx; + l_unspent_out->output = l_out; + if (l_out_type != TX_ITEM_TYPE_OUT_EXT) + dap_strncpy(l_unspent_out->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); + else + dap_strncpy(l_unspent_out->token_ticker, ((dap_chain_tx_out_ext_t*)l_tx_item)->token, DAP_CHAIN_TICKER_SIZE_MAX); + HASH_ADD(hh, l_wallet_item->unspent_outputs, key, sizeof(unspent_cache_hh_key), l_unspent_out); + } pthread_rwlock_unlock(&s_wallet_cache_rwlock); } + l_out_idx++; } - dap_list_t *l_in_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN_ALL, &l_items_cnt); - for (dap_list_t *it=l_in_list; it; it=it->next ){ - uint8_t l_cond_type = *(uint8_t *)it->data; + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_IN_ALL, l_size, i, a_tx) { + uint8_t l_cond_type = *l_tx_item; uint256_t l_value = {}; dap_chain_addr_t l_addr_from = {}; if(l_cond_type == TX_ITEM_TYPE_IN){ - dap_hash_fast_t l_prev_tx_hash = ((dap_chain_tx_in_t*)it->data)->header.tx_prev_hash; - int l_prev_idx = ((dap_chain_tx_in_t*)it->data)->header.tx_out_prev_idx; + dap_hash_fast_t l_prev_tx_hash = ((dap_chain_tx_in_t*)l_tx_item)->header.tx_prev_hash; + int l_prev_idx = ((dap_chain_tx_in_t*)l_tx_item)->header.tx_out_prev_idx; if (dap_hash_fast_is_blank(&l_prev_tx_hash)) continue; dap_chain_datum_t *l_prev_datum = a_chain->callback_datum_find_by_hash(a_chain, &l_prev_tx_hash, NULL, NULL); @@ -750,18 +689,22 @@ static int s_save_tx_into_wallet_cache(dap_chain_t *a_chain, dap_chain_datum_tx_ l_tx_in->tx_out_prev_idx = l_prev_idx; l_tx_in->value = l_value; l_wallet_tx_item->tx_wallet_inputs = dap_list_append(l_wallet_tx_item->tx_wallet_inputs, l_tx_in); + if (!a_ret_code){ + unspent_cache_hh_key key = {0}; + key.tx_hash = l_prev_tx_hash; + key.out_idx = l_prev_idx; + dap_wallet_cache_unspent_outs_t *l_item = NULL; + HASH_FIND(hh, l_wallet_item->unspent_outputs, &key, sizeof(unspent_cache_hh_key), l_item); + if (l_item){ + HASH_DEL(l_wallet_item->unspent_outputs, l_item); + DAP_DELETE(l_item); + } + } pthread_rwlock_unlock(&s_wallet_cache_rwlock); } - } } - if (l_out_list) - dap_list_free(l_out_list); - - if (l_in_list) - dap_list_free(l_in_list); - return l_ret_val; } @@ -925,6 +868,18 @@ static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_ad l_out->tx_out = l_tx_item; l_out->tx_out_idx = l_out_idx; l_wallet_tx_item->tx_wallet_outputs = dap_list_append(l_wallet_tx_item->tx_wallet_outputs, l_out); + // Add unspent out into cache + if (!a_ret_code){ + dap_wallet_cache_unspent_outs_t *l_unspent_out = DAP_NEW_Z(dap_wallet_cache_unspent_outs_t); + l_unspent_out->key.tx_hash = *a_tx_hash; + l_unspent_out->key.out_idx = l_out_idx; + l_unspent_out->output = l_out; + if (l_out_type != TX_ITEM_TYPE_OUT_EXT) + dap_strncpy(l_unspent_out->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); + else + dap_strncpy(l_unspent_out->token_ticker, ((dap_chain_tx_out_ext_t*)l_tx_item)->token, DAP_CHAIN_TICKER_SIZE_MAX); + HASH_ADD(hh, l_wallet_item->unspent_outputs, key, sizeof(unspent_cache_hh_key), l_unspent_out); + } pthread_rwlock_unlock(&s_wallet_cache_rwlock); } l_out_idx++; @@ -947,20 +902,18 @@ static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_ad continue; } uint8_t* l_prev_item = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_prev_idx); - if (!l_prev_item){ - log_it(L_ERROR, "Can't find out with index %d in transaction %s", l_prev_idx, dap_hash_fast_to_str_static(&l_prev_tx_hash)); + if (!l_prev_item) continue; - } - uint8_t l_out_type = *(uint8_t *)l_prev_item; + uint8_t l_out_type = *(uint8_t *)l_tx_item; switch(l_out_type){ case TX_ITEM_TYPE_OUT_OLD: { - l_value = GET_256_FROM_64(((dap_chain_tx_out_old_t*)l_prev_item)->header.value); - l_addr_from = ((dap_chain_tx_out_old_t*)l_prev_item)->addr; + l_value = GET_256_FROM_64(((dap_chain_tx_out_old_t*)l_tx_item)->header.value); + l_addr_from = ((dap_chain_tx_out_old_t*)l_tx_item)->addr; } break; case TX_ITEM_TYPE_OUT: case TX_ITEM_TYPE_OUT_EXT: { - l_value = ((dap_chain_tx_out_ext_t*)l_prev_item)->header.value; - l_addr_from = ((dap_chain_tx_out_ext_t*)l_prev_item)->addr; + l_value = ((dap_chain_tx_out_ext_t*)l_tx_item)->header.value; + l_addr_from = ((dap_chain_tx_out_ext_t*)l_tx_item)->addr; } break; default: continue; @@ -997,37 +950,166 @@ static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_ad l_tx_in->tx_out_prev_idx = l_prev_idx; l_tx_in->value = l_value; l_wallet_tx_item->tx_wallet_inputs = dap_list_append(l_wallet_tx_item->tx_wallet_inputs, l_tx_in); + // Delete unspent out from unspent outs cache + if (!a_ret_code){ + unspent_cache_hh_key key; + key.tx_hash = l_prev_tx_hash; + key.out_idx = l_prev_idx; + dap_wallet_cache_unspent_outs_t *l_item = NULL; + HASH_FIND(hh, l_wallet_item->unspent_outputs, &key, sizeof(unspent_cache_hh_key), l_item); + if (l_item){ + HASH_DEL(l_wallet_item->unspent_outputs, l_item); + DAP_DELETE(l_item); + } + } pthread_rwlock_unlock(&s_wallet_cache_rwlock); } - } } return l_ret_val; } -static void s_callback_datum_removed_notify(void *a_arg, dap_chain_hash_fast_t *a_datum_hash) +static void s_callback_datum_removed_notify(void *a_arg, dap_chain_hash_fast_t *a_datum_hash, dap_chain_datum_t *a_datum) { - if (!a_datum_hash) + if (!a_datum_hash || !a_datum || a_datum->header.type_id != DAP_CHAIN_DATUM_TX) return; - pthread_rwlock_wrlock(&s_wallet_cache_rwlock); - dap_wallet_cache_t *l_wallet_item = NULL, *l_tmp; - HASH_ITER(hh, s_wallets_cache, l_wallet_item, l_tmp){ - dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; - HASH_FIND(hh, l_wallet_item->wallet_txs, a_datum_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - if (l_wallet_tx_item){ - HASH_DEL(l_wallet_item->wallet_txs, l_wallet_tx_item); - dap_list_free_full(l_wallet_tx_item->tx_wallet_inputs, NULL); - dap_list_free_full(l_wallet_tx_item->tx_wallet_outputs, NULL); - DAP_DEL_Z(l_wallet_tx_item); + dap_atom_notify_arg_t *l_arg = (dap_atom_notify_arg_t*)a_arg; + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)a_datum->data; + int l_out_idx = 0, i = 0; + uint8_t *l_tx_item = NULL; + size_t l_size; + // remove this tx outs from unspent outs cache + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, l_tx) { + uint8_t l_out_type = *l_tx_item; + dap_chain_addr_t l_addr = {}; + switch(l_out_type){ + case TX_ITEM_TYPE_OUT_OLD: { + l_addr = ((dap_chain_tx_out_old_t*)l_tx_item)->addr; + } break; + case TX_ITEM_TYPE_OUT: { + l_addr = ((dap_chain_tx_out_t*)l_tx_item)->addr; + } break; + case TX_ITEM_TYPE_OUT_EXT: { + l_addr = ((dap_chain_tx_out_ext_t*)l_tx_item)->addr; + } break; + default:{ + l_out_idx++; + continue; + } + } + + if(!dap_chain_addr_is_blank(&l_addr) && + ((s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_LOCAL && + dap_chain_wallet_addr_cache_get_name(&l_addr) != NULL) || s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_ALL) && + l_addr.net_id.uint64 == l_arg->chain->net_id.uint64 + ){ + pthread_rwlock_wrlock(&s_wallet_cache_rwlock); + dap_wallet_cache_t *l_wallet_item = NULL; + HASH_FIND(hh, s_wallets_cache, &l_addr, sizeof(dap_chain_addr_t), l_wallet_item); + if (l_wallet_item){ + dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; + HASH_FIND(hh, l_wallet_item->wallet_txs, a_datum_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); + if (l_wallet_tx_item){ + HASH_DEL(l_wallet_item->wallet_txs, l_wallet_tx_item); + dap_list_free_full(l_wallet_tx_item->tx_wallet_inputs, NULL); + dap_list_free_full(l_wallet_tx_item->tx_wallet_outputs, NULL); + DAP_DEL_Z(l_wallet_tx_item); + } + if (!l_wallet_item->wallet_txs){ + HASH_DEL(s_wallets_cache, l_wallet_item); + DAP_DEL_Z(l_wallet_item); + } + + unspent_cache_hh_key key = {0}; + key.tx_hash = *a_datum_hash; + key.out_idx = l_out_idx; + dap_wallet_cache_unspent_outs_t *l_item = NULL; + HASH_FIND(hh, l_wallet_item->unspent_outputs, &key, sizeof(unspent_cache_hh_key), l_item); + if (l_item){ + HASH_DEL(l_wallet_item->unspent_outputs, l_item); + DAP_DELETE(l_item); + } + } + pthread_rwlock_unlock(&s_wallet_cache_rwlock); } - if (!l_wallet_item->wallet_txs){ - HASH_DEL(s_wallets_cache, l_wallet_item); - DAP_DEL_Z(l_wallet_item); - } + l_out_idx++; } - pthread_rwlock_unlock(&s_wallet_cache_rwlock); + + // return previous transactions outs to unspent outs cache + TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_IN_ALL, l_size, i, l_tx) { + uint8_t l_cond_type = *l_tx_item; + dap_chain_addr_t l_addr_from = {}; + if(l_cond_type == TX_ITEM_TYPE_IN){ + dap_hash_fast_t l_prev_tx_hash = ((dap_chain_tx_in_t*)l_tx_item)->header.tx_prev_hash; + int l_prev_idx = ((dap_chain_tx_in_t*)l_tx_item)->header.tx_out_prev_idx; + if (dap_hash_fast_is_blank(&l_prev_tx_hash)) + continue; + dap_chain_datum_tx_t *l_tx_prev = (dap_chain_datum_tx_t *)(l_arg->chain->callback_datum_find_by_hash(l_arg->chain, &l_prev_tx_hash, NULL, NULL)->data); + if (!l_tx_prev) + continue; + uint8_t* l_prev_item = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_prev_idx); + if (!l_prev_item) + continue; + uint8_t l_out_type = *(uint8_t *)l_prev_item; + switch(l_out_type){ + case TX_ITEM_TYPE_OUT_OLD: { + l_addr_from = ((dap_chain_tx_out_old_t*)l_prev_item)->addr; + } break; + case TX_ITEM_TYPE_OUT: + case TX_ITEM_TYPE_OUT_EXT: { + l_addr_from = ((dap_chain_tx_out_ext_t*)l_prev_item)->addr; + } break; + default: + continue; + } + + if(!dap_chain_addr_is_blank(&l_addr_from) && ((s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_LOCAL && + dap_chain_wallet_addr_cache_get_name(&l_addr_from) != NULL) || s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_ALL) && + l_addr_from.net_id.uint64 == l_arg->chain->net_id.uint64 + ){ + pthread_rwlock_wrlock(&s_wallet_cache_rwlock); + dap_wallet_cache_t *l_wallet_item = NULL; + HASH_FIND(hh, s_wallets_cache, &l_addr_from, sizeof(dap_chain_addr_t), l_wallet_item); + if (l_wallet_item){ + dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; + HASH_FIND(hh, l_wallet_item->wallet_txs, a_datum_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); + if (l_wallet_tx_item){ + HASH_DEL(l_wallet_item->wallet_txs, l_wallet_tx_item); + dap_list_free_full(l_wallet_tx_item->tx_wallet_inputs, NULL); + dap_list_free_full(l_wallet_tx_item->tx_wallet_outputs, NULL); + DAP_DEL_Z(l_wallet_tx_item); + } + // Add unspent out into cache + dap_wallet_tx_cache_t *l_wallet_prev_tx_item = NULL; + HASH_FIND(hh, l_wallet_item->wallet_txs, &l_prev_tx_hash, sizeof(dap_hash_fast_t), l_wallet_prev_tx_item); + if (l_wallet_prev_tx_item){ + if (!l_wallet_prev_tx_item->ret_code){ + void *l_out = NULL; + for (dap_list_t *it = l_wallet_prev_tx_item->tx_wallet_outputs; it; it=it->next){ + if (((dap_wallet_tx_cache_output_t *)it->data)->tx_out_idx == l_prev_idx) + l_out = ((dap_wallet_tx_cache_output_t *)it->data)->tx_out; + } + if (l_out){ + dap_wallet_cache_unspent_outs_t *l_unspent_out = DAP_NEW_Z(dap_wallet_cache_unspent_outs_t); + l_unspent_out->key.tx_hash = l_prev_tx_hash; + l_unspent_out->key.out_idx = l_prev_idx; + l_unspent_out->output = l_out; + if (l_out_type != TX_ITEM_TYPE_OUT_EXT) + dap_strncpy(l_unspent_out->token_ticker, l_wallet_prev_tx_item->token_ticker, DAP_CHAIN_TICKER_SIZE_MAX); + else + dap_strncpy(l_unspent_out->token_ticker, ((dap_chain_tx_out_ext_t*)l_tx_item)->token, DAP_CHAIN_TICKER_SIZE_MAX); + HASH_ADD(hh, l_wallet_item->unspent_outputs, key, sizeof(unspent_cache_hh_key), l_unspent_out); + } + } + } + + } + pthread_rwlock_unlock(&s_wallet_cache_rwlock); + } + } + } } diff --git a/modules/wallet/include/dap_chain_wallet_cache.h b/modules/wallet/include/dap_chain_wallet_cache.h index 197dcc6565..3b10980084 100644 --- a/modules/wallet/include/dap_chain_wallet_cache.h +++ b/modules/wallet/include/dap_chain_wallet_cache.h @@ -99,10 +99,10 @@ int dap_chain_wallet_cache_tx_find_in_history(dap_chain_addr_t *a_addr, char **a */ int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, dap_list_t **a_outs_list, uint256_t a_value_needed, uint256_t *a_value_transfer); - + int dap_chain_wallet_cache_tx_find_outs(dap_chain_net_t *a_net, const char *a_token_ticker, const dap_chain_addr_t *a_addr, dap_list_t **a_outs_list, uint256_t *a_value_transfer); - + dap_chain_wallet_cache_iter_t *dap_chain_wallet_cache_iter_create(dap_chain_addr_t a_addr); void dap_chain_wallet_cache_iter_delete(dap_chain_wallet_cache_iter_t *a_iter); dap_chain_datum_tx_t *dap_chain_wallet_cache_iter_get(dap_chain_wallet_cache_iter_t *a_iter, dap_chain_wallet_getting_type_t a_type); -- GitLab