diff --git a/dap-sdk b/dap-sdk index 69e6e0d245c8d0ded155a79f268ff45300981021..6551148098209cc9237f67453205271a74802d06 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 69e6e0d245c8d0ded155a79f268ff45300981021 +Subproject commit 6551148098209cc9237f67453205271a74802d06 diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index 16cef77e057b7eb79276ad5c36ddd54554d4a2d0..108858895a07b0f4a816b07cc6a8807ec366dd60 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -180,7 +180,8 @@ typedef struct dap_chain_ledger_tx_bound { union { dap_chain_tx_in_t *tx_cur_in; dap_chain_tx_in_cond_t *tx_cur_in_cond; - } in; + dap_chain_tx_in_ems_t *tx_cur_in_ems; + } in; union { dap_chain_tx_out_old_t *tx_prev_out; // 256 @@ -638,8 +639,8 @@ char * dap_ledger_token_tx_item_list(dap_ledger_t * a_ledger, dap_chain_addr_t * } if (dap_hash_fast_is_blank(l_tx_prev_hash)) { l_base_tx = true; - dap_chain_tx_token_t *l_token = (dap_chain_tx_token_t *)dap_chain_datum_tx_item_get( - l_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL); + dap_chain_tx_in_ems_t *l_token = (dap_chain_tx_in_ems_t *)dap_chain_datum_tx_item_get( + l_tx, NULL, TX_ITEM_TYPE_IN_EMS, NULL); if (l_token) l_src_token = l_token->header.ticker; break; @@ -3000,43 +3001,59 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t bound_item = DAP_NEW_Z(dap_chain_ledger_tx_bound_t); dap_chain_tx_in_t *l_tx_in = NULL; dap_chain_addr_t l_tx_in_from={0}; - dap_chain_tx_in_cond_t *l_tx_in_cond; + dap_chain_tx_in_cond_t *l_tx_in_cond = NULL; + dap_chain_tx_in_ems_t * l_tx_in_ems = NULL; dap_chain_hash_fast_t l_tx_prev_hash={0}; uint8_t l_cond_type = *(uint8_t *)l_list_tmp->data; // one of the previous transaction - if (l_cond_type == TX_ITEM_TYPE_IN) { + switch (l_cond_type) { + case 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->in.tx_cur_in = l_tx_in; - } else { // TX_ITEM_TYPE_IN_COND + break; + case 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->in.tx_cur_in_cond = l_tx_in_cond; + break; + case TX_ITEM_TYPE_IN_EMS: + l_tx_in_ems = (dap_chain_tx_in_ems_t *)l_list_tmp->data; + l_tx_prev_hash =l_tx_in_ems->header.token_emission_hash; + bound_item->in.tx_cur_in_ems = l_tx_in_ems; + break; + default: + break; } - bound_item->tx_prev_hash = l_tx_prev_hash; - bool l_is_blank = dap_hash_fast_is_blank(&l_tx_prev_hash); + bound_item->tx_prev_hash = l_tx_prev_hash; + bool l_is_ems = (l_cond_type ==TX_ITEM_TYPE_IN_EMS) ? 1 : 0; char l_tx_prev_hash_str[70]={[0]='\0'}; - if (l_is_blank){ + if (l_is_ems){ debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "Tx check: blank prev hash"); dap_snprintf(l_tx_prev_hash_str,sizeof( l_tx_prev_hash_str),"BLANK"); }else{ dap_chain_hash_fast_to_str(&l_tx_prev_hash,l_tx_prev_hash_str,sizeof(l_tx_prev_hash_str)); } - if (l_is_blank) { // It's the first TX + uint256_t l_value; + void *l_tx_prev_out = NULL; + dap_chain_datum_tx_t *l_tx_prev = NULL; + + if (l_is_ems) { // It's the emission TX // if at least one blank hash is present, then all the hashes should be blank if (l_list_tmp_num > 1) { l_err_num = -3; log_it(L_WARNING, "Only one IN item allowed for base TX"); break; } - dap_chain_tx_token_t *l_tx_token = (dap_chain_tx_token_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL); + dap_chain_tx_in_ems_t *l_tx_token = (dap_chain_tx_in_ems_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_IN_EMS, NULL); if (!l_tx_token) { - log_it(L_WARNING, "tx token item is mandatory fot base TX"); + log_it(L_WARNING, "tx token item is mandatory for base TX"); l_err_num = -4; break; } + bool is_emission = false; l_token = l_tx_token->header.ticker; l_emission_hash = &l_tx_token->header.token_emission_hash; dap_chain_ledger_token_emission_item_t *l_emission_item = s_emission_item_find(a_ledger, l_token, l_emission_hash); @@ -3114,11 +3131,11 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t if (!IS_ZERO_256(l_token_item->total_supply) && compare256(l_token_item->current_supply, l_tx_out->header.value) < 0) { char *l_balance = dap_chain_balance_print(l_token_item->current_supply); - char *l_value = dap_chain_balance_print(l_tx_out->header.value); + char *l_value_ch = dap_chain_balance_print(l_tx_out->header.value); log_it(L_WARNING, "Token current supply %s lower, than emission value = %s", - l_balance, l_value); + l_balance, l_value_ch); DAP_DEL_Z(l_balance); - DAP_DEL_Z(l_value); + DAP_DEL_Z(l_value_ch); l_err_num = -30; break; } @@ -3157,81 +3174,54 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t break; } } - if (!l_emission_item) { - debug_if(s_debug_more && !a_from_threshold, L_WARNING, "Emission for tx_token [%s] wasn't found", l_tx_token->header.ticker); - l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION; - break; - } - if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out)) { - debug_if(s_debug_more, L_WARNING, "Emission for tx_token [%s] is already used", l_tx_token->header.ticker); - l_err_num = -22; - break; - } - dap_chain_datum_token_emission_t * l_token_emission = l_emission_item->datum_token_emission; - int l_outs_count; - dap_list_t *l_list_out = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT, &l_outs_count); - dap_chain_tx_out_t *l_out = l_list_out ? (dap_chain_tx_out_t *)l_list_out->data : NULL; - dap_list_free(l_list_out); - if (l_outs_count != 1) { - l_err_num = -23; - log_it(L_WARNING, "Only one OUT item allowed for base TX"); - break; - } - if (!EQUAL_256(l_token_emission->hdr.value_256, l_out->header.value)) { - l_err_num = -10; - log_it(L_WARNING, "Output value of base TX must be equal emission value"); + else + if(l_emission_item) + { + if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out)) { + debug_if(s_debug_more, L_WARNING, "Emission for tx_token [%s] is already used", l_tx_token->header.ticker); + l_err_num = -22; + break; + } + }//end else emission + bound_item->item_emission = l_emission_item; + } + else //It's not the emission TX + { + // Get previous transaction in the cache by hash + dap_chain_ledger_tx_item_t *l_item_out = NULL; + l_tx_prev = s_find_datum_tx_by_hash(a_ledger, &l_tx_prev_hash, &l_item_out); + if (!l_tx_prev) { // Unchained transaction + debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str); + l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS; break; } - if (memcmp(&l_token_emission->hdr.address, &l_out->addr, sizeof(dap_chain_addr_t))) { - l_err_num = -24; - log_it(L_WARNING, "Output addr of base TX must be equal emission addr"); + bound_item->item_out = l_item_out; + l_token = l_item_out->cache_data.token_ticker; + debug_if(s_debug_more && !a_from_threshold, L_INFO, "Previous transaction was found for hash %s",l_tx_prev_hash_str); + bound_item->tx_prev = l_tx_prev; + + // 2. Check if out in previous transaction has spent + int l_idx = (l_cond_type == TX_ITEM_TYPE_IN) ? l_tx_in->header.tx_out_prev_idx : l_tx_in_cond->header.tx_out_prev_idx; + if (dap_chain_ledger_item_is_used_out(l_item_out, l_idx)) { + l_err_num = -6; break; } - // Match the signature of the emission with the transaction - /*if(!s_tx_match_sign(l_token_emission, a_tx)) { - log_it(L_WARNING, "Base TX is not signed by the same certificate as the emission"); - l_err_num = -25; - break; - }*/ // Base TX can be unsigned so temporary disabled - bound_item->item_emission = l_emission_item; - l_list_bound_items = dap_list_append(l_list_bound_items, bound_item); - break; - } - // Get previous transaction in the cache by hash - dap_chain_ledger_tx_item_t *l_item_out = NULL; - dap_chain_datum_tx_t *l_tx_prev = s_find_datum_tx_by_hash(a_ledger, &l_tx_prev_hash, &l_item_out); - if (!l_tx_prev) { // Unchained transaction - debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str); - l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS; - break; - } - bound_item->item_out = l_item_out; - l_token = l_item_out->cache_data.token_ticker; - debug_if(s_debug_more && !a_from_threshold, L_INFO, "Previous transaction was found for hash %s",l_tx_prev_hash_str); - bound_item->tx_prev = l_tx_prev; - - // 2. Check if out in previous transaction has spent - int l_idx = (l_cond_type == TX_ITEM_TYPE_IN) ? l_tx_in->header.tx_out_prev_idx : l_tx_in_cond->header.tx_out_prev_idx; - if (dap_chain_ledger_item_is_used_out(l_item_out, l_idx)) { - l_err_num = -6; - break; - } - uint256_t l_value; - // Get one 'out' item in previous transaction bound with current 'in' item - void *l_tx_prev_out = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_idx); - if(!l_tx_prev_out) { - l_err_num = -8; - break; - } - // 3. Compare out in previous transaction with currently used out - for (dap_list_t *it = l_list_bound_items; it; it = it->next) { - dap_chain_ledger_tx_bound_t *l_bound_tmp = it->data; - if (l_tx_prev_out == l_bound_tmp->out.tx_prev_out) { - debug_if(s_debug_more, L_ERROR, "Previous transaction output already used in current tx"); - l_err_num = -7; + // Get one 'out' item in previous transaction bound with current 'in' item + l_tx_prev_out = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_idx); + if(!l_tx_prev_out) { + l_err_num = -8; break; } + // 3. Compare out in previous transaction with currently used out + for (dap_list_t *it = l_list_bound_items; it; it = it->next) { + dap_chain_ledger_tx_bound_t *l_bound_tmp = it->data; + if (l_tx_prev_out == l_bound_tmp->out.tx_prev_out) { + debug_if(s_debug_more, L_ERROR, "Previous transaction output already used in current tx"); + l_err_num = -7; + break; + } + } } if (l_err_num) break; @@ -3280,7 +3270,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t l_err_num = -9; break; } - } else { // TX_ITEM_TYPE_IN_COND + } else if(l_cond_type == TX_ITEM_TYPE_IN_COND) { // TX_ITEM_TYPE_IN_COND if(*(uint8_t *)l_tx_prev_out != TX_ITEM_TYPE_OUT_COND) { l_err_num = -8; break; @@ -3330,6 +3320,12 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t bound_item->out.tx_prev_out_cond_256 = l_tx_prev_out_cond; l_value = l_tx_prev_out_cond->header.value; } + else if(l_cond_type == TX_ITEM_TYPE_IN_EMS){ + + l_token = bound_item->item_emission->datum_token_emission->hdr.ticker; + l_value = bound_item->item_emission->datum_token_emission->hdr.value_256; + + } if (! l_token || !*l_token ) { log_it(L_WARNING, "No token ticker found in previous transaction"); l_err_num = -15; @@ -3776,57 +3772,55 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data; void *l_item_in = *(void **)&bound_item->in; dap_chain_tx_item_type_t l_type = *(uint8_t *)l_item_in; - if (l_type == TX_ITEM_TYPE_IN) { - dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in; - if (dap_hash_fast_is_blank(&l_tx_in->header.tx_prev_hash)) { // It's the emission behind - // Find token ticker for emission - dap_chain_tx_token_t * l_tx_token = (dap_chain_tx_token_t *) dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL); - if (l_tx_token) - l_main_token_ticker = l_tx_token->header.ticker; - else { - log_it(L_ERROR, "No token item with blank prev tx hash"); + if (l_type == TX_ITEM_TYPE_IN_EMS) { + // It's the emission behind + // Find token ticker for emission + dap_chain_tx_in_ems_t * l_tx_token = (dap_chain_tx_in_ems_t *) dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_IN_EMS, NULL); + if (l_tx_token) + l_main_token_ticker = l_tx_token->header.ticker; + else { + log_it(L_ERROR, "No token item with blank prev tx hash"); + break; + } + if (bound_item->tx_prev) { // It's the stake lock emission + dap_chain_ledger_token_item_t *l_token_item = NULL; + pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock); + HASH_FIND_STR(l_ledger_priv->tokens, l_main_token_ticker, l_token_item); + pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock); + if (!l_token_item){ + log_it(L_ERROR, "No token item found for token %s", l_main_token_ticker); break; } - if (bound_item->tx_prev) { // It's the stake lock emission - dap_chain_ledger_token_item_t *l_token_item = NULL; - pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock); - HASH_FIND_STR(l_ledger_priv->tokens, l_main_token_ticker, l_token_item); - pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock); - if (!l_token_item){ - log_it(L_ERROR, "No token item found for token %s", l_main_token_ticker); - break; - } - if (!IS_ZERO_256(l_token_item->total_supply)) { - dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT, 0); - SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply); - char *l_balance = dap_chain_balance_print(l_token_item->current_supply); - log_it(L_DEBUG, "New current supply %s for token %s", l_balance, l_token_item->ticker); - DAP_DEL_Z(l_balance); - if (PVT(a_ledger)->cached) - s_ledger_token_cache_update(a_ledger, l_token_item); - } - bound_item->stake_lock_item->tx_used_out = *a_tx_hash; - if (PVT(a_ledger)->cached) - // Mirror it in cache - s_ledger_stake_lock_cache_update(a_ledger, bound_item->stake_lock_item); - } else { // It's the general emission - // Mark it as used with base tx hash - bound_item->item_emission->tx_used_out = *a_tx_hash; + if (!IS_ZERO_256(l_token_item->total_supply)) { + dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*)dap_chain_datum_tx_item_get(a_tx, 0, TX_ITEM_TYPE_OUT, 0); + SUBTRACT_256_256(l_token_item->current_supply, l_tx_out->header.value, &l_token_item->current_supply); + char *l_balance = dap_chain_balance_print(l_token_item->current_supply); + log_it(L_DEBUG, "New current supply %s for token %s", l_balance, l_token_item->ticker); + DAP_DEL_Z(l_balance); if (PVT(a_ledger)->cached) - // Mirror it in cache - s_ledger_emission_cache_update(a_ledger, bound_item->item_emission); + s_ledger_token_cache_update(a_ledger, l_token_item); } - l_list_tmp = dap_list_next(l_list_tmp); - i--; // Do not calc this output with tx used items - l_outs_used--; - continue; + bound_item->stake_lock_item->tx_used_out = *a_tx_hash; + if (PVT(a_ledger)->cached) + // Mirror it in cache + s_ledger_stake_lock_cache_update(a_ledger, bound_item->stake_lock_item); + } else { // It's the general emission + // Mark it as used with base tx hash + bound_item->item_emission->tx_used_out = *a_tx_hash; + if (PVT(a_ledger)->cached) + // Mirror it in cache + s_ledger_emission_cache_update(a_ledger, bound_item->item_emission); } + l_list_tmp = dap_list_next(l_list_tmp); + i--; // Do not calc this output with tx used items + l_outs_used--; + continue; } dap_chain_ledger_tx_item_t *l_prev_item_out = bound_item->item_out; l_cur_token_ticker = l_prev_item_out->cache_data.token_ticker; if (!l_main_token_ticker) l_main_token_ticker = l_cur_token_ticker; - int l_tx_prev_out_used_idx; + int l_tx_prev_out_used_idx = 0; if (l_type == TX_ITEM_TYPE_IN) { dap_chain_tx_in_t *l_tx_in = bound_item->in.tx_cur_in; dap_ledger_wallet_balance_t *wallet_balance = NULL; @@ -3874,7 +3868,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d DAP_DELETE(l_wallet_balance_key); /// Mark 'out' item in cache because it used l_tx_prev_out_used_idx = l_tx_in->header.tx_out_prev_idx; - } else { // TX_ITEM_TYPE_IN_COND + } 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->in.tx_cur_in_cond; /// Mark 'out' item in cache because it used @@ -3893,6 +3887,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d if (l_verificator && l_verificator->callback_added) l_verificator->callback_added(a_ledger, a_tx, l_cond); } + // add a used output l_prev_item_out->cache_data.tx_hash_spent_fast[l_tx_prev_out_used_idx] = *a_tx_hash; l_prev_item_out->cache_data.n_outs_used++; @@ -3944,6 +3939,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d l_list_tmp = dap_list_next(l_list_tmp); } + //Update balance : raise bool l_multichannel = false; for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) { diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c index 6780258f57302a9ed0798d13ea6c13ebbdf08a1f..d26b3ed46fc804d0d61ee56db46a7a6d16b13bd2 100644 --- a/modules/chain/tests/dap_chain_ledger_tests.c +++ b/modules/chain/tests/dap_chain_ledger_tests.c @@ -4,6 +4,7 @@ #include "dap_chain_wallet.h" #include "dap_math_ops.h" +static const uint64_t s_fee = 2; static const uint64_t s_total_supply = 500; static const uint64_t s_standard_value_tx = 500; static const char* s_token_ticker = "TestCoins"; @@ -45,24 +46,26 @@ dap_chain_datum_tx_t *dap_chain_ledger_test_create_datum_base_tx( dap_chain_hash_fast_t *l_emi_hash, dap_chain_addr_t a_addr_to, dap_cert_t *a_cert) { + uint256_t l_value_fee = dap_chain_uint256_from(s_fee); + uint256_t l_value_need = a_emi->hdr.value_256; dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t)); l_tx->header.ts_created = time(NULL); dap_chain_hash_fast_t l_tx_prev_hash = { 0 }; - dap_chain_tx_token_t *l_token = DAP_NEW_Z(dap_chain_tx_token_t); - l_token->header.type = TX_ITEM_TYPE_TOKEN; - l_token->header.token_emission_chain_id.uint64 = 0; - l_token->header.token_emission_hash = *l_emi_hash; - strcpy(l_token->header.ticker, a_emi->hdr.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(&a_addr_to, a_emi->hdr.value_256); - - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_token); - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); + dap_chain_tx_in_ems_t *l_in_ems = DAP_NEW_Z(dap_chain_tx_in_ems_t); + l_in_ems->header.type = TX_ITEM_TYPE_IN_EMS; + l_in_ems->header.token_emission_chain_id.uint64 = 0; + l_in_ems->header.token_emission_hash = *l_emi_hash; + strcpy(l_in_ems->header.ticker, a_emi->hdr.ticker); + SUBTRACT_256_256(l_value_need, l_value_fee, &l_value_need); + dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(&a_addr_to, l_value_need); + dap_chain_tx_out_cond_t *l_tx_out_fee = dap_chain_datum_tx_item_out_cond_create_fee(l_value_fee); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_out_fee); dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key); - DAP_DEL_Z(l_token); - DAP_DEL_Z(l_in); + DAP_DEL_Z(l_in_ems); DAP_DEL_Z(l_out); + DAP_DEL_Z(l_tx_out_fee); return l_tx; } @@ -87,7 +90,7 @@ void dap_chain_ledger_test_double_spending( dap_chain_addr_t l_addr_first = {0}; dap_chain_addr_fill_from_key(&l_addr_first, l_first_cert->enc_key, a_net_id); dap_chain_datum_tx_t *l_first_tx = dap_chain_ledger_test_create_tx(a_from_key, a_prev_hash, - &l_addr_first, dap_chain_uint256_from(s_standard_value_tx)); + &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee)); dap_assert_PIF(l_first_tx, "Can't creating base transaction."); dap_chain_hash_fast_t l_first_tx_hash = {0}; dap_hash_fast(l_first_tx, dap_chain_datum_tx_get_size(l_first_tx), &l_first_tx_hash); @@ -95,7 +98,7 @@ void dap_chain_ledger_test_double_spending( uint256_t l_balance = dap_chain_ledger_calc_balance(a_ledger, &l_addr_first, s_token_ticker); // Second tx dap_chain_datum_tx_t *l_second_tx = dap_chain_ledger_test_create_tx(a_from_key, a_prev_hash, - &l_addr_first, dap_chain_uint256_from(s_standard_value_tx)); + &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee)); dap_chain_hash_fast_t l_second_tx_hash = {0}; dap_hash_fast(l_second_tx, dap_chain_datum_tx_get_size(l_second_tx), &l_second_tx_hash); dap_assert_PIF(dap_chain_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false) != 1, "Added second transaction on ledger"); @@ -232,12 +235,12 @@ void dap_chain_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a "Can't added base tx in white address"); dap_hash_fast_t l_tx_addr4_hash = {0}; dap_chain_datum_tx_t *l_tx_to_addr4 = dap_chain_ledger_test_create_tx(l_addr_1->enc_key, &l_btx_addr1_hash, - l_addr_4->addr, dap_chain_uint256_from(s_total_supply)); + l_addr_4->addr, dap_chain_uint256_from(s_total_supply-s_fee)); dap_hash_fast(l_tx_to_addr4, dap_chain_datum_tx_get_size(l_tx_to_addr4), &l_tx_addr4_hash); dap_assert_PIF(dap_chain_ledger_tx_add(a_ledger, l_tx_to_addr4, &l_tx_addr4_hash, false) == 1, "Can't added transaction to address from white list in ledger"); dap_chain_datum_tx_t *l_tx_to_addr3 = dap_chain_ledger_test_create_tx(l_addr_4->enc_key, &l_tx_addr4_hash, - l_addr_3->addr, dap_chain_uint256_from(s_total_supply)); + l_addr_3->addr, dap_chain_uint256_from(s_total_supply-s_fee)); dap_hash_fast_t l_tx_addr3_hash = {0}; dap_hash_fast(l_tx_to_addr3, dap_chain_datum_tx_get_size(l_tx_to_addr3), &l_tx_addr3_hash); int res_add_tx = dap_chain_ledger_tx_add(a_ledger, l_tx_to_addr3, &l_tx_addr3_hash, false); @@ -376,6 +379,7 @@ void dap_chain_ledger_test_run(void){ l_check_added_decl_token = dap_chain_ledger_token_decl_add_check(l_ledger, l_token_decl, l_token_decl_size); dap_assert_PIF(l_check_added_decl_token == 0, "Checking whether it is possible to add a token declaration to ledger."); dap_assert_PIF(!dap_chain_ledger_token_add(l_ledger, l_token_decl, l_token_decl_size), "Adding token declaration to ledger."); + // Create emission dap_chain_addr_t l_addr = {0}; dap_chain_addr_fill_from_key(&l_addr, l_cert->enc_key, l_iddn); @@ -394,7 +398,9 @@ void dap_chain_ledger_test_run(void){ dap_hash_fast(l_base_tx, dap_chain_datum_tx_get_size(l_base_tx), &l_hash_btx); dap_assert_PIF(dap_chain_ledger_tx_add(l_ledger, l_base_tx, &l_hash_btx, false) == 1, "Added base tx in ledger."); uint256_t l_balance_example = dap_chain_uint256_from(s_standard_value_tx); - uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, &l_addr, s_token_ticker); + uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, &l_addr, s_token_ticker); + uint256_t l_fee = dap_chain_uint256_from(s_fee); + SUM_256_256(l_balance,l_fee,&l_balance); dap_assert_PIF(!compare256(l_balance, l_balance_example), "Checking the availability of the necessary balance " "on the wallet after the first transaction."); dap_pass_msg("Validation of the declaration of the tocen, creation of an emission and a basic transaction using this in the ledger."); @@ -409,8 +415,9 @@ void dap_chain_ledger_test_run(void){ dap_pass_msg("Checking for a failure to add a second base transaction for the same issue to the ledger."); } else { dap_fail("Checking for a failure to add a second base transaction for the same issue to the ledger."); - } + } dap_chain_ledger_test_double_spending(l_ledger, &l_hash_btx, l_cert->enc_key, l_iddn); dap_chain_ledger_test_excess_supply(l_ledger, l_cert, &l_addr); - dap_chain_ledger_test_write_back_list(l_ledger, l_cert, l_iddn); + //dap_chain_ledger_test_write_back_list(l_ledger, l_cert, l_iddn); + } diff --git a/modules/channel/chain/include/dap_stream_ch_chain_pkt.h b/modules/channel/chain/include/dap_stream_ch_chain_pkt.h index dabfa60e075034053aa74c81ea011364604041e8..531f54d3f667fc1c16e9873f496a2f6dcd599e48 100644 --- a/modules/channel/chain/include/dap_stream_ch_chain_pkt.h +++ b/modules/channel/chain/include/dap_stream_ch_chain_pkt.h @@ -113,7 +113,7 @@ typedef struct dap_stream_ch_chain_pkt_hdr{ uint8_t padding[7]; } DAP_ALIGN_PACKED; uint64_t ext_id; - } DAP_ALIGN_PACKED; + }DAP_ALIGN_PACKED; dap_chain_net_id_t net_id; dap_chain_id_t chain_id; dap_chain_cell_id_t cell_id; diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c index 4b51e489b252ffa59afb865b9264597cbe294307..92f2c1eb9dfd80ce651b11e346baf0291f73c2c6 100644 --- a/modules/common/dap_chain_datum.c +++ b/modules/common/dap_chain_datum.c @@ -275,8 +275,8 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum, DAP_DELETE(l_coins_str); DAP_DELETE(l_addr_str); } break; - case TX_ITEM_TYPE_TOKEN: { - l_hash_tmp = &((dap_chain_tx_token_t*)item)->header.token_emission_hash; + case TX_ITEM_TYPE_IN_EMS: { + l_hash_tmp = &((dap_chain_tx_in_ems_t*)item)->header.token_emission_hash; if (!dap_strcmp(a_hash_out_type, "hex")) l_hash_str = dap_chain_hash_fast_to_str_new(l_hash_tmp); else @@ -285,12 +285,12 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum, "\t\t ticker: %s \n" "\t\t token_emission_hash: %s\n" "\t\t token_emission_chain_id: 0x%016"DAP_UINT64_FORMAT_x"\n", - ((dap_chain_tx_token_t*)item)->header.ticker, + ((dap_chain_tx_in_ems_t*)item)->header.ticker, l_hash_str, - ((dap_chain_tx_token_t*)item)->header.token_emission_chain_id.uint64); + ((dap_chain_tx_in_ems_t*)item)->header.token_emission_chain_id.uint64); DAP_DELETE(l_hash_str); } break; - case TX_ITEM_TYPE_TOKEN_EXT: { + case TX_ITEM_TYPE_IN_EMS_EXT: { l_hash_tmp = &((dap_chain_tx_token_ext_t*)item)->header.ext_tx_hash; if (!dap_strcmp(a_hash_out_type, "hex")) l_hash_str = dap_chain_hash_fast_to_str_new(l_hash_tmp); diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index d4b83fdf6f146630053b3ae7d42e617fb35a434d..0bd20cb46c78ef6470500a1e232a36328c210dfc 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -92,10 +92,10 @@ static size_t dap_chain_tx_sig_get_size(const dap_chain_tx_sig_t *a_item) return size; } -static size_t dap_chain_tx_token_get_size(const dap_chain_tx_token_t *a_item) +static size_t dap_chain_tx_token_get_size(const dap_chain_tx_in_ems_t *a_item) { (void) a_item; - size_t size = sizeof(dap_chain_tx_token_t); + size_t size = sizeof(dap_chain_tx_in_ems_t); return size; } @@ -129,7 +129,7 @@ dap_chain_tx_item_type_t dap_chain_datum_tx_item_str_to_type(const char *a_datum else if(!dap_strcmp(a_datum_name, "sign")) return TX_ITEM_TYPE_SIG; else if(!dap_strcmp(a_datum_name, "token")) - return TX_ITEM_TYPE_TOKEN; + return TX_ITEM_TYPE_IN_EMS; else if(!dap_strcmp(a_datum_name, "in_cond")) return TX_ITEM_TYPE_IN_COND; else if(!dap_strcmp(a_datum_name, "out_cond")) @@ -213,8 +213,8 @@ size_t dap_chain_datum_item_tx_get_size(const void *a_item) case TX_ITEM_TYPE_SIG: // Transaction signatures size = dap_chain_tx_sig_get_size((const dap_chain_tx_sig_t*) a_item); break; - case TX_ITEM_TYPE_TOKEN: // token item - size = dap_chain_tx_token_get_size((const dap_chain_tx_token_t*) a_item); + case TX_ITEM_TYPE_IN_EMS: // token item + size = dap_chain_tx_token_get_size((const dap_chain_tx_in_ems_t*) a_item); break; case TX_ITEM_TYPE_TSD: size = dap_chain_tx_tsd_get_size((const dap_chain_tx_tsd_t*)a_item); @@ -230,12 +230,12 @@ size_t dap_chain_datum_item_tx_get_size(const void *a_item) * * return item, NULL Error */ -dap_chain_tx_token_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker) +dap_chain_tx_in_ems_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker) { if(!a_ticker) return NULL; - dap_chain_tx_token_t *l_item = DAP_NEW_Z(dap_chain_tx_token_t); - l_item->header.type = TX_ITEM_TYPE_TOKEN; + dap_chain_tx_in_ems_t *l_item = DAP_NEW_Z(dap_chain_tx_in_ems_t); + l_item->header.type = TX_ITEM_TYPE_IN_EMS; l_item->header.token_emission_chain_id.uint64 = a_id.uint64; l_item->header.token_emission_hash = *a_datum_token_hash;; strncpy(l_item->header.ticker, a_ticker, sizeof(l_item->header.ticker) - 1); @@ -497,7 +497,9 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id (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) || (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN) || - (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN_COND)) { + (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN_COND) || + (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN_EMS) || + (a_type == TX_ITEM_TYPE_IN_ALL && l_type == TX_ITEM_TYPE_IN_EMS_EXT)) { if(a_item_idx) *a_item_idx = 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 09c070799482605cc42ed512bf61aef1de91b83c..e17af915462c1d1f6ec167f13ba2a40a8816f647 100644 --- a/modules/common/include/dap_chain_common.h +++ b/modules/common/include/dap_chain_common.h @@ -204,8 +204,8 @@ enum dap_chain_tx_item_type { TX_ITEM_TYPE_PKEY = 0x20, TX_ITEM_TYPE_SIG = 0x30, - TX_ITEM_TYPE_TOKEN = 0x40, - TX_ITEM_TYPE_TOKEN_EXT = 0x41, + TX_ITEM_TYPE_IN_EMS = 0x40, + TX_ITEM_TYPE_IN_EMS_EXT = 0x41, TX_ITEM_TYPE_IN_COND = 0x50, /// @brief Transaction: conditon inputs diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h index 74299c607e06c7b0dd91cac5d8171e7da3332a4d..8e83de002985ad6fa77e858d75ae3ddf85cf5a4e 100644 --- a/modules/common/include/dap_chain_datum_tx_items.h +++ b/modules/common/include/dap_chain_datum_tx_items.h @@ -70,8 +70,8 @@ DAP_STATIC_INLINE const char * dap_chain_datum_tx_item_type_to_str(dap_chain_tx_ case TX_ITEM_TYPE_OUT_EXT: return "TX_ITEM_TYPE_OUT_EXT"; // 256 case TX_ITEM_TYPE_PKEY: return "TX_ITEM_TYPE_PKEY"; case TX_ITEM_TYPE_SIG: return "TX_ITEM_TYPE_SIG"; - case TX_ITEM_TYPE_TOKEN: return "TX_ITEM_TYPE_TOKEN"; - case TX_ITEM_TYPE_TOKEN_EXT: return "TX_ITEM_TYPE_TOKEN_EXT"; + case TX_ITEM_TYPE_IN_EMS: return "TX_ITEM_TYPE_IN_EMS"; + case TX_ITEM_TYPE_IN_EMS_EXT: return "TX_ITEM_TYPE_IN_EMS_EXT"; case TX_ITEM_TYPE_IN_COND: return "TX_ITEM_TYPE_IN_COND"; case TX_ITEM_TYPE_OUT_COND: return "TX_ITEM_TYPE_OUT_COND"; // 256 case TX_ITEM_TYPE_RECEIPT: return "TX_ITEM_TYPE_RECEIPT"; @@ -108,7 +108,7 @@ size_t dap_chain_datum_item_tx_get_size(const void *a_item); * * return item, NULL Error */ -dap_chain_tx_token_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker); +dap_chain_tx_in_ems_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker); /** * Create item dap_chain_tx_out_old_t diff --git a/modules/common/include/dap_chain_datum_tx_token.h b/modules/common/include/dap_chain_datum_tx_token.h index f385363a12654da1b948bc462e7afd132bc47f4a..63a86c6f1a4d541cf1674c2263e7b907dabd8e27 100644 --- a/modules/common/include/dap_chain_datum_tx_token.h +++ b/modules/common/include/dap_chain_datum_tx_token.h @@ -40,7 +40,7 @@ typedef struct dap_chain_tx_token{ dap_chain_id_t token_emission_chain_id; dap_chain_hash_fast_t token_emission_hash; } header; /// Only header's hash is used for verification -} DAP_ALIGN_PACKED dap_chain_tx_token_t; +} DAP_ALIGN_PACKED dap_chain_tx_in_ems_t; /** diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index 904435d085cccbebbe57c3d84c2449465a9b3c63..fef0ffa03a1f378ceec9cfc104cadf3499b99ee6 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -628,7 +628,7 @@ char *dap_chain_mempool_tx_create_cond(dap_chain_net_t *a_net, dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(l_ledger, a_token_ticker, &l_addr_from, l_value_need, &l_value_transfer); if(!l_list_used_out) { - log_it( L_ERROR, "Nothing to tranfer (not enough funds)"); + log_it( L_ERROR, "Nothing to transfer (not enough funds)"); return NULL; } @@ -699,37 +699,131 @@ char *dap_chain_mempool_tx_create_cond(dap_chain_net_t *a_net, char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash, dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker, - dap_chain_addr_t *a_addr_to, dap_cert_t **a_certs, size_t a_certs_count, - const char *a_hash_out_type) + dap_enc_key_t *a_key_from, dap_chain_addr_t *a_addr_to, dap_cert_t **a_certs, size_t a_certs_count, + const char *a_hash_out_type, uint256_t a_value_fee) { - // create first transaction (with tx_token) + uint256_t l_net_fee = {}; + uint256_t l_value_need = a_emission_value; + uint256_t l_value_transfer = {}; + dap_chain_addr_t l_addr_fee = {}; + dap_chain_addr_t* l_addr_from = NULL; + dap_chain_tx_out_cond_t *l_tx_out_fee = NULL; + dap_chain_tx_out_t *l_out_fee_net; + dap_chain_tx_in_t *l_in; + dap_list_t *l_list_used_out; + const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker; + bool not_native = dap_strcmp(a_ticker, l_native_ticker); + bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_fee); + dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t)); l_tx->header.ts_created = time(NULL); - dap_chain_hash_fast_t l_tx_prev_hash = { 0 }; - // create items - - dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_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(a_addr_to, a_emission_value); - - // pack items to transaction - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token); - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); - dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out); - - if (a_certs) { - // Sign all that we have with certs - for(size_t i = 0; i < a_certs_count; i++) { - if(dap_chain_datum_tx_add_sign_item(&l_tx, a_certs[i]->enc_key) < 0) { - log_it(L_WARNING, "No private key for certificate '%s'", a_certs[i]->name); + + if (not_native) + { + l_addr_from = DAP_NEW_Z(dap_chain_addr_t); + dap_chain_addr_fill_from_key(l_addr_from, a_key_from, a_chain->net_id); + if(!l_addr_from){ + log_it(L_WARNING,"Can't fill address from transfer"); + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + // list of transaction with 'out' items + l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker, + l_addr_from, l_net_fee, &l_value_transfer); + if (!l_list_used_out) { + log_it(L_WARNING,"Not enough funds to transfer"); + DAP_DEL_Z(l_addr_from); + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + //add in + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + + //add out + uint256_t l_value_back = l_value_transfer; // how much datoshi add to 'out' items + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)){ + dap_chain_datum_tx_delete(l_tx); + DAP_DEL_Z(l_addr_from); + return NULL; + } + if(l_net_fee_used){ + // Network fee + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker)){ + dap_chain_datum_tx_delete(l_tx); + DAP_DEL_Z(l_addr_from); return NULL; } + SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back); } + if (!IS_ZERO_256(a_value_fee)) + SUBTRACT_256_256(l_value_back, a_value_fee, &l_value_back); + // coin back + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_native_ticker)){ + dap_chain_datum_tx_delete(l_tx); + DAP_DEL_Z(l_addr_from); + return NULL; + } + DAP_DEL_Z(l_addr_from); + } + else + {//nativ ticker + if (!IS_ZERO_256(a_value_fee)) + SUBTRACT_256_256(l_value_need, a_value_fee, &l_value_need); + if(l_net_fee_used) + SUBTRACT_256_256(l_value_need, l_net_fee, &l_value_need); + if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + //in_ems + dap_chain_tx_in_ems_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_ticker); + if(l_tx_token){ + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token); + DAP_DEL_Z(l_tx_token); + } + else + { + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + if (!IS_ZERO_256(a_value_fee)){ + if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + //sign item + if (not_native) + { + if(a_key_from) + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) < 0) { + log_it(L_WARNING, "No private key for sign"); + return NULL; + } + } + else{ + if (a_certs) { + for(size_t i = 0; i < a_certs_count; i++) { + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_certs[i]->enc_key) < 0) { + log_it(L_WARNING, "No private key for certificate '%s'", a_certs[i]->name); + return NULL; + } + } + } + else + if(a_key_from) + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) < 0) { + log_it(L_WARNING, "No private key for sign"); + return NULL; + } } - - DAP_DEL_Z(l_tx_token); - DAP_DEL_Z(l_in); - DAP_DEL_Z(l_out); size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h index e5c374021178c3a2c321242f302b3a41bb7c1f80..4a960b320415fa8fd36b894b17748a5153842294 100644 --- a/modules/mempool/include/dap_chain_mempool.h +++ b/modules/mempool/include/dap_chain_mempool.h @@ -71,7 +71,7 @@ int dap_chain_mempool_tx_create_massive(dap_chain_t * a_chain, dap_enc_key_t *a_ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash, dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value, const char *a_ticker, - dap_chain_addr_t *a_addr_to, dap_cert_t **a_certs, size_t a_certs_count, const char *a_hash_out_type); + dap_enc_key_t *a_key_from, dap_chain_addr_t *a_addr_to, dap_cert_t **a_certs, size_t a_certs_count, const char *a_hash_out_type, uint256_t a_value_fee); dap_chain_datum_token_emission_t *dap_chain_mempool_emission_get(dap_chain_t *a_chain, const char *a_emission_hash_str); dap_chain_datum_token_emission_t *dap_chain_mempool_datum_emission_extract(dap_chain_t *a_chain, byte_t *a_data, size_t a_size); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index 22e6b51e5b939fdb1e6dd526cb80e4472126b399..61d28d0d451fa06b78eee9dd8948ea419f5a2fdc 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2733,7 +2733,7 @@ dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id) pthread_rwlock_rdlock(&s_net_ids_rwlock); HASH_FIND(hh,s_net_items_ids,&a_id,sizeof (a_id), l_net_item ); pthread_rwlock_unlock(&s_net_ids_rwlock); - return l_net_item ? l_net_item->chain_net : NULL; + return l_net_item ? l_net_item->chain_net : NULL; } /** diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index bd467d2052f1cfe3ab444a2076ffc12a70c62940..95d4be85a746e76546a2a536c84026eb8806d5cd 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -228,10 +228,8 @@ int dap_chain_node_cli_init(dap_config_t * g_config) ); dap_cli_server_cmd_add ("token_emit", com_token_emit, "Token emission", - "token_emit { sign | -token <mempool_token_ticker> -emission_value <value> " - "-addr <addr> [-chain_emission <chain_name>] " - "[-chain_base_tx <chain_name> | use flag '-no_base_tx' if you need create emission has no base transaction] } " - "-net <net_name> -certs <cert list>\n"); + "token_emit { sign | -token <mempool_token_ticker> -emission_value <value>" + "-addr <addr> [-chain_emission <chain_name>] -net <net_name> -certs <cert list>\n"); dap_cli_server_cmd_add ("mempool_list", com_mempool_list, "List mempool (entries or transaction) for (selected chain network or wallet)", @@ -260,7 +258,8 @@ int dap_chain_node_cli_init(dap_config_t * g_config) // Transaction commands dap_cli_server_cmd_add ("tx_create", com_tx_create, "Make transaction", - "tx_create -net <net_name> -chain <chain_name> {-from_wallet <wallet_name> -token <token_ticker> -value <value> -to_addr <addr> | -from_emission <emission_hash>} [-fee <addr> -value_fee <val>]\n" ); + "tx_create -net <net_name> -chain <chain_name> -value <value> -token <token_ticker> -to_addr <addr>" + "{-from_wallet <wallet_name> | -from_emission <emission_hash> {-certs <cert list> | -wallet_fee <wallet_name>}} -fee <value>\n"); dap_cli_server_cmd_add ("tx_create_json", com_tx_create_json, "Make transaction", "tx_create_json -net <net_name> -chain <chain_name> -json <json_file_path>\n" ); dap_cli_server_cmd_add ("tx_cond_create", com_tx_cond_create, "Make cond transaction", diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 41c0f5730f0fc4974ed01f46a2eeb3ee63c9b203..0e75623032b85b3befd0019c5407ca62cc56d949 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -2431,7 +2431,7 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a DAP_DATUM_TYPE_STR(l_datum->header.type_id, l_type) const char *l_token_ticker = NULL; if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) { // TODO rewrite it for support of multichannel & conditional transactions - dap_chain_tx_token_t *obj_token = (dap_chain_tx_token_t*)dap_chain_datum_tx_item_get((dap_chain_datum_tx_t*)l_datum->data, NULL, TX_ITEM_TYPE_TOKEN, NULL); + dap_chain_tx_in_ems_t *obj_token = (dap_chain_tx_in_ems_t*)dap_chain_datum_tx_item_get((dap_chain_datum_tx_t*)l_datum->data, NULL, TX_ITEM_TYPE_IN_EMS, NULL); if (obj_token) { l_token_ticker = obj_token->header.ticker; } else { @@ -3581,9 +3581,10 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) { int arg_index = 1; const char *str_tmp = NULL; + //const char *str_fee = NULL; char *l_str_reply_tmp = NULL; uint256_t l_emission_value = {}; - + //uint256_t l_fee_value = {}; const char * l_ticker = NULL; const char * l_addr_str = NULL; @@ -3620,9 +3621,6 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) if( ! l_net) { // Can't find such network return -43; } - - int no_base_tx = dap_cli_server_cmd_check_option(a_argv, arg_index, a_argc, "-no_base_tx"); - // Token emission dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-emission", &l_emission_hash_str); @@ -3646,9 +3644,9 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) "token_emit command requres at least one valid certificate to sign the basic transaction of emission"); return -5; } - const char *l_add_sign = NULL; dap_chain_addr_t *l_addr = NULL; + dap_chain_addr_t *l_addr_from = NULL; dap_cli_server_cmd_find_option_val(a_argv, arg_index, arg_index + 1, "sign", &l_add_sign); if (!l_add_sign) { //Create the emission // Emission value @@ -3707,25 +3705,6 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) } } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_base_tx", &l_chain_base_tx_str); - - if(l_chain_base_tx_str && no_base_tx < 0) { - if((l_chain_base_tx = dap_chain_net_get_chain_by_name(l_net, l_chain_base_tx_str)) == NULL) { // Can't find such chain - dap_cli_server_cmd_set_reply_text(a_str_reply, - "token_create requires parameter '-chain_base_tx' to be valid chain name in chain net %s or set default datum type in chain configuration file", l_net->pub.name); - DAP_DEL_Z(l_addr); - return -47; - } - } else if (no_base_tx < 0) { - if((l_chain_base_tx = dap_chain_net_get_default_chain_by_chain_type(l_net, CHAIN_TYPE_TX)) == NULL) { // Can't find such chain - dap_cli_server_cmd_set_reply_text(a_str_reply, - "token_emit requires parameter '-chain_base_tx' to be valid chain name in chain net %s or set default datum type in chain configuration file " - "but, if you need create emission has no base transaction, use flag '-no_base_tx'", l_net->pub.name); - - DAP_DEL_Z(l_addr); - return -47; - } - } if(!l_ticker) { dap_cli_server_cmd_set_reply_text(a_str_reply, "token_emit requires parameter '-token'"); DAP_DEL_Z(l_addr); @@ -3741,13 +3720,10 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) l_net->pub.name); return -50; } - } - // l_chain_emission = dap_chain_net_get_chain_by_chain_type(l_net, CHAIN_TYPE_EMISSION); + } // Create emission datum l_emission = dap_chain_datum_emission_create(l_emission_value, l_ticker, l_addr); } - // - //l_emission->data.type_auth.signs_count += l_certs_size; // Then add signs for(size_t i = 0; i < l_certs_size; i++) l_emission = dap_chain_datum_emission_add_sign(l_certs[i]->enc_key, l_emission); @@ -3774,21 +3750,8 @@ int com_token_emit(int a_argc, char **a_argv, char **a_str_reply) dap_global_db_del_sync(l_gdb_group_mempool_emission, l_emission_hash_str_remove); DAP_DEL_Z(l_gdb_group_mempool_emission); } + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_reply_tmp); - if(l_chain_base_tx) { - char *l_tx_hash_str = dap_chain_mempool_base_tx_create(l_chain_base_tx, &l_emission_hash, - l_chain_emission->id, l_emission_value, l_ticker, - l_addr, l_certs, l_certs_size, l_hash_out_type); - if (l_tx_hash_str) - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nDatum %s with 256bit TX is placed in datum pool", - l_str_reply_tmp, l_tx_hash_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't place TX datum in mempool, examine log files", - l_str_reply_tmp); - DAP_DEL_Z(l_tx_hash_str); - } else{ // if transaction was not specified when emission was added we need output only emission result - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_reply_tmp); - } DAP_DEL_Z(l_certs); DAP_DEL_Z(l_str_reply_tmp); DAP_DEL_Z(l_addr); @@ -4591,9 +4554,9 @@ int com_tx_create_json(int a_argc, char ** a_argv, char **a_str_reply) break; //case TX_ITEM_TYPE_PKEY: //break; - //case TX_ITEM_TYPE_TOKEN: + //case TX_ITEM_TYPE_IN_EMS: //break; - //case TX_ITEM_TYPE_TOKEN_EXT: + //case TX_ITEM_TYPE_IN_EMS_EXT: //break; } // Add item to transaction @@ -4687,6 +4650,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) const char *addr_base58_to = NULL; const char *str_tmp = NULL; const char * l_from_wallet_name = NULL; + const char * l_wallet_fee_name = NULL; const char * l_token_ticker = NULL; const char * l_net_name = NULL; const char * l_chain_name = NULL; @@ -4698,6 +4662,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) size_t l_certs_count = 0; dap_chain_hash_fast_t l_emission_hash = {}; size_t l_tx_num = 0; + dap_chain_wallet_t * l_wallet_fee = NULL; const char * l_hash_out_type = NULL; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type); @@ -4711,8 +4676,9 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) uint256_t l_value = {}; uint256_t l_value_fee = {}; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-from_wallet", &l_from_wallet_name); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-wallet_fee", &l_wallet_fee_name); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-from_emission", &l_emission_hash_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-emission_chain", &l_emission_chain_name); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain_emission", &l_emission_chain_name); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-to_addr", &addr_base58_to); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_ticker); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name); @@ -4739,7 +4705,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) return -5; } - if(!l_from_wallet_name && !l_emission_hash_str) { + if((!l_from_wallet_name && !l_emission_hash_str)||(l_from_wallet_name && l_emission_hash_str)) { dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires one of parameters '-from_wallet' or '-from_emission'"); return -1; } @@ -4764,6 +4730,8 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) return -7; } + const char *c_wallets_path = dap_chain_wallet_get_path(g_config); + dap_chain_t *l_emission_chain = NULL; if (l_emission_hash_str) { if (dap_chain_hash_fast_from_str(l_emission_hash_str, &l_emission_hash)) { @@ -4781,15 +4749,27 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) "to be a valid chain name or set default datum type in chain configuration file"); return -9; } - if(!l_certs_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-certs'"); - return -4; + + const char *l_native_ticker = l_net->pub.native_ticker; + bool not_native = dap_strcmp(l_token_ticker, l_native_ticker); + + l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path); + if((!l_wallet_fee)&&(not_native)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "wallet %s does not exist", l_wallet_fee_name); + return -9; } - dap_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_count); - if(!l_certs_count) { - dap_cli_server_cmd_set_reply_text(a_str_reply, - "tx_create requires at least one valid certificate to sign the basic transaction of emission"); - return -5; + + if(!l_wallet_fee){ + if(!l_certs_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-certs'"); + return -4; + } + dap_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_count); + if(!l_certs_count) { + dap_cli_server_cmd_set_reply_text(a_str_reply, + "tx_create requires at least one valid certificate to sign the basic transaction of emission"); + return -5; + } } } @@ -4816,22 +4796,22 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) int res = 0; if (l_emission_hash_str) { char *l_tx_hash_str = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_emission_chain->id, - l_value, l_token_ticker, l_addr_to, l_certs, - l_certs_count, l_hash_out_type); + l_value, l_token_ticker,dap_chain_wallet_get_key(l_wallet_fee, 0), l_addr_to, l_certs, + l_certs_count, l_hash_out_type,l_value_fee); if (l_tx_hash_str) { - dap_string_append_printf(l_string_ret, "transfer=Ok\ntx_hash=%s\n", l_tx_hash_str); + dap_string_append_printf(l_string_ret, "\nDatum %s with 256bit TX is placed in datum pool\n", l_tx_hash_str); DAP_DELETE(l_tx_hash_str); } else { - dap_string_append_printf(l_string_ret, "transfer=False\n"); + dap_string_append_printf(l_string_ret, "\nCan't place TX datum in mempool, examine log files\n"); res = -15; } dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_string_ret->str); dap_string_free(l_string_ret, true); DAP_DELETE(l_addr_to); - return res; + dap_chain_wallet_close(l_wallet_fee); + return res; } - const char *c_wallets_path = dap_chain_wallet_get_path(g_config); dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path); if(!l_wallet) { diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index a0bfb9e0ca4c1c7199d1a9ea5982cc5b7d299130..882a194c3e4f35860a106741b6ac8aa4403a9d85 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -151,7 +151,7 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain, // find Token items - present in emit transaction dap_list_t *l_list_tx_token; - l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL); + l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_EMS, NULL); // find OUT items bool l_type_256 = false; @@ -184,7 +184,7 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain, memcpy(l_tx_data->datum, l_datum, l_atom_size); // save token name if(l_list_tx_token) { - dap_chain_tx_token_t *tk = l_list_tx_token->data; + dap_chain_tx_in_ems_t *tk = l_list_tx_token->data; memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker)); } else { @@ -483,8 +483,8 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const } if (dap_hash_fast_is_blank(l_tx_prev_hash)) { l_base_tx = true; - dap_chain_tx_token_t *l_token = (dap_chain_tx_token_t *)dap_chain_datum_tx_item_get( - l_tx, NULL, TX_ITEM_TYPE_TOKEN, NULL); + dap_chain_tx_in_ems_t *l_token = (dap_chain_tx_in_ems_t *)dap_chain_datum_tx_item_get( + l_tx, NULL, TX_ITEM_TYPE_IN_EMS, NULL); if (l_token) l_src_token = l_token->header.ticker; break; @@ -1165,11 +1165,9 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply) dap_cli_server_cmd_set_reply_text(a_str_reply, l_str_out->str); dap_string_free(l_str_out, true); return 0; - } // command tx history else if(l_cmd == CMD_TX) { - enum { SUBCMD_TX_NONE, SUBCMD_TX_ALL, SUBCMD_TX_ADDR }; // find subcommand int l_subcmd = CMD_NONE; @@ -1211,7 +1209,6 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply) l_page = 1; } - // tx all if(l_subcmd == SUBCMD_TX_ALL) { dap_string_t *l_str_out = dap_string_new(NULL); diff --git a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c index 0a08646dd782c4030a723fb4dc0c0b00af1ee612..aa52f196476110435340a1781fb5395802466121 100644 --- a/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c +++ b/modules/service/stake_lock/dap_chain_net_srv_stake_lock.c @@ -1444,7 +1444,7 @@ static char *dap_chain_mempool_base_tx_for_stake_lock_create(dap_chain_t *a_chai dap_chain_hash_fast_t l_tx_prev_hash = { 0 }; // create items - dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_ticker); + dap_chain_tx_in_ems_t *l_tx_token = dap_chain_datum_tx_item_token_create(a_emission_chain_id, a_emission_hash, a_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(a_addr_to, a_emission_value); diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c index 78ee7b9038d72af5676846778136e6dfda6bd32d..440ed9d15358309d71fb4803db6f8519848f123d 100644 --- a/modules/wallet/dap_chain_wallet.c +++ b/modules/wallet/dap_chain_wallet.c @@ -355,12 +355,13 @@ static char s_wallets_path[MAX_PATH]; const char* dap_chain_wallet_get_path(dap_config_t * a_config) { char *l_cp; - + if (!a_config) + a_config = g_config; if ( s_wallets_path[0] ) /* Is the path to the wallet's store has been defined ? */ return s_wallets_path; /* Fine, just return existen value */ /* Retrieve Wallet's store path from config */ - if ( !(l_cp = (char *) dap_config_get_item_str(g_config, "resources", "wallets_path")) ) + if ( !(l_cp = (char *) dap_config_get_item_str(a_config, "resources", "wallets_path")) ) return log_it(L_WARNING, "No path to wallet's store has been defined"), s_wallets_path;