diff --git a/modules/wallet/dap_chain_wallet_cache.c b/modules/wallet/dap_chain_wallet_cache.c index e4b852af7fb86ab2af6cfe9ebc9dfe5880a627b0..789cba9e96b25e38e45ebb0ce7bf207123ad5aa7 100644 --- a/modules/wallet/dap_chain_wallet_cache.c +++ b/modules/wallet/dap_chain_wallet_cache.c @@ -112,10 +112,9 @@ static dap_s_wallets_cache_type_t s_wallets_cache_type = DAP_WALLET_CACHE_TYPE_L static dap_wallet_cache_t *s_wallets_cache = NULL; static pthread_rwlock_t s_wallet_cache_rwlock; -static int s_save_tx_into_wallet_cache(dap_chain_t *a_chain, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, - dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action); -static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, - dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action); +static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx, + dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, + dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action, char a_cache_op); static int s_save_cache_for_addr_in_net(dap_chain_net_t *a_net, dap_chain_addr_t *a_addr); 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, @@ -544,171 +543,6 @@ int dap_chain_wallet_cache_tx_find_outs_with_val(dap_chain_net_t *a_net, const c return 0; } -static int s_save_tx_into_wallet_cache(dap_chain_t *a_chain, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, - dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action) -{ - int l_ret_val = 0; - int l_items_cnt = 0; - - - bool l_multichannel = false; - 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*)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; - l_multichannel = true; - } 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 == a_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){ - l_wallet_item = DAP_NEW_Z(dap_wallet_cache_t); - memcpy (&l_wallet_item->wallet_addr, &l_addr, sizeof(dap_chain_addr_t)); - HASH_ADD(hh, s_wallets_cache, wallet_addr, sizeof(dap_chain_addr_t), l_wallet_item); - } - dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; - HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - if (!l_wallet_tx_item){ - l_wallet_tx_item = DAP_NEW_Z(dap_wallet_tx_cache_t); - l_wallet_tx_item->tx_hash = *a_tx_hash; - l_wallet_tx_item->atom_hash = *a_atom_hash; - l_wallet_tx_item->tx = a_tx; - dap_strncpy(l_wallet_tx_item->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); - l_wallet_tx_item->ret_code = a_ret_code; - l_wallet_tx_item->srv_uid = a_srv_uid; - l_wallet_tx_item->action = a_action; - HASH_ADD(hh, l_wallet_item->wallet_txs, tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - } - 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 = 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++; - } - - 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*)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); - dap_chain_datum_tx_t *l_tx_prev = l_prev_datum ? (dap_chain_datum_tx_t *)(l_prev_datum->data) : NULL; - if (!l_tx_prev){ - log_it(L_ERROR, "Can't find previous transactions (hash=%s)", dap_hash_fast_to_str_static(&l_prev_tx_hash)); - 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)); - continue; - } - uint8_t l_out_type = *(uint8_t *)l_prev_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; - } 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; - } 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 == a_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){ - l_wallet_item = DAP_NEW_Z(dap_wallet_cache_t); - memcpy (&l_wallet_item->wallet_addr, &l_addr_from, sizeof(dap_chain_addr_t)); - HASH_ADD(hh, s_wallets_cache, wallet_addr, sizeof(dap_chain_addr_t), l_wallet_item); - } - dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; - HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - if (!l_wallet_tx_item){ - l_wallet_tx_item = DAP_NEW_Z(dap_wallet_tx_cache_t); - l_wallet_tx_item->tx_hash = *a_tx_hash; - l_wallet_tx_item->atom_hash = *a_atom_hash; - l_wallet_tx_item->tx = a_tx; - dap_strncpy(l_wallet_tx_item->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); - l_wallet_tx_item->multichannel = l_multichannel; - l_wallet_tx_item->ret_code = a_ret_code; - l_wallet_tx_item->srv_uid = a_srv_uid; - l_wallet_tx_item->action = a_action; - HASH_ADD(hh, l_wallet_item->wallet_txs, tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - } - dap_wallet_tx_cache_input_t *l_tx_in = DAP_NEW_Z(dap_wallet_tx_cache_input_t); - l_tx_in->tx_prev_hash = l_prev_tx_hash; - 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); - } - } - } - - return l_ret_val; -} - static int s_save_cache_for_addr_in_net(dap_chain_net_t *a_net, dap_chain_addr_t *a_addr) { @@ -723,7 +557,8 @@ static int s_save_cache_for_addr_in_net(dap_chain_net_t *a_net, dap_chain_addr_t l_datum = l_chain->callback_datum_iter_get_next(l_iter)){ if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) - s_save_tx_cache_for_addr(l_chain, a_addr, (dap_chain_datum_tx_t*)l_datum->data, l_iter->cur_hash, l_iter->cur_atom_hash, l_iter->ret_code, l_iter->token_ticker, l_iter->uid, l_iter->action); + s_save_tx_cache_for_addr(l_chain, a_addr, (dap_chain_datum_tx_t*)l_datum->data, l_iter->cur_hash,l_iter->cur_atom_hash, + l_iter->ret_code, l_iter->token_ticker, l_iter->uid, l_iter->action, 'a'); } l_chain->callback_datum_iter_delete(l_iter); break; @@ -735,22 +570,27 @@ static int s_save_cache_for_addr_in_net(dap_chain_net_t *a_net, dap_chain_addr_t return 0; } -static void s_callback_datum_notify(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) +static void s_callback_datum_notify(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) { dap_atom_notify_arg_t *l_arg = (dap_atom_notify_arg_t*)a_arg; - dap_chain_datum_t *l_datum = (dap_chain_datum_t*)a_datum; if (!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) return; - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)l_datum->data; + s_save_tx_cache_for_addr(l_arg->chain, NULL, (dap_chain_datum_tx_t*)l_datum->data, a_datum_hash, a_atom_hash, a_ret_code, + (char*)dap_ledger_tx_get_token_ticker_by_hash(l_arg->net->pub.ledger, a_datum_hash), + a_uid, a_action, 'a'); +} - const char* l_main_token_ticker = NULL; +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 || !a_datum || a_datum->header.type_id != DAP_CHAIN_DATUM_TX) + return; - l_main_token_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_arg->net->pub.ledger, a_datum_hash); - s_save_tx_into_wallet_cache(l_arg->chain, l_tx, a_datum_hash, a_atom_hash, a_ret_code, (char*)l_main_token_ticker, a_uid, a_action); + dap_atom_notify_arg_t *l_arg = (dap_atom_notify_arg_t*)a_arg; + s_save_tx_cache_for_addr(l_arg->chain, NULL, (dap_chain_datum_tx_t*)a_datum->data, a_datum_hash, NULL, 0, + NULL, (dap_chain_net_srv_uid_t){ }, DAP_CHAIN_TX_TAG_ACTION_UNKNOWN, 'd'); } typedef struct wallet_cache_load_args { @@ -809,311 +649,207 @@ static void s_wallet_opened_callback(dap_chain_wallet_t *a_wallet, void *a_arg) } } +static int s_out_idx_cmp(dap_list_t *a_l1, dap_list_t *a_l2) { + dap_wallet_tx_cache_output_t *o1 = a_l1->data, + *o2 = a_l2->data; + return o1->tx_out_idx != o2->tx_out_idx; +} -static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, - dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action) +static int s_save_tx_cache_for_addr(dap_chain_t *a_chain, dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx, + dap_hash_fast_t *a_tx_hash, dap_hash_fast_t *a_atom_hash, int a_ret_code, char* a_main_token_ticker, + dap_chain_net_srv_uid_t a_srv_uid, dap_chain_tx_tag_action_type_t a_action, char a_cache_op) { - int l_ret_val = 0; - int l_items_cnt = 0; + int l_ret_val = 0, l_items_cnt = 0, l_out_idx = 0, l_prev_idx; bool l_multichannel = false; - int l_out_idx = 0; - uint8_t *l_tx_item = NULL; - size_t l_size; int i; - TX_ITEM_ITER_TX_TYPE(l_tx_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, a_tx) { - uint8_t l_out_type = *(uint8_t *)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; - l_multichannel = true; - } break; - default:{ - l_out_idx++; - continue; - } - } - - if(!dap_chain_addr_is_blank(&l_addr) && - dap_chain_addr_compare(&l_addr, a_addr) && - l_addr.net_id.uint64 == a_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){ - l_wallet_item = DAP_NEW_Z(dap_wallet_cache_t); - memcpy (&l_wallet_item->wallet_addr, &l_addr, sizeof(dap_chain_addr_t)); - HASH_ADD(hh, s_wallets_cache, wallet_addr, sizeof(dap_chain_addr_t), l_wallet_item); - } - dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; - HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - if (!l_wallet_tx_item){ - l_wallet_tx_item = DAP_NEW_Z(dap_wallet_tx_cache_t); - l_wallet_tx_item->tx_hash = *a_tx_hash; - l_wallet_tx_item->atom_hash = *a_atom_hash; - l_wallet_tx_item->tx = a_tx; - dap_strncpy(l_wallet_tx_item->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); - l_wallet_tx_item->ret_code = a_ret_code; - l_wallet_tx_item->srv_uid = a_srv_uid; - l_wallet_tx_item->action = a_action; - HASH_ADD(hh, l_wallet_item->wallet_txs, tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - } - 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 = 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++; - } - - l_tx_item = NULL; - 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*)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)) +#define m_check_addr(addr) ( \ + !dap_chain_addr_is_blank(&addr) && ( \ + a_addr ? dap_chain_addr_compare(&addr, a_addr) : \ + ( (s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_LOCAL && dap_chain_wallet_addr_cache_get_name(&addr)) \ + || s_wallets_cache_type == DAP_WALLET_CACHE_TYPE_ALL ) ) \ + && addr.net_id.uint64 == a_chain->net_id.uint64 \ +) + uint8_t *l_tx_item; size_t l_size; + TX_ITEM_ITER_TX(l_tx_item, l_size, a_tx) { + dap_hash_fast_t l_prev_tx_hash; + dap_chain_addr_t l_addr; + uint256_t l_value; + uint8_t *l_prev_item = NULL; + int l_prev_idx; + uint8_t l_item_type = TX_ITEM_TYPE_ANY; + + switch(*l_tx_item) { + case TX_ITEM_TYPE_IN: { + l_prev_tx_hash = ((dap_chain_tx_in_t*)l_tx_item)->header.tx_prev_hash; + 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); dap_chain_datum_tx_t *l_tx_prev = l_prev_datum ? (dap_chain_datum_tx_t *)(l_prev_datum->data) : NULL; - if (!l_tx_prev){ - log_it(L_ERROR, "Can't find previous transactions (hash=%s)", dap_hash_fast_to_str_static(&l_prev_tx_hash)); + if (!l_tx_prev) { + log_it(L_ERROR, "Can't find previous transaction by hash \"%s\"", dap_hash_fast_to_str_static(&l_prev_tx_hash)); 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) + 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 output %d in tx \"%s\"", l_prev_idx, dap_hash_fast_to_str_static(&l_prev_tx_hash)); continue; - 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_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_tx_item)->header.value; - l_addr_from = ((dap_chain_tx_out_ext_t*)l_tx_item)->addr; - } break; - default: - continue; } - - if(!dap_chain_addr_is_blank(&l_addr_from) && - dap_chain_addr_compare(&l_addr_from, a_addr) && - l_addr_from.net_id.uint64 == a_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){ - l_wallet_item = DAP_NEW_Z(dap_wallet_cache_t); - memcpy (&l_wallet_item->wallet_addr, &l_addr_from, sizeof(dap_chain_addr_t)); - HASH_ADD(hh, s_wallets_cache, wallet_addr, sizeof(dap_chain_addr_t), l_wallet_item); - } - dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; - HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - if (!l_wallet_tx_item){ - l_wallet_tx_item = DAP_NEW_Z(dap_wallet_tx_cache_t); - l_wallet_tx_item->tx_hash = *a_tx_hash; - l_wallet_tx_item->atom_hash = *a_atom_hash; - l_wallet_tx_item->tx = a_tx; - dap_strncpy(l_wallet_tx_item->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); - l_wallet_tx_item->multichannel = l_multichannel; - l_wallet_tx_item->ret_code = a_ret_code; - l_wallet_tx_item->srv_uid = a_srv_uid; - l_wallet_tx_item->action = a_action; - HASH_ADD(hh, l_wallet_item->wallet_txs, tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); - } - dap_wallet_tx_cache_input_t *l_tx_in = DAP_NEW_Z(dap_wallet_tx_cache_input_t); - l_tx_in->tx_prev_hash = l_prev_tx_hash; - 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); + switch (*l_prev_item) { + 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 = ((dap_chain_tx_out_old_t*)l_prev_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 = ((dap_chain_tx_out_ext_t*)l_prev_item)->addr; + break; + default: + continue; } + l_item_type = TX_ITEM_TYPE_IN; + } break; + case TX_ITEM_TYPE_OUT_OLD: + l_addr = ((dap_chain_tx_out_old_t*)l_tx_item)->addr; + l_item_type = TX_ITEM_TYPE_OUT_ALL; + break; + case TX_ITEM_TYPE_OUT: + l_addr = ((dap_chain_tx_out_t*)l_tx_item)->addr; + l_item_type = TX_ITEM_TYPE_OUT_ALL; + break; + case TX_ITEM_TYPE_OUT_EXT: + l_addr = ((dap_chain_tx_out_ext_t*)l_tx_item)->addr; + l_multichannel = true; + l_item_type = TX_ITEM_TYPE_OUT_ALL; + break; + case TX_ITEM_TYPE_OUT_COND: + /* Make it explicit for possible future STAKE_LOCK adoption */ + // TODO + ++l_out_idx; + default: + continue; } - } - - return l_ret_val; -} -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 || !a_datum || a_datum->header.type_id != DAP_CHAIN_DATUM_TX) - return; - - 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 ( !m_check_addr(l_addr) ) { + l_out_idx += (int)(l_item_type == TX_ITEM_TYPE_OUT_ALL); + 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); + pthread_rwlock_wrlock(&s_wallet_cache_rwlock); + dap_wallet_cache_t *l_wallet_item = NULL; + dap_wallet_tx_cache_t *l_wallet_tx_item = NULL; + HASH_FIND(hh, s_wallets_cache, &l_addr, sizeof(dap_chain_addr_t), l_wallet_item); + switch (a_cache_op) { + case 'a': + if (!l_wallet_item) { + l_wallet_item = DAP_NEW_Z(dap_wallet_cache_t); + l_wallet_item->wallet_addr = l_addr; + HASH_ADD(hh, s_wallets_cache, wallet_addr, sizeof(dap_chain_addr_t), l_wallet_item); + } + + HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); + if (!l_wallet_tx_item) { + l_wallet_tx_item = DAP_NEW(dap_wallet_tx_cache_t); + *l_wallet_tx_item = (dap_wallet_tx_cache_t){ .tx_hash = *a_tx_hash, .atom_hash = *a_atom_hash, .tx = a_tx, + .multichannel = l_multichannel, .ret_code = a_ret_code, .srv_uid = a_srv_uid, .action = a_action }; + dap_strncpy(l_wallet_tx_item->token_ticker, a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); + HASH_ADD(hh, l_wallet_item->wallet_txs, tx_hash, sizeof(dap_hash_fast_t), l_wallet_tx_item); + } + break; + case 'd': { + if (l_wallet_item) { + HASH_FIND(hh, l_wallet_item->wallet_txs, a_tx_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_DELETE(l_wallet_tx_item); } - if (!l_wallet_item->wallet_txs){ - HASH_DEL(s_wallets_cache, l_wallet_item); - DAP_DEL_Z(l_wallet_item); + } + } + default: break; + } + + + switch (l_item_type) { + case TX_ITEM_TYPE_OUT_ALL: { + switch (a_cache_op) { + case 'a': { + dap_wallet_tx_cache_output_t *l_out = DAP_NEW(dap_wallet_tx_cache_output_t); + *l_out = (dap_wallet_tx_cache_output_t){ .tx_out = l_tx_item, .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 to cache */ + if (!a_ret_code) { + dap_wallet_cache_unspent_outs_t *l_unspent_out = DAP_NEW(dap_wallet_cache_unspent_outs_t); + *l_unspent_out = (dap_wallet_cache_unspent_outs_t) { + .key = { .tx_hash = *a_tx_hash, .out_idx = l_out_idx }, + .output = l_out + }; + dap_strncpy(l_unspent_out->token_ticker, *l_tx_item == TX_ITEM_TYPE_OUT_EXT ? ((dap_chain_tx_out_ext_t*)l_tx_item)->token + : a_main_token_ticker ? a_main_token_ticker : "0", DAP_CHAIN_TICKER_SIZE_MAX); + HASH_ADD(hh, l_wallet_item->unspent_outputs, key, sizeof(unspent_cache_hh_key), l_unspent_out); } - - unspent_cache_hh_key key = {0}; - key.tx_hash = *a_datum_hash; - key.out_idx = l_out_idx; + ++l_out_idx; + } break; + case 'd': { + if ( !l_wallet_item->wallet_txs ) { + HASH_DEL(s_wallets_cache, l_wallet_item); + DAP_DELETE(l_wallet_item); + } + unspent_cache_hh_key key = { .tx_hash = *a_tx_hash, .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){ + if (l_item) { HASH_DEL(l_wallet_item->unspent_outputs, l_item); DAP_DELETE(l_item); } + } break; + default: break; } - pthread_rwlock_unlock(&s_wallet_cache_rwlock); - } - l_out_idx++; - } - - // 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); + } break; + case TX_ITEM_TYPE_IN: { + switch (a_cache_op) { + case 'a': { + dap_wallet_tx_cache_input_t *l_tx_in = DAP_NEW(dap_wallet_tx_cache_input_t); + *l_tx_in = (dap_wallet_tx_cache_input_t) { .tx_prev_hash = l_prev_tx_hash, .tx_out_prev_idx = l_prev_idx, .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 cache */ + if (!a_ret_code) { + unspent_cache_hh_key key = { .tx_hash = l_prev_tx_hash, .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); } - // 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); - } - } + } + } break; + case 'd': { + 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 && !l_wallet_prev_tx_item->ret_code ) { + dap_wallet_tx_cache_output_t l_sought_out = { .tx_out_idx = l_prev_idx }; + void *l_out = dap_list_find(l_wallet_prev_tx_item->tx_wallet_outputs, &l_sought_out, s_out_idx_cmp); + if (l_out) { + dap_wallet_cache_unspent_outs_t *l_unspent_out = DAP_NEW_Z(dap_wallet_cache_unspent_outs_t); + *l_unspent_out = (dap_wallet_cache_unspent_outs_t) { .key = { .tx_hash = l_prev_tx_hash, .out_idx = l_prev_idx }, + .output = l_out }; + dap_strncpy(l_unspent_out->token_ticker, *l_prev_item == TX_ITEM_TYPE_OUT_EXT ? ((dap_chain_tx_out_ext_t*)l_tx_item)->token + : l_wallet_prev_tx_item->token_ticker, 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); - } + } break; + default: break; + } + } break; + default: break; } - } + pthread_rwlock_unlock(&s_wallet_cache_rwlock); + } + return l_ret_val; } - static void s_wallet_cache_iter_fill(dap_chain_wallet_cache_iter_t *a_cache_iter, dap_wallet_tx_cache_t *a_cache_index) { a_cache_iter->cur_item = (void*)a_cache_index;