diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index ccecb739db3ca02aaa5a3ab9e5e7a5dbb5ace9cc..8e5565f9fdbe9f2686bcbadd6d13adc60aa39b4a 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -112,15 +112,14 @@ typedef struct dap_chain_ledger_tx_bound { dap_chain_hash_fast_t tx_prev_hash_fast; dap_chain_datum_tx_t *tx_prev; union { - struct { - dap_chain_tx_in_t *tx_cur_in; - dap_chain_tx_out_t *tx_prev_out; - }; - struct { - dap_chain_tx_in_cond_t *tx_cur_in_cond; - dap_chain_tx_out_cond_t *tx_prev_out_cond; - }; - }; + dap_chain_tx_in_t *tx_cur_in; + dap_chain_tx_in_cond_t *tx_cur_in_cond; + } in; + union { + dap_chain_tx_out_t *tx_prev_out; + dap_chain_tx_out_ext_t *tx_prev_out_ext; + dap_chain_tx_out_cond_t *tx_prev_out_cond; + } out; dap_chain_ledger_tx_item_t *item_out; } dap_chain_ledger_tx_bound_t; @@ -731,11 +730,11 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t if (l_cond_type == TX_ITEM_TYPE_IN) { l_tx_in = (dap_chain_tx_in_t *)l_list_tmp->data; l_tx_prev_hash = l_tx_in->header.tx_prev_hash; - bound_item->tx_cur_in = l_tx_in; + bound_item->in.tx_cur_in = l_tx_in; } else { // TX_ITEM_TYPE_IN_COND l_tx_in_cond = (dap_chain_tx_in_cond_t *)l_list_tmp->data; l_tx_prev_hash = l_tx_in_cond->header.tx_prev_hash; - bound_item->tx_cur_in_cond = l_tx_in_cond; + bound_item->in.tx_cur_in_cond = l_tx_in_cond; } memcpy(&bound_item->tx_prev_hash_fast, &l_tx_prev_hash, sizeof(dap_chain_hash_fast_t)); @@ -804,15 +803,23 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t uint64_t l_value; // Get list of all 'out' items from previous transaction dap_list_t *l_list_prev_out = dap_chain_datum_tx_items_get(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, NULL); + // Get one 'out' item in previous transaction bound with current 'in' item + void *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_tx_in->header.tx_out_prev_idx); + dap_list_free(l_list_prev_out); + if(!l_tx_prev_out) { + l_err_num = -8; + break; + } if (l_cond_type == TX_ITEM_TYPE_IN) { - // Get one 'out' item in previous transaction bound with current 'in' item - dap_chain_tx_out_t *l_tx_prev_out = dap_list_nth_data(l_list_prev_out, l_tx_in->header.tx_out_prev_idx); - if(!l_tx_prev_out || *(uint8_t *)l_tx_prev_out != TX_ITEM_TYPE_OUT) { + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_prev_out; + if (l_type == TX_ITEM_TYPE_OUT) { + bound_item->out.tx_prev_out = l_tx_prev_out; + } else if (l_type == TX_ITEM_TYPE_OUT_EXT) { + bound_item->out.tx_prev_out_ext = l_tx_prev_out; + } else { l_err_num = -8; break; } - dap_list_free(l_list_prev_out); - bound_item->tx_prev_out = l_tx_prev_out; // calculate hash of public key in current transaction dap_chain_hash_fast_t l_hash_pkey; { @@ -827,22 +834,27 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t // calculate hash from public key dap_hash_fast(l_pkey_ser, l_pkey_ser_size, &l_hash_pkey); // hash of public key in 'out' item of previous transaction - uint8_t *l_prev_out_addr_key = l_tx_prev_out->addr.data.key; - + uint8_t *l_prev_out_addr_key = (l_type == TX_ITEM_TYPE_OUT) ? + bound_item->out.tx_prev_out->addr.data.key : + bound_item->out.tx_prev_out_ext->addr.data.key; // 4. compare public key hashes in the signature of the current transaction and in the 'out' item of the previous transaction if(memcmp(&l_hash_pkey, l_prev_out_addr_key, sizeof(dap_chain_hash_fast_t))) { l_err_num = -9; break; } } - l_value = l_tx_prev_out->header.value; - l_token = l_tx_prev_out->token; + if (l_type == TX_ITEM_TYPE_OUT) { + l_value = bound_item->out.tx_prev_out->header.value; + } else { + l_value = bound_item->out.tx_prev_out_ext->header.value; + l_token = bound_item->out.tx_prev_out_ext->token; + } } else { // TX_ITEM_TYPE_IN_COND - dap_chain_tx_out_cond_t *l_tx_prev_out_cond = dap_list_nth_data(l_list_prev_out, l_tx_in_cond->header.tx_out_prev_idx); - if(!l_tx_prev_out_cond || *(uint8_t *)l_tx_prev_out_cond != TX_ITEM_TYPE_OUT_COND) { + if(*(uint8_t *)l_tx_prev_out != TX_ITEM_TYPE_OUT_COND) { l_err_num = -8; break; } + dap_chain_tx_out_cond_t * l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out; dap_chain_ledger_verificator_t *l_verificator; int l_tmp = (int)l_tx_prev_out_cond->header.subtype; HASH_FIND_INT(s_verificators, &l_tmp, l_verificator); @@ -856,7 +868,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t l_err_num = -14; break; } - bound_item->tx_prev_out_cond = l_tx_prev_out_cond; + bound_item->out.tx_prev_out_cond = l_tx_prev_out_cond; // calculate sum of values from previous transactions l_value = l_tx_prev_out_cond->header.value; l_token = NULL; @@ -908,24 +920,31 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t dap_list_t *l_list_out = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_ALL, NULL); uint64_t l_value; for (l_list_tmp = l_list_out; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp)) { - if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT) { - dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*) l_list_tmp->data; + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data; + if (l_type == TX_ITEM_TYPE_OUT) + { + dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t *)l_list_tmp->data; + if (l_multichannel) { // token ticker is mandatory for multichannel transactions + l_err_num = -16; + break; + } if (emission_flag) { l_value = l_tx_out->header.value; } - if (l_multichannel) { - l_token = l_tx_out->token; - if (!*l_token) { // token ticker is mandatory for multichannel transactions - l_err_num = -16; - break; - } - } else if (*l_tx_out->token) { // token ticker is deprecated for single-channel tx - l_err_num = -17; + l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out); + } else if (l_type == TX_ITEM_TYPE_OUT_EXT) { + dap_chain_tx_out_ext_t *l_tx_out = (dap_chain_tx_out_ext_t *)l_list_tmp->data; + if (!l_multichannel) { // token ticker is depricated for single-channel transactions + l_err_num = -16; break; } + if (emission_flag) { + l_value = l_tx_out->header.value; + l_token = l_tx_out->token; + } l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out); - } else { - dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t*) l_list_tmp->data; + } else if (l_type == TX_ITEM_TYPE_OUT_COND) { + dap_chain_tx_out_cond_t *l_tx_out = (dap_chain_tx_out_cond_t *)l_list_tmp->data; if (emission_flag) { l_value = l_tx_out->header.value; } @@ -1076,28 +1095,34 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx) // int l_list_tmp_num = 0; while(l_list_tmp) { dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data; - uint8_t l_cond = *(uint8_t *)bound_item->tx_cur_in; + dap_chain_tx_item_type_t l_type = *(uint8_t *)&bound_item->in; dap_chain_ledger_tx_item_t *l_prev_item_out = bound_item->item_out; if (*l_prev_item_out->token_tiker) { l_token_ticker = l_prev_item_out->token_tiker; } else { // Previous multichannel transaction - l_token_ticker = bound_item->tx_prev_out->token; + l_token_ticker = bound_item->out.tx_prev_out_ext->token; } - if (l_token_ticker_old && strcmp(l_token_ticker, l_token_ticker_old)) { + if (!l_multichannel && l_token_ticker_old && strcmp(l_token_ticker, l_token_ticker_old)) { l_multichannel = true; } l_token_ticker_old = l_token_ticker; dap_chain_hash_fast_t *l_tx_prev_hash; - if (l_cond == TX_ITEM_TYPE_IN) { - dap_chain_tx_in_t *l_tx_in = bound_item->tx_cur_in; + if (l_type == TX_ITEM_TYPE_IN) { + dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in; // 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); + dap_chain_tx_item_type_t l_out_type = *(uint8_t *)&bound_item->out; + dap_chain_addr_t *l_addr = (l_out_type == TX_ITEM_TYPE_OUT) ? + &bound_item->out.tx_prev_out->addr : + &bound_item->out.tx_prev_out_ext->addr; + char *l_addr_str = dap_chain_addr_to_str(l_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,"SPEND %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; + wallet_balance->balance -= (l_out_type == TX_ITEM_TYPE_OUT) ? + bound_item->out.tx_prev_out->header.value : + bound_item->out.tx_prev_out_ext->header.value; } else { log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_token_ticker); } @@ -1107,7 +1132,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx) l_tx_prev_hash = &(l_prev_item_out->tx_hash_spent_fast[l_tx_in->header.tx_out_prev_idx]); } else { // TX_ITEM_TYPE_IN_COND // all balance deducts performed with previous conditional transaction - dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->tx_cur_in_cond; + dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->in.tx_cur_in_cond; /// Mark 'out' item in cache because it used l_tx_prev_hash = &(l_prev_item_out->tx_hash_spent_fast[l_tx_in_cond->header.tx_out_prev_idx]); } @@ -1164,30 +1189,41 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx) //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)) { - if (*(uint8_t *)l_tx_out->data == TX_ITEM_TYPE_OUT_COND) { + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data; + if (l_type == TX_ITEM_TYPE_OUT_COND) { continue; // balance raise will be with next conditional transaction } - dap_chain_tx_out_t *l_out_item = l_tx_out->data; + dap_chain_tx_out_t *l_out_item; + dap_chain_tx_out_ext_t *l_out_item_ext; + if (l_type == TX_ITEM_TYPE_OUT) { + l_out_item = l_tx_out->data; + } else { + l_out_item_ext = l_tx_out->data; + } if (l_out_item && l_token_ticker) { - char *l_addr_str = dap_chain_addr_to_str(&l_out_item->addr); + dap_chain_addr_t *l_addr = (l_type == TX_ITEM_TYPE_OUT) ? + &l_out_item->addr : + &l_out_item_ext->addr; + char *l_addr_str = dap_chain_addr_to_str(l_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; if (l_multichannel) { - l_token_ticker = l_out_item->token; + l_token_ticker = l_out_item_ext->token; } 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); + uint64_t l_value = (l_type == TX_ITEM_TYPE_OUT) ? l_out_item->header.value : l_out_item_ext->header.value; 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; + wallet_balance->balance += l_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; + wallet_balance->balance += l_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, @@ -1444,31 +1480,46 @@ uint64_t dap_chain_ledger_calc_balance_full(dap_ledger_t *a_ledger, const dap_ch // Get 'out' items from transaction int l_out_item_count = 0; - dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_cur_tx, TX_ITEM_TYPE_OUT, &l_out_item_count); + dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_cur_tx, TX_ITEM_TYPE_OUT_ALL, &l_out_item_count); if(l_out_item_count >= MAX_OUT_ITEMS) { log_it(L_ERROR, "Too many 'out' items=%d in transaction (max=%d)", l_out_item_count, MAX_OUT_ITEMS); assert(l_out_item_count < MAX_OUT_ITEMS); } - dap_list_t *l_list_tmp = l_list_out_items; int l_out_idx_tmp = 0; - while(l_list_tmp) { - const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data; - assert(l_tx_out); - // Check for token name - if (!strcmp(a_token_ticker, l_iter_current->token_tiker) || !strcmp(a_token_ticker, l_tx_out->token)) - { // if transaction has the out item with requested addr - if (!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) { - // if 'out' item not used & transaction is valid - if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) && - dap_chain_datum_tx_verify_sign(l_cur_tx)) - balance += l_tx_out->header.value; + for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) { + assert(l_list_tmp->data); + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data; + if (l_type == TX_ITEM_TYPE_OUT_COND) { + continue; + } + if (l_type == TX_ITEM_TYPE_OUT) { + const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data; + // Check for token name + if (!strcmp(a_token_ticker, l_iter_current->token_tiker)) + { // if transaction has the out item with requested addr + if (!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) { + // if 'out' item not used & transaction is valid + if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) && + dap_chain_datum_tx_verify_sign(l_cur_tx)) + balance += l_tx_out->header.value; + } + } + } + if (l_type == TX_ITEM_TYPE_OUT_EXT) { + const dap_chain_tx_out_ext_t *l_tx_out = (const dap_chain_tx_out_ext_t*) l_list_tmp->data; + // Check for token name + if (!strcmp(a_token_ticker, l_tx_out->token)) + { // if transaction has the out item with requested addr + if (!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) { + // if 'out' item not used & transaction is valid + if(!dap_chain_ledger_item_is_used_out(l_iter_current, l_out_idx_tmp) && + dap_chain_datum_tx_verify_sign(l_cur_tx)) + balance += l_tx_out->header.value; + } } } - // go to the next 'out' item in l_tx_tmp transaction - l_out_idx_tmp++; - l_list_tmp = dap_list_next(l_list_tmp); } - dap_list_free(l_list_tmp); + dap_list_free(l_list_out_items); } pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock); return balance; @@ -1507,20 +1558,34 @@ static dap_chain_ledger_tx_item_t* tx_item_find_by_addr(dap_ledger_t *a_ledger, continue; } // Get 'out' items from transaction - dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL); + dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL); for(dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp)) { - const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data; - assert(l_tx_out); - // If a_token is setup we check if its not our token - miss it - if (a_token && !*l_iter_current->token_tiker && dap_strcmp(l_tx_out->token, a_token)) { + assert(l_list_tmp->data); + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data; + if (l_type == TX_ITEM_TYPE_OUT_COND) { continue; } - // if transaction has the out item with requested addr - if(!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) { - memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t)); - is_tx_found = true; - break; - } + if (l_type == TX_ITEM_TYPE_OUT) { + const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t *)l_list_tmp->data; + // if transaction has the out item with requested addr + if(!memcmp(a_addr, &l_tx_out->addr, sizeof(dap_chain_addr_t))) { + memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t)); + is_tx_found = true; + break; + } + } + if (l_type == TX_ITEM_TYPE_OUT_EXT) { + const dap_chain_tx_out_ext_t *l_tx_out_ext = (const dap_chain_tx_out_ext_t *)l_list_tmp->data; + // If a_token is setup we check if its not our token - miss it + if (a_token && dap_strcmp(l_tx_out_ext->token, a_token)) { + continue; + } // if transaction has the out item with requested addr + if(!memcmp(a_addr, &l_tx_out_ext->addr, sizeof(dap_chain_addr_t))) { + memcpy(a_tx_first_hash, l_tx_hash, sizeof(dap_chain_hash_fast_t)); + is_tx_found = true; + break; + } + } } dap_list_free(l_list_out_items); // already found transaction @@ -1699,24 +1764,36 @@ dap_list_t *dap_chain_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, c uint32_t l_out_idx_tmp = 0; // current index of 'out' item for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) { - if (*(uint8_t *)l_list_tmp->data != TX_ITEM_TYPE_OUT) { + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data; + if (l_type == TX_ITEM_TYPE_OUT_COND) { continue; } - dap_chain_tx_out_t *out_item = l_list_tmp->data; - // if 'out' item has addr = a_addr_from - if(out_item && out_item->header.value && !memcmp(a_addr_from, &out_item->addr, sizeof(dap_chain_addr_t))) { - // Check whether used 'out' items - if(!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, &l_tx_cur_hash, l_out_idx_tmp)) { - list_used_item_t *item = DAP_NEW(list_used_item_t); - memcpy(&item->tx_hash_fast, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t)); - item->num_idx_out = l_out_idx_tmp; - item->value = out_item->header.value; - l_list_used_out = dap_list_append(l_list_used_out, item); - l_value_transfer += item->value; - // already accumulated the required value, finish the search for 'out' items - if(l_value_transfer >= a_value_need) { - break; - } + uint64_t l_value; + if (l_type == TX_ITEM_TYPE_OUT) { + dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t *)l_list_tmp->data; + if (!l_out->header.value || memcmp(a_addr_from, &l_out->addr, sizeof(dap_chain_addr_t))) { + continue; + } + l_value = l_out->header.value; + } else { // TX_ITEM_TYPE_OUT_EXT + dap_chain_tx_out_ext_t *l_out_ext = (dap_chain_tx_out_ext_t *)l_list_tmp->data; + if (!l_out_ext->header.value || memcmp(a_addr_from, &l_out_ext->addr, sizeof(dap_chain_addr_t)) || + strcpy((char *)a_token_ticker, l_out_ext->token)) { + continue; + } + l_value = l_out_ext->header.value; + } + // Check whether used 'out' items + if (!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, &l_tx_cur_hash, l_out_idx_tmp)) { + list_used_item_t *item = DAP_NEW(list_used_item_t); + memcpy(&item->tx_hash_fast, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t)); + item->num_idx_out = l_out_idx_tmp; + item->value = l_value; + l_list_used_out = dap_list_append(l_list_used_out, item); + l_value_transfer += item->value; + // already accumulated the required value, finish the search for 'out' items + if(l_value_transfer >= a_value_need) { + break; } } } diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c index 350bf57843cb3c5b44b47e86104b773337abe1a6..0bdb9260550bdd590f66badd8d3f5076660aa29e 100644 --- a/modules/common/dap_chain_datum_tx.c +++ b/modules/common/dap_chain_datum_tx.c @@ -141,6 +141,7 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h return -1; } + /** * Create 'out' item and insert to transaction * @@ -148,7 +149,23 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h */ int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, uint64_t a_value) { - dap_chain_tx_out_t *l_tx_out = dap_chain_datum_tx_item_out_create(a_addr, a_value, NULL); + dap_chain_tx_out_t *l_tx_out = dap_chain_datum_tx_item_out_create(a_addr, a_value); + if(l_tx_out) { + dap_chain_datum_tx_add_item(a_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + return 1; + } + return -1; +} + +/** + * Create 'out_ext' item and insert to transaction + * + * return 1 Ok, -1 Error + */ +int dap_chain_datum_tx_add_out_ext_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token) +{ + dap_chain_tx_out_ext_t *l_tx_out = dap_chain_datum_tx_item_out_ext_create(a_addr, a_value, a_token); if(l_tx_out) { dap_chain_datum_tx_add_item(a_tx, (const uint8_t *)l_tx_out); DAP_DELETE(l_tx_out); diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index 438e774512fb648b19322cde7768456a9d451541..6c44465b08399af133461ab20a4e36ea8c868ebf 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -58,6 +58,13 @@ static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_t *a_item) return size; } +static size_t dap_chain_tx_out_ext_get_size(const dap_chain_tx_out_ext_t *a_item) +{ + (void) a_item; + size_t size = sizeof(dap_chain_tx_out_ext_t); + return size; +} + static size_t dap_chain_tx_out_cond_get_size(const dap_chain_tx_out_cond_t *a_item) { return sizeof(dap_chain_tx_out_cond_t) + a_item->params_size; @@ -110,6 +117,9 @@ size_t dap_chain_datum_item_tx_get_size(const uint8_t *a_item) case TX_ITEM_TYPE_OUT: // Transaction outputs size = dap_chain_tx_out_get_size((const dap_chain_tx_out_t*) a_item); break; + case TX_ITEM_TYPE_OUT_EXT: + size = dap_chain_tx_out_ext_get_size((const dap_chain_tx_out_ext_t*) a_item); + break; case TX_ITEM_TYPE_RECEIPT: // Receipt size = dap_chain_datum_tx_receipt_get_size((const dap_chain_datum_tx_receipt_t*) a_item); case TX_ITEM_TYPE_IN_COND: // Transaction inputs with condition @@ -194,7 +204,7 @@ dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fa * * return item, NULL Error */ -dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token) +dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value) { if(!a_addr) return NULL; @@ -202,9 +212,18 @@ dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a l_item->header.type = TX_ITEM_TYPE_OUT; l_item->header.value = a_value; memcpy(&l_item->addr, a_addr, sizeof(dap_chain_addr_t)); - if (a_token) { - strcpy(l_item->token, a_token); - } + return l_item; +} + +dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token) +{ + if (!a_addr || !a_token) + return NULL; + dap_chain_tx_out_ext_t *l_item = DAP_NEW_Z(dap_chain_tx_out_ext_t); + l_item->header.type = TX_ITEM_TYPE_OUT_EXT; + l_item->header.value = a_value; + memcpy(&l_item->addr, a_addr, sizeof(dap_chain_addr_t)); + strcpy(l_item->token, a_token); return l_item; } @@ -320,7 +339,8 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id dap_chain_tx_item_type_t l_type = dap_chain_datum_tx_item_get_type(l_item); if (a_type == TX_ITEM_TYPE_ANY || a_type == l_type || (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT) || - (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_COND)) { + (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_COND) || + (a_type == TX_ITEM_TYPE_OUT_ALL && l_type == TX_ITEM_TYPE_OUT_EXT)) { if(a_item_idx_start) *a_item_idx_start = l_item_idx; if(a_item_out_size) diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h index 19cc29e9e542b1208520bb13ca5c709c6f0c2b76..a4a11b7d27703246ffc778bfcb9940b75f291938 100644 --- a/modules/common/include/dap_chain_common.h +++ b/modules/common/include/dap_chain_common.h @@ -173,6 +173,7 @@ typedef union { typedef enum dap_chain_tx_item_type { TX_ITEM_TYPE_IN = 0x00, /// @brief Transaction: inputs TX_ITEM_TYPE_OUT = 0x10, /// @brief Transaction: outputs + TX_ITEM_TYPE_OUT_EXT = 0x11, TX_ITEM_TYPE_PKEY = 0x20, TX_ITEM_TYPE_SIG = 0x30, TX_ITEM_TYPE_TOKEN = 0x40, diff --git a/modules/common/include/dap_chain_datum_tx.h b/modules/common/include/dap_chain_datum_tx.h index 189222a4097f1f0a41a20af87c6a1aa674be5cfa..54885c4863ecfe326112fc46141c54141ac66043 100644 --- a/modules/common/include/dap_chain_datum_tx.h +++ b/modules/common/include/dap_chain_datum_tx.h @@ -106,6 +106,14 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h */ int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, uint64_t a_value); +/** + * Create 'out'_ext item and insert to transaction + * + * return 1 Ok, -1 Error + */ +int dap_chain_datum_tx_add_out_ext_item(dap_chain_datum_tx_t **a_tx, const dap_chain_addr_t *a_addr, + uint64_t a_value, const char *a_token); + /** * Create 'out_cond' item and insert to transaction * diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h index bea1bf9fd272abe470cfbcdccd61651724eb613c..7ef0ab207c26e21ea3c702865a6c4c59815528cb 100644 --- a/modules/common/include/dap_chain_datum_tx_items.h +++ b/modules/common/include/dap_chain_datum_tx_items.h @@ -34,6 +34,7 @@ #include "dap_chain_datum_tx.h" #include "dap_chain_datum_tx_in.h" #include "dap_chain_datum_tx_out.h" +#include "dap_chain_datum_tx_out_ext.h" #include "dap_chain_datum_tx_in_cond.h" #include "dap_chain_datum_tx_out_cond.h" #include "dap_chain_datum_tx_sig.h" @@ -77,7 +78,14 @@ dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fa * * return item, NULL Error */ -dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token); +dap_chain_tx_out_t* dap_chain_datum_tx_item_out_create(const dap_chain_addr_t *a_addr, uint64_t a_value); + +/** + * Create item dap_chain_tx_out_ext_t + * + * return item, NULL Error + */ +dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_addr_t *a_addr, uint64_t a_value, const char *a_token); /** * Create item dap_chain_tx_out_cond_t diff --git a/modules/common/include/dap_chain_datum_tx_out.h b/modules/common/include/dap_chain_datum_tx_out.h index 77dfd998dbb0c9e45a6cf9f5b97f62b8e28eea44..24f8240a6fc37aaf163783b7700dc7d71323e00f 100644 --- a/modules/common/include/dap_chain_datum_tx_out.h +++ b/modules/common/include/dap_chain_datum_tx_out.h @@ -38,5 +38,4 @@ typedef struct dap_chain_tx_out{ uint64_t value; /// @param value @brief Number of Datoshis ( DAP/10^9 ) to be transfered } header; /// Only header's hash is used for verification dap_chain_addr_t addr; //// - char token[DAP_CHAIN_TICKER_SIZE_MAX]; } DAP_ALIGN_PACKED dap_chain_tx_out_t; diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 7d1ad6ca0910e362ad92b9f2754c953c5982c232..809d073a559952b4be4e489f37c794be47a9a4f5 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -3095,7 +3095,7 @@ int com_token_emit(int argc, char ** argv, void *arg_func, char ** str_reply) // create items dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(&l_token_emission_hash, l_ticker); dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0); - dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(l_addr, l_emission_value, NULL); + dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(l_addr, l_emission_value); // pack items to transaction dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token); diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index 00645c770ac735c7a1524634c60093ee62ef67e3..75b4c2b48d5fd000e6582fbb8640319d375656a4 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -101,11 +101,11 @@ bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_ // it's the condition owner, let the transaction to be performed return true; } else { - dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT, NULL); + dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_EXT, NULL); uint64_t l_out_val = 0; for (dap_list_t *l_list_tmp = l_list_out;l_list_tmp; l_list_tmp = l_list_tmp->next) { - dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t *)l_list_tmp->data; + dap_chain_tx_out_ext_t *l_tx_out = (dap_chain_tx_out_ext_t *)l_list_tmp->data; if (memcmp(&l_tx_out->addr, &a_cond->params, sizeof(dap_chain_addr_t)) || strcmp(l_tx_out->token, a_cond->subtype.srv_xchange.token)) { continue; @@ -250,11 +250,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha { // transfer selling coins const dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)l_tx_out_cond->params; - dap_chain_tx_out_t *l_tx_out = dap_chain_datum_tx_item_out_create(l_buyer_addr, a_price->datoshi_sell, a_price->token_sell); - if (l_tx_out) { - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); - DAP_DELETE(l_tx_out); - } else { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, a_price->datoshi_sell, a_price->token_sell) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't add selling coins output"); @@ -263,11 +259,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha // coin back uint64_t l_value_back = l_value_sell - a_price->datoshi_sell; if (l_value_back) { - l_tx_out = dap_chain_datum_tx_item_out_create(l_seller_addr, l_value_back, a_price->token_sell); - if (l_tx_out) { - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); - DAP_DELETE(l_tx_out); - } else { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back, a_price->token_sell) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't add selling coins back output"); @@ -275,11 +267,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha } } //transfer buying coins - l_tx_out = dap_chain_datum_tx_item_out_create(l_seller_addr, a_price->datoshi_buy, a_price->token_buy); - if (l_tx_out) { - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); - DAP_DELETE(l_tx_out); - } else { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, a_price->datoshi_buy, a_price->token_buy) == -1) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Cant add buying coins output"); @@ -290,12 +278,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha uint64_t l_buying_value = l_tx_out_cond->header.value; l_value_back = l_buying_value - a_price->datoshi_buy; if (l_value_back) { - /*l_tx_out = dap_chain_datum_tx_item_out_create(l_buyer_addr, l_value_back, a_price->token_buy); - if (l_tx_out) { - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); - DAP_DELETE(l_tx_out); - } else { - dap_chain_datum_tx_delete(l_tx);*/ + //if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) { log_it(L_WARNING, "Partial exchange not allowed"); return NULL; //}