From 272b608943e1327b3cfc79ecd3c4daf4d85fdde5 Mon Sep 17 00:00:00 2001
From: p-const <p.const@bk.ru>
Date: Fri, 14 Jun 2019 00:46:29 +0300
Subject: [PATCH] balance update and calc fixes

---
 dap_chain_ledger.c | 277 ++++++++++++++++++++++++---------------------
 dap_chain_ledger.h |   5 +-
 2 files changed, 149 insertions(+), 133 deletions(-)

diff --git a/dap_chain_ledger.c b/dap_chain_ledger.c
index 7201976..369dc99 100755
--- a/dap_chain_ledger.c
+++ b/dap_chain_ledger.c
@@ -87,15 +87,17 @@ typedef struct dap_chain_ledger_tx_bound {
     dap_chain_ledger_tx_item_t *item_out;
 } dap_chain_ledger_tx_bound_t;
 
-
-typedef struct dap_ledger_wallet_balance_key{
+// Gotta use a regular null-terminated string instead, for uthash usability
+/*typedef struct dap_ledger_wallet_balance_key{
     dap_chain_addr_t addr;
     char ticker[10];
-} DAP_ALIGN_PACKED dap_ledger_wallet_balance_key_t;
+} DAP_ALIGN_PACKED dap_ledger_wallet_balance_key_t; */
 
 // in-memory wallet balance
 typedef struct dap_ledger_wallet_balance {
-    dap_ledger_wallet_balance_key_t key;
+    //dap_ledger_wallet_balance_key_t key;
+    char *key;
+    char token_ticker[10];
     uint64_t balance;
     UT_hash_handle hh;
 } dap_ledger_wallet_balance_t;
@@ -410,6 +412,25 @@ void dap_chain_ledger_addr_get_token_ticker_all(dap_ledger_t *a_ledger, dap_chai
     *a_tickers_size = l_tickers_pos;
 }
 
+void dap_chain_ledger_addr_get_token_ticker_all_fast(dap_ledger_t *a_ledger, dap_chain_addr_t * a_addr,
+        char *** a_tickers, size_t * a_tickers_size) {
+    dap_ledger_wallet_balance_t *wallet_balance, *tmp;
+    size_t l_count = HASH_COUNT(PVT(a_ledger)->balance_accounts);
+    char **l_tickers = DAP_NEW_Z_SIZE(char*, l_count * sizeof(char*));
+    l_count = 0;
+    char *l_addr = dap_chain_addr_to_str(a_addr);
+    HASH_ITER(hh, PVT(a_ledger)->balance_accounts, wallet_balance, tmp) {
+        char **l_keys = dap_strsplit(wallet_balance->key, " ", -1);
+        if (!dap_strcmp(l_keys[0], l_addr)) {
+            l_tickers[l_count] = dap_strdup(wallet_balance->token_ticker);
+            ++l_count;
+        }
+        dap_strfreev(l_keys);
+    }
+    *a_tickers = l_tickers;
+    *a_tickers_size = l_count;
+}
+
 /**
  * @brief dap_chain_node_datum_tx_calc_hash
  * @param a_tx
@@ -464,7 +485,7 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_find_by_hash(dap_ledger_t *a_ledger, d
  */
 // Checking a new transaction before adding to the cache
 int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
-        dap_list_t **a_list_bound_items)
+        dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out)
 {
     /*
      Steps of checking for current transaction tx2 and every previous transaction tx1:
@@ -627,32 +648,36 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
     }
 
     // Calculate the sum of values in 'out' items from the current transaction
+    dap_list_t *l_list_tx_out = NULL;
     uint64_t l_values_from_cur_tx = 0;
-    if(!l_is_first_transaction || (l_is_first_transaction && l_ledger_priv->check_token_emission))
-            {
-        // find 'out' items
-        dap_list_t *l_list_out = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT, NULL);
-        dap_list_t *l_list_out_cond = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_COND,
-        NULL);
-        // accumalate value ​from all  'out' transactions
-        dap_list_t *l_list_tmp = l_list_out;
-        while(l_list_tmp) {
-            dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*) l_list_tmp->data;
+    bool emission_flag = !l_is_first_transaction || (l_is_first_transaction && l_ledger_priv->check_token_emission);
+    // find 'out' items
+    dap_list_t *l_list_out = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT, NULL);
+    dap_list_t *l_list_out_cond = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_COND, NULL);
+    // accumalate value ​from all  'out' transactions
+    l_list_tmp = l_list_out;
+    while(l_list_tmp) {
+        dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*) l_list_tmp->data;
+        if (emission_flag) {
             l_values_from_cur_tx += l_tx_out->header.value;
-            l_list_tmp = dap_list_next(l_list_tmp);
         }
-        // accumalate value ​from all  'ut_cond' transactions
-        l_list_tmp = l_list_out_cond;
-        while(l_list_tmp) {
-            dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t*) l_list_tmp->data;
+        l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
+        l_list_tmp = dap_list_next(l_list_tmp);
+    }
+    // accumalate value ​from all  'ut_cond' transactions
+    l_list_tmp = l_list_out_cond;
+    while(l_list_tmp) {
+        dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t*) l_list_tmp->data;
+        if (emission_flag) {
             l_values_from_cur_tx += l_tx_out->header.value;
-            l_list_tmp = dap_list_next(l_list_tmp);
         }
-        if ( l_list_out )
-            dap_list_free(l_list_out);
-        if ( l_list_out_cond)
-            dap_list_free(l_list_out_cond);
+        l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out);
+        l_list_tmp = dap_list_next(l_list_tmp);
     }
+    if ( l_list_out )
+        dap_list_free(l_list_out);
+    if ( l_list_out_cond)
+        dap_list_free(l_list_out_cond);
 
     // Additional check whether the transaction is first
     if(l_is_first_transaction)
@@ -663,6 +688,8 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         if(!(l_tx_token = (dap_chain_tx_token_t*) dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL))) {
             if ( l_list_bound_items )
                 dap_list_free_full(l_list_bound_items, free);
+            if (l_list_tx_out)
+                dap_list_free(l_list_tx_out);
             return -4;
         }
         l_tx_token_size = dap_chain_datum_item_tx_get_size((uint8_t*) l_tx_token);
@@ -675,11 +702,15 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                 if(l_token_emission->hdr.value != l_values_from_cur_tx) {
                     if ( l_list_bound_items )
                         dap_list_free_full(l_list_bound_items, free);
+                    if (l_list_tx_out)
+                        dap_list_free(l_list_tx_out);
                     return -5;
                 }
             } else {
                 if ( l_list_bound_items )
                     dap_list_free_full(l_list_bound_items, free);
+                if (l_list_tx_out)
+                    dap_list_free(l_list_tx_out);
                 return -6;
             }
         }
@@ -690,6 +721,8 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
                l_values_from_cur_tx, l_values_from_prev_tx);
         if ( l_list_bound_items )
             dap_list_free_full(l_list_bound_items, free);
+        if (l_list_tx_out)
+            dap_list_free(l_list_tx_out);
         return -7;
     }
 
@@ -697,6 +730,10 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         *a_list_bound_items = l_list_bound_items;
     else if ( l_list_bound_items )
         dap_list_free_full(l_list_bound_items, free);
+    if (a_list_tx_out)
+        *a_list_tx_out = l_list_tx_out;
+    else if (l_list_tx_out)
+        dap_list_free(l_list_tx_out);
     return 0;
 }
 
@@ -712,9 +749,11 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     int ret = 1;
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     dap_list_t *l_list_bound_items = NULL;
+    dap_list_t *l_list_tx_out = NULL;
 
     int l_ret_check;
-    if( (l_ret_check = dap_chain_ledger_tx_cache_check(a_ledger, a_tx, &l_list_bound_items)) < 0){
+    if( (l_ret_check = dap_chain_ledger_tx_cache_check(
+             a_ledger, a_tx, &l_list_bound_items, &l_list_tx_out)) < 0){
         log_it (L_WARNING, "dap_chain_ledger_tx_add() tx not passed the check: code %d ",l_ret_check);
         return -1;
     }
@@ -734,6 +773,21 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
         dap_chain_ledger_tx_item_t *l_prev_item_out = bound_item->item_out;
         if ( l_token_ticker == NULL)
             l_token_ticker = dap_strdup (l_prev_item_out->token_tiker);
+
+        // Update balance: deducts
+        dap_ledger_wallet_balance_t *wallet_balance = NULL;
+        char *l_addr_str = dap_chain_addr_to_str(&bound_item->tx_prev_out->addr);
+        char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
+        HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+        if (wallet_balance) {
+            log_it(L_DEBUG,"SPEDN %lu from addr: %s", bound_item->tx_prev_out->header.value, l_wallet_balance_key);
+            wallet_balance->balance -= bound_item->tx_prev_out->header.value;
+        } else {
+            log_it(L_ERROR,"!!! Attempt to SPEDN from some non-existent balance !!!: %s %s", l_addr_str, l_token_ticker);
+        }
+        DAP_DELETE(l_addr_str);
+        DAP_DELETE(l_wallet_balance_key);
+
         /// Mark 'out' item in cache because it used
         dap_chain_hash_fast_t *l_tx_prev_hash =
                 &(l_prev_item_out->tx_hash_spent_fast[l_tx_in->header.tx_out_prev_idx]);
@@ -771,6 +825,55 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     if (l_list_bound_items)
         dap_list_free_full(l_list_bound_items, free);
 
+    // Try to find token ticker if wasn't
+    if ( l_token_ticker == NULL){
+        int l_base_tx_count = 0;
+        dap_list_t *l_base_tx_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_TOKEN, &l_base_tx_count );
+        if (l_base_tx_count >=1  && l_base_tx_list){
+            dap_chain_tx_token_t * l_tx_token =(dap_chain_tx_token_t *) l_base_tx_list->data;
+            if ( l_tx_token )
+                l_token_ticker = dap_strdup( l_tx_token->header.ticker);
+        }
+    }
+
+    //Update balance : raise
+    for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
+        dap_chain_tx_out_t *l_out_item = l_tx_out->data;
+        if (l_out_item && l_token_ticker) {
+            char *l_addr_str = dap_chain_addr_to_str(&l_out_item->addr);
+            log_it (L_DEBUG, "Check unspent %.03Lf %s for addr %s",
+                    (long double) l_out_item->header.value/ 1000000000000.0L,
+                    l_token_ticker, l_addr_str);
+            dap_ledger_wallet_balance_t *wallet_balance = NULL;
+            char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_token_ticker, (char*)NULL);
+            log_it (L_DEBUG,"\t\tAddr: %s token: %s", l_addr_str, l_token_ticker);
+            HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+            if (wallet_balance) {
+                log_it(L_DEBUG, "Balance item is present in cache");
+                wallet_balance->balance += l_out_item->header.value;
+                DAP_DELETE (l_wallet_balance_key);
+            } else {
+                wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
+                wallet_balance->key = l_wallet_balance_key;
+                wallet_balance->balance += l_out_item->header.value;
+                dap_stpcpy(wallet_balance->token_ticker, l_token_ticker);
+                log_it(L_DEBUG,"!!! Create new balance item: %s %s", l_addr_str, l_token_ticker);
+                HASH_ADD_KEYPTR(hh, PVT(a_ledger)->balance_accounts, wallet_balance->key,
+                                strlen(l_wallet_balance_key), wallet_balance);
+            }
+            log_it(L_INFO, "Updated balance +%.3Lf %s, now %.3Lf on addr %s",
+                   dap_chain_balance_to_coins (l_out_item->header.value),
+                   dap_chain_balance_to_coins (wallet_balance->balance),
+                   l_token_ticker, l_addr_str);
+            DAP_DELETE (l_addr_str);
+        } else {
+            log_it(L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache");
+        }
+    }
+
+    if (l_list_tx_out)
+        dap_list_free(l_list_tx_out);
+
     dap_chain_ledger_tx_item_t *l_item_tmp = NULL;
     pthread_rwlock_wrlock(&l_ledger_priv->ledger_rwlock);
     HASH_FIND(hh, l_ledger_priv->ledger_items, l_tx_hash, sizeof(dap_chain_hash_fast_t), l_item_tmp); // tx_hash already in the hash?
@@ -807,99 +910,6 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
             }
         }
 
-        // Try to find tocken ticker if wasn't
-        if ( l_token_ticker == NULL){
-            int l_base_tx_count = 0;
-            dap_list_t *l_base_tx_list = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_TOKEN, &l_base_tx_count );
-            if (l_base_tx_count >=1  && l_base_tx_list){
-                dap_chain_tx_token_t * l_tx_token =(dap_chain_tx_token_t *) l_base_tx_list->data;
-                if ( l_tx_token )
-
-                    l_token_ticker = dap_strdup( l_tx_token->header.ticker);
-            }
-        }
-
-        // update balance
-        int l_index_tmp = 0;
-        dap_list_t *l_tist_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT, &l_item_tmp->n_outs);
-
-        for (dap_list_t *l_item = l_tist_tmp; l_item; l_item = dap_list_next(l_item), ++l_index_tmp) {
-            dap_chain_tx_out_t *l_out_item = l_item->data;
-            if(l_out_item ) {
-                if(!dap_chain_ledger_tx_hash_is_used_out_item(a_ledger, &l_item_tmp->tx_hash_fast, l_index_tmp)) {
-
-                    if ( l_token_ticker ){
-                        char * l_addr_str = dap_chain_addr_to_str(&l_out_item->addr);
-                        log_it (L_DEBUG,"Check unspent %.03Lf %s to addr %s",
-                                (long double) l_out_item->header.value/ 1000000000000.0L, l_token_ticker,
-                                l_addr_str );
-                        dap_ledger_wallet_balance_t *wallet_balance = NULL;
-                        dap_ledger_wallet_balance_key_t l_balance_key={{0}};
-                        memcpy(&l_balance_key.addr,&l_out_item->addr, sizeof(l_out_item->addr));
-                        snprintf (l_balance_key.ticker,sizeof(l_balance_key.ticker),"%s",  l_token_ticker);
-                        HASH_FIND (hh, PVT(a_ledger)->balance_accounts,&l_balance_key, sizeof(l_balance_key),
-                                  wallet_balance);
-                        if (wallet_balance) {
-                            log_it(L_DEBUG,"!!!Existent balance item found");
-                            wallet_balance->balance += l_out_item->header.value;
-                            //dap_ledger_wallet_balance_t *dummy = NULL;
-                            //HASH_REPLACE(hh, PVT(a_ledger)->balance_accounts, l_balance_key, sizeof(l_balance_key), wallet_balance, dummy);
-                        } else {
-                            wallet_balance = DAP_NEW_Z(dap_ledger_wallet_balance_t);
-                            memcpy(&wallet_balance->key, &l_balance_key , sizeof(dap_ledger_wallet_balance_key_t ));
-                            //wallet_balance->addr = l_out_item->addr;
-                            wallet_balance->balance = l_out_item->header.value;
-                            log_it(L_DEBUG,"!!! Create new balance item: %s %s", l_addr_str,  l_token_ticker);
-                            HASH_ADD(hh, PVT(a_ledger)->balance_accounts, key, sizeof(dap_ledger_wallet_balance_key_t), wallet_balance);
-                        }
-                        log_it(L_INFO, "Updated balance +%.3Lf %s, now %.3Lf on addr %s",
-                               dap_chain_balance_to_coins (l_out_item->header.value)  ,
-                               dap_chain_balance_to_coins (wallet_balance->balance )  ,
-                               l_token_ticker? l_token_ticker :"???" , l_addr_str);
-                        // TODO : put to local db for fast extraction
-                        DAP_DELETE (l_addr_str);
-                    } else
-                        log_it(L_WARNING,"Can't detect tx ticker, can't add in balances cache");
-                }
-            }
-        }
-
-        int l_prev_count = 0;
-        dap_list_t *l_list_tmp_in = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_IN, &l_prev_count);
-        for (dap_list_t *l_item = l_list_tmp_in; l_item; l_item = dap_list_next(l_item)) {
-            dap_chain_tx_in_t *l_in_item = l_item->data;
-            dap_chain_hash_fast_t l_tx_prev_hash = l_in_item->header.tx_prev_hash;
-            if (!dap_hash_fast_is_blank(&l_tx_prev_hash)) {
-                dap_chain_datum_tx_t  * l_tx_prev = dap_chain_ledger_tx_find_by_hash( a_ledger,  &l_tx_prev_hash);
-                dap_list_t *l_list_prev_out = dap_chain_datum_tx_items_get(l_tx_prev, TX_ITEM_TYPE_OUT, NULL);
-                dap_chain_tx_out_t *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_in_item->header.tx_out_prev_idx);
-                if (l_tx_prev_out) {
-                    //charge_off +=
-                    if ( l_token_ticker ){
-                        dap_ledger_wallet_balance_t *wallet_balance = NULL;
-                        dap_ledger_wallet_balance_key_t l_balance_key;
-                        memcpy(&l_balance_key.addr,&l_tx_prev_out->addr, sizeof(l_tx_prev_out->addr));
-                        snprintf(l_balance_key.ticker,sizeof(l_balance_key.ticker),"%s", l_token_ticker);
-
-                        HASH_FIND(hh, PVT(a_ledger)->balance_accounts, &l_balance_key, sizeof(l_balance_key), wallet_balance);
-                        if (wallet_balance) {
-                            wallet_balance->balance -= l_tx_prev_out->header.value;
-                            //dap_ledger_wallet_balance_t *dummy = NULL;
-                            //HASH_REPLACE(hh, PVT(a_ledger)->balance_accounts, addr, sizeof(&l_tx_prev_out->addr), wallet_balance, dummy);
-                        } else {
-                            // impossible
-                        }
-                    }else
-                        log_it(L_WARNING,"Can't detect tx ticker, can't withdraw from balances cache");
-                    // TODO : put to local db
-                }
-            }
-        }
-        if ( l_list_tmp_in )
-            dap_list_free(l_list_tmp_in);
-        if ( l_tist_tmp )
-            dap_list_free( l_tist_tmp );
-
         if ( l_token_ticker == NULL) { //No token ticker in previous txs
             log_it(L_DEBUG, "No token ticker in previous txs");
             int l_tokens_count = 0;
@@ -919,6 +929,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
     }
     pthread_rwlock_tryrdlock (&l_ledger_priv->ledger_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
+    DAP_DELETE(l_token_ticker);
     DAP_DELETE(l_tx_hash);
     return ret;
 }
@@ -1069,23 +1080,23 @@ uint64_t dap_chain_ledger_calc_balance(dap_ledger_t *a_ledger, const dap_chain_a
 {
     uint64_t l_ret = 0;
     dap_ledger_wallet_balance_t *l_balance_item = NULL ,* l_balance_item_tmp = NULL;
-    dap_ledger_wallet_balance_key_t l_balance_key = {{0}};
-    memcpy( &l_balance_key.addr, &a_addr, sizeof(a_addr));
-    snprintf( l_balance_key.ticker,sizeof (l_balance_key.ticker),"%s",a_token_ticker);
-    HASH_FIND(hh,PVT(a_ledger)->balance_accounts,&l_balance_key,sizeof(dap_ledger_wallet_balance_key_t),l_balance_item);
+    char *l_addr = dap_chain_addr_to_str(a_addr);
+    char *l_wallet_balance_key = dap_strjoin(" ", l_addr, a_token_ticker, (char*)NULL);
+
+    HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, l_balance_item);
     if (l_balance_item) {
-        log_it (L_DEBUG,"Found address in cache with balance %llu", l_balance_item->balance);
+        log_it (L_INFO,"Found address in cache with balance %llu", l_balance_item->balance);
         l_ret = l_balance_item->balance;
-    }else{
-        char * l_addr_str = dap_chain_addr_to_str( a_addr);
-        log_it (L_WARNING,"Can't find balance for address %s token \"%s\" in cache", l_addr_str,
+    } /*else {
+        //char * l_addr_str = dap_chain_addr_to_str( a_addr);
+        log_it (L_WARNING,"Can't find balance for address %s token \"%s\" in cache", l_addr,
                 a_token_ticker?a_token_ticker: "???");
-        DAP_DELETE(l_addr_str);
+        //DAP_DELETE(l_addr_str);
         log_it (L_DEBUG,"Total size of hashtable %u", HASH_COUNT( PVT(a_ledger)->balance_accounts ) );
         HASH_ITER(hh,PVT(a_ledger)->balance_accounts,l_balance_item, l_balance_item_tmp ){
-            char * l_addr_str = dap_chain_addr_to_str( &l_balance_item->key.addr);
-            log_it (L_DEBUG,"\t\tAddr: %s token: %s", l_addr_str, l_balance_item->key.ticker  );
-            DAP_DELETE(l_addr_str);
+            //char * l_addr_str = dap_chain_addr_to_str( &l_balance_item->key.addr);
+            log_it (L_DEBUG,"\t\tAddr: %s token: %s", l_addr, l_balance_item->key.ticker  );
+            //DAP_DELETE(l_addr_str);
             if ( memcmp(&l_balance_item->key.addr, a_addr,sizeof(*a_addr) ) == 0 )
                 if ( strcmp (l_balance_item->key.ticker, a_token_ticker) ==0 ) {
                     l_ret = l_balance_item->balance;
@@ -1093,7 +1104,9 @@ uint64_t dap_chain_ledger_calc_balance(dap_ledger_t *a_ledger, const dap_chain_a
                 }
         }
 
-    }
+    }*/
+    DAP_DELETE(l_addr);
+    DAP_DELETE(l_wallet_balance_key);
     return l_ret;
 }
 
diff --git a/dap_chain_ledger.h b/dap_chain_ledger.h
index 9f07c45..fc1fa3e 100755
--- a/dap_chain_ledger.h
+++ b/dap_chain_ledger.h
@@ -90,9 +90,12 @@ const char* dap_chain_ledger_tx_get_token_ticker_by_hash(dap_chain_hash_fast_t *
 void dap_chain_ledger_addr_get_token_ticker_all(dap_ledger_t *a_ledger, dap_chain_addr_t * a_addr,
         char *** a_tickers, size_t * a_tickers_size);
 
+void dap_chain_ledger_addr_get_token_ticker_all_fast(dap_ledger_t *a_ledger, dap_chain_addr_t * a_addr,
+        char *** a_tickers, size_t * a_tickers_size);
+
 // Checking a new transaction before adding to the cache
 int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
-        dap_list_t **a_list_bound_items);
+        dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out);
 
 int dap_chain_node_datum_tx_cache_check(dap_chain_datum_tx_t *a_tx, dap_list_t **a_list_bound_items);
 
-- 
GitLab