diff --git a/modules/common/include/dap_chain_datum_token.h b/modules/common/include/dap_chain_datum_token.h index dcc0c1ce25664e3bb8a18cf6ce2e34612fa03cb2..eac32ebaede40a9170b2f788ea84a16ba7666174 100644 --- a/modules/common/include/dap_chain_datum_token.h +++ b/modules/common/include/dap_chain_datum_token.h @@ -447,7 +447,7 @@ typedef struct dap_chain_datum_token_emission { union { uint64_t value64; // Deprecated uint256_t value; - }; + } DAP_ALIGN_PACKED; uint8_t nonce[DAP_CHAIN_DATUM_NONCE_SIZE]; } DAP_ALIGN_PACKED hdr; union { @@ -469,7 +469,7 @@ typedef struct dap_chain_datum_token_emission { uint16_t signs_count; } DAP_ALIGN_PACKED type_auth; byte_t free_space[128]; // For future changes - } data; + } DAP_ALIGN_PACKED data; byte_t tsd_n_signs[]; // TSD sections and signs if any } DAP_ALIGN_PACKED dap_chain_datum_token_emission_t; diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index 4d0e37e3182baf620964c234a7cf177c36c842ae..c0a021aa0ddacccce51a71e8ba0e196b922fb019 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -1014,19 +1014,25 @@ 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_enc_key_t *a_private_key, + dap_chain_id_t a_emission_chain_id, dap_enc_key_t *a_private_key, const char *a_hash_out_type, uint256_t a_value_fee) { + dap_return_val_if_fail(a_chain && a_emission_hash && a_private_key, NULL); uint256_t l_net_fee = {}; uint256_t l_total_fee = a_value_fee; - uint256_t l_value_need = a_emission_value; uint256_t l_value_transfer = {}; dap_chain_addr_t l_addr_to_fee = {}; dap_chain_addr_t l_addr_from_fee = {}; - dap_list_t *l_list_used_out; + + dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id); + dap_chain_datum_token_emission_t *l_emission = dap_ledger_token_emission_find(l_net->pub.ledger, a_emission_hash); + if (!l_emission) { + log_it(L_WARNING, "Specified emission not found"); + return NULL; + } + uint256_t l_emission_value = l_emission->hdr.value; 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 not_native = dap_strcmp(l_emission->hdr.ticker, l_native_ticker); bool l_net_fee_used = IS_ZERO_256(a_value_fee) ? false : dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_to_fee); if (l_net_fee_used) @@ -1035,7 +1041,7 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast 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); //in_ems - dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(a_emission_chain_id, a_emission_hash, a_ticker); + dap_chain_tx_in_ems_t *l_in_ems = dap_chain_datum_tx_item_in_ems_create(a_emission_chain_id, a_emission_hash, l_emission->hdr.ticker); if (l_in_ems) { dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*)l_in_ems); DAP_DELETE(l_in_ems); @@ -1052,7 +1058,7 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast } dap_ledger_t *l_ledger = dap_chain_net_by_id(a_chain->net_id)->pub.ledger; // list of transaction with 'out' items - l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, &l_addr_from_fee, l_total_fee, &l_value_transfer); if (!l_list_used_out) { log_it(L_WARNING,"Not enough funds to transfer"); @@ -1087,26 +1093,27 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast dap_chain_datum_tx_delete(l_tx); return NULL; } - if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)) { + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_emission->hdr.address, + l_emission_value, l_emission->hdr.ticker)) { dap_chain_datum_tx_delete(l_tx); return NULL; } } else { //native ticker if (!IS_ZERO_256(a_value_fee)) { - SUBTRACT_256_256(l_value_need, a_value_fee, &l_value_need); + SUBTRACT_256_256(l_emission_value, a_value_fee, &l_emission_value); if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){ dap_chain_datum_tx_delete(l_tx); return NULL; } } if (l_net_fee_used) { - SUBTRACT_256_256(l_value_need, l_net_fee, &l_value_need); + SUBTRACT_256_256(l_emission_value, l_net_fee, &l_emission_value); if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_to_fee, l_net_fee)) { dap_chain_datum_tx_delete(l_tx); return NULL; } } - if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)) { + if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_emission->hdr.address, l_emission_value)) { dap_chain_datum_tx_delete(l_tx); return NULL; } diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h index 7e436c23f2bf3ee2cc76ce734c86905ee793837a..6ac84d3277ce3241066713a3cd16d4f582bfbcb1 100644 --- a/modules/mempool/include/dap_chain_mempool.h +++ b/modules/mempool/include/dap_chain_mempool.h @@ -98,8 +98,7 @@ int dap_chain_mempool_tx_create_massive(dap_chain_t * a_chain, dap_enc_key_t *a_ * @return */ 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_enc_key_t *a_private_key, + dap_chain_id_t a_emission_chain_id, dap_enc_key_t *a_private_key, 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); diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index efa416417f1d39d91afb3f38eb56ad04d74c693a..3f39dd0ab5f63b4356bf5bc06320ac725ab36df4 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -2995,10 +2995,16 @@ dap_ledger_token_emission_item_t *s_emission_item_find(dap_ledger_t *a_ledger, * @param a_token_emission_hash * @return */ -dap_chain_datum_token_emission_t *dap_ledger_token_emission_find(dap_ledger_t *a_ledger, - const char *a_token_ticker, const dap_chain_hash_fast_t *a_token_emission_hash) +dap_chain_datum_token_emission_t *dap_ledger_token_emission_find(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash) { - dap_ledger_token_emission_item_t *l_emission_item = s_emission_item_find(a_ledger, a_token_ticker, a_token_emission_hash, NULL); + dap_ledger_token_emission_item_t *l_emission_item = NULL; + pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock); + for (dap_ledger_token_item_t *l_item = PVT(a_ledger)->tokens; l_item; l_item = l_item->hh.next) { + l_emission_item = s_emission_item_find(a_ledger, l_item->ticker, a_token_emission_hash, NULL); + if (l_emission_item) + break; + } + pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock); return l_emission_item ? l_emission_item->datum_token_emission : NULL; } diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index f11098992c6a11cb1c12697b7d58f3f1674dddf5..6367e274c69f990b2e948d0cc94630c47a73d995 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -5504,15 +5504,20 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) return -1; } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_name); + dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name); + if (l_net == NULL) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "not found net by name '%s'", l_net_name); + return -7; + } + uint256_t l_value = {}; uint256_t l_value_fee = {}; + dap_chain_addr_t *l_addr_to = NULL; 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, "-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); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-chain", &l_chain_name); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-tx_num", &l_tx_num_str); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cert", &l_cert_str); @@ -5520,13 +5525,6 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) if(l_tx_num_str) l_tx_num = strtoul(l_tx_num_str, NULL, 10); - if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &str_tmp)) - l_value = dap_chain_balance_scan(str_tmp); - if(IS_ZERO_256(l_value)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-value' to be valid uint256 value"); - return -4; - } - // Validator's fee if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &str_tmp)) l_value_fee = dap_chain_balance_scan(str_tmp); @@ -5540,33 +5538,12 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires one of parameters '-from_wallet' or '-from_emission'"); return -1; } - if(!addr_base58_to) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-to_addr'"); - return -2; - } if(!l_net_name) { dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-net'"); return -6; } - if(!l_token_ticker) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-token'"); - return -3; - } - dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name); - dap_ledger_t *l_ledger = l_net ? l_net->pub.ledger : NULL; - if(l_net == NULL || (l_ledger = dap_ledger_by_net_name(l_net_name)) == NULL) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "not found net by name '%s'", l_net_name); - return -7; - } - - if(!dap_ledger_token_ticker_check(l_ledger, l_token_ticker)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Ticker '%s' is not declared on network '%s'.", - l_token_ticker, l_net_name); - return -16; - } - const char *c_wallets_path = dap_chain_wallet_get_path(g_config); dap_chain_t *l_emission_chain = NULL; @@ -5606,6 +5583,33 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) "tx_create requires parameter '-cert' or '-wallet_fee' for create base tx for emission"); return -10; } + } else { + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_ticker); + if (!l_token_ticker) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-token'"); + return -3; + } + if (!dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_ticker)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Ticker '%s' is not declared on network '%s'.", + l_token_ticker, l_net_name); + return -16; + } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-to_addr", &addr_base58_to); + if (!addr_base58_to) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-to_addr'"); + return -2; + } + l_addr_to = dap_chain_addr_from_str(addr_base58_to); + if(!l_addr_to) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "destination address is invalid"); + return -11; + } + if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-value", &str_tmp)) + l_value = dap_chain_balance_scan(str_tmp); + if (IS_ZERO_256(l_value)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-value' to be valid uint256 value"); + return -4; + } } dap_chain_t *l_chain = NULL; @@ -5621,24 +5625,17 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) return -8; } - dap_chain_addr_t *l_addr_to = dap_chain_addr_from_str(addr_base58_to); - if(!l_addr_to) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "destination address is invalid"); - return -11; - } - dap_string_t *l_string_ret = dap_string_new(NULL); int l_ret = 0; if (l_emission_hash_str) { char *l_tx_hash_str = NULL; if (!l_priv_key) { dap_string_append_printf(l_string_ret, "No private key defined for creating the underlying " - "transaction no '-wallet_fee' or ' -cert' parameter specified."); + "transaction no '-wallet_fee' or '-cert' parameter specified."); l_ret = -10; } 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_priv_key, - l_hash_out_type, l_value_fee); + l_priv_key, l_hash_out_type, l_value_fee); if (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); @@ -5653,7 +5650,6 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) dap_chain_wallet_close(l_wallet_fee); dap_enc_key_delete(l_priv_key); } - DAP_DEL_Z(l_cert); return l_ret; } diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 89178a2fb07433b1d3a282dbcedbf2a0d069d12d..76f7603378451d6009b73e537fc25c7fbdd2b83a 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -364,7 +364,7 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const case TX_ITEM_TYPE_OUT_COND: l_value = ((dap_chain_tx_out_cond_t *)it->data)->header.value; if (((dap_chain_tx_out_cond_t *)it->data)->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { - SUM_256_256(l_fee_sum, ((dap_chain_tx_out_cond_t *)it->data)->header.value, &l_fee_sum); + l_fee_sum = ((dap_chain_tx_out_cond_t *)it->data)->header.value; l_dst_token = l_native_ticker; } else l_dst_token = l_src_token; @@ -423,7 +423,9 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const } dap_list_free(l_list_out_items); // fee for base TX in native token - if (l_header_printed && l_base_tx && !dap_strcmp(l_native_ticker, l_src_token)) { + if (l_header_printed && + (l_base_tx || !dap_strcmp(l_native_ticker, l_noaddr_token)) && + !dap_strcmp(l_native_ticker, l_src_token)) { char *l_fee_value_str = dap_chain_balance_print(l_fee_sum); char *l_fee_coins_str = dap_chain_balance_to_coins(l_fee_sum); dap_string_append_printf(l_str_out, "\tpay %s (%s) fee\n", @@ -631,7 +633,7 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger } l_sht = DAP_NEW_Z(dap_chain_tx_hash_processed_ht_t); if (!l_sht) { - log_it(L_CRITICAL, "Memory allocation error"); + log_it(L_CRITICAL, "Memory allocation error"); return NULL; } l_sht->hash = l_tx_hash; diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h index ddf614be57d500f503dc8b8c34bc6882814b3bc8..7fa2f5d3e943888754ea8a732c70a9f90e688cc8 100644 --- a/modules/net/include/dap_chain_ledger.h +++ b/modules/net/include/dap_chain_ledger.h @@ -247,8 +247,7 @@ int dap_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_ /* Add stake-lock item */ int dap_ledger_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_tx_hash); -dap_chain_datum_token_emission_t *dap_ledger_token_emission_find(dap_ledger_t *a_ledger, - const char *a_token_ticker, const dap_chain_hash_fast_t *a_token_emission_hash); +dap_chain_datum_token_emission_t *dap_ledger_token_emission_find(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_token_emission_hash); const char* dap_ledger_tx_get_token_ticker_by_hash(dap_ledger_t *a_ledger,dap_chain_hash_fast_t *a_tx_hash); diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index d6a18ca9e5768ff4ebe1b65ad6c2cee76968217f..c35e86862e4d35e67ee16133c6a5b70600f04b05 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -399,12 +399,14 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); dap_ledger_t *l_ledger = a_price->net->pub.ledger; - dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); if (l_single_channel) SUM_256_256(l_value_need, l_total_fee, &l_value_need); else { l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - l_seller_addr, l_total_fee, &l_fee_transfer); + &l_seller_addr, l_total_fee, &l_fee_transfer); if (!l_list_fee_out) { log_it(L_WARNING, "Not enough funds to pay fee"); return NULL; @@ -412,9 +414,8 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan } // list of transaction with 'out' items to sell dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_sell, - l_seller_addr, l_value_need, &l_value_transfer); + &l_seller_addr, l_value_need, &l_value_transfer); if(!l_list_used_out) { - DAP_DELETE(l_seller_addr); log_it(L_WARNING, "Nothing to change (not enough funds)"); return NULL; } @@ -427,7 +428,6 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer) != 0) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't compose the transaction input"); return NULL; } @@ -436,7 +436,6 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); if (!EQUAL_256(l_value_fee_items, l_fee_transfer) != 0) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't compose the transaction input"); return NULL; } @@ -448,10 +447,9 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange(l_uid, a_price->net->pub.id, a_price->datoshi_sell, a_price->net->pub.id, a_price->token_buy, a_price->rate, - l_seller_addr, NULL, 0); + &l_seller_addr, NULL, 0); if (!l_tx_out) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Can't compose the transaction conditional output"); return NULL; } @@ -459,9 +457,11 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan DAP_DELETE(l_tx_out); // Network fee if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_net_fee, l_net_fee) != 1) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_net_fee, l_net_fee) != 1) || + (!l_single_channel && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_net_fee, l_net_fee, l_native_ticker) != 1)) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Cant add network fee output"); return NULL; } @@ -470,7 +470,6 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan if (!IS_ZERO_256(a_price->fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) != 1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Cant add validator's fee output"); return NULL; } @@ -479,28 +478,28 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_request(dap_chain_net_srv_xchan uint256_t l_value_back = {}; SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_value_back) != 1) { + if ((l_single_channel && + dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_value_back) != 1) || + (!l_single_channel && + 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, "Cant add coin back output"); return NULL; } } // Fee coinback if (!l_single_channel) { - SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); - if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_value_back, - a_price->net->pub.native_ticker) != 1) { + uint256_t l_fee_coinback = {}; + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_coinback); + if (!IS_ZERO_256(l_fee_coinback)) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_coinback, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Cant add fee back output"); return NULL; } } } } - DAP_DELETE(l_seller_addr); dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); // add 'sign' item @@ -523,10 +522,9 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha } const char *l_native_ticker = a_price->net->pub.native_ticker; const char *l_service_ticker = NULL; - bool l_pay_with_native = !dap_strcmp(a_price->token_buy, l_native_ticker); // find the transactions from which to take away coins uint256_t l_value_transfer, // how many coins to transfer - l_value_need = a_datoshi_buy, //a_price->datoshi_buy, + l_value_need = a_datoshi_buy, l_net_fee, l_service_fee, l_total_fee = a_datoshi_fee, @@ -555,55 +553,48 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha break; } } + dap_ledger_t *l_ledger = a_price->net->pub.ledger; - dap_chain_addr_t *l_buyer_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); - if (l_pay_with_native) - SUM_256_256(l_value_need, l_total_fee, &l_value_need); - else { + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); + dap_chain_addr_t l_buyer_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); + + // list of transaction with 'out' items to sell + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_buy, + &l_buyer_addr, l_value_need, &l_value_transfer); + if (!l_list_used_out) { + log_it(L_WARNING, "Nothing to change (not enough funds)"); + return NULL; + } + bool l_pay_with_native = !dap_strcmp(a_price->token_sell, l_native_ticker); + if (!l_pay_with_native) { l_list_fee_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - l_buyer_addr, l_total_fee, &l_fee_transfer); + &l_buyer_addr, l_total_fee, &l_fee_transfer); if (!l_list_fee_out) { + dap_list_free_full(l_list_used_out, NULL); log_it(L_WARNING, "Not enough funds to pay fee"); return NULL; } } - // list of transaction with 'out' items to sell - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_price->token_buy, - l_buyer_addr, l_value_need, &l_value_transfer); - if(!l_list_used_out) { - DAP_DELETE(l_buyer_addr); - log_it(L_WARNING, "Nothing to change (not enough funds)"); - return NULL; - } - // create empty transaction dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); - // create and add reciept - dap_chain_datum_tx_receipt_t *l_receipt = s_xchange_receipt_create(a_price, a_datoshi_buy); - if( l_receipt == NULL){ - DAP_DELETE(l_buyer_addr); - log_it(L_ERROR, "Can't compose the receipt"); - return NULL; - } - dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt); - DAP_DELETE(l_receipt); // add 'in' items to sell uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); dap_list_free_full(l_list_used_out, NULL); if (!EQUAL_256(l_value_to_items, l_value_transfer)) { + dap_list_free_full(l_list_fee_out, NULL); dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't compose the transaction input"); return NULL; } if (!l_pay_with_native) { // add 'in' items to fee uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_out); + dap_list_free_full(l_list_fee_out, NULL); if (!EQUAL_256(l_value_fee_items, l_fee_transfer)) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't compose the transaction input"); return NULL; } @@ -611,6 +602,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha // add 'in' item to buy from conditional transaction dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_price->tx_hash); if (!l_cond_tx) { + dap_chain_datum_tx_delete(l_tx); log_it(L_WARNING, "Requested conditional transaction not found"); return NULL; } @@ -618,15 +610,21 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_prev_cond_idx); if (!l_tx_out_cond) { + dap_chain_datum_tx_delete(l_tx); log_it(L_WARNING, "Requested transaction has no conditional output"); return NULL; } if (dap_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) { + dap_chain_datum_tx_delete(l_tx); log_it(L_WARNING, "Requested conditional transaction is already used out"); return NULL; } const dap_chain_addr_t *l_seller_addr = &l_tx_out_cond->subtype.srv_xchange.seller_addr; - dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); + if (dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0)) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Can't add conditional input"); + return NULL; + } // add 'out' items // transfer selling coins @@ -638,35 +636,42 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha if (compare256(l_tx_out_cond->header.value, l_datoshi_sell) < 0) { l_datoshi_sell = l_tx_out_cond->header.value; MULT_256_COIN(l_datoshi_sell, a_price->rate, &l_datoshi_buy); + uint256_t l_exceed = {}; // Correct requested transfer value + SUBTRACT_256_256(a_datoshi_buy, l_datoshi_buy, &l_exceed); + SUBTRACT_256_256(l_value_need, l_exceed, &l_value_need); } else l_datoshi_buy = a_datoshi_buy; - debug_if(s_debug_more, L_NOTICE, "l_datoshi_sell = %s", dap_chain_balance_to_coins(l_datoshi_sell)); - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_datoshi_sell, a_price->token_sell) == -1) { + debug_if(s_debug_more, L_NOTICE, "l_value_sell = %s %s", dap_chain_balance_to_coins(l_datoshi_sell), a_price->token_sell); + uint256_t l_value_sell = l_datoshi_sell; + if (l_pay_with_native) { + if (compare256(l_datoshi_sell, l_total_fee) <= 0) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Fee is greater or equal than transfer value"); + return NULL; + } + SUBTRACT_256_256(l_datoshi_sell, l_total_fee, &l_value_sell); + } + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_sell, a_price->token_sell) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add selling coins output"); return NULL; } - }else{ - DAP_DELETE(l_buyer_addr); + } else { log_it(L_ERROR, "Can't add selling coins output because price rate is 0"); return NULL; } // transfer unselling coins (partial exchange) - debug_if(s_debug_more, L_NOTICE, "l_datoshi_cond = %s", dap_chain_balance_to_coins(l_tx_out_cond->header.value)); + debug_if(s_debug_more, L_NOTICE, "l_value_cond = %s", dap_chain_balance_to_coins(l_tx_out_cond->header.value)); if (compare256(l_tx_out_cond->header.value, l_datoshi_sell) == 1) { SUBTRACT_256_256(l_tx_out_cond->header.value, l_datoshi_sell, &l_value_back); - debug_if(s_debug_more, L_NOTICE, "l_value_back = %s", dap_chain_balance_to_coins(l_value_back)); - uint256_t l_datoshi_buy_again; - MULT_256_COIN(l_value_back, a_price->rate, &l_datoshi_buy_again); - debug_if(s_debug_more, L_NOTICE, "l_datoshi_buy_again = %s", dap_chain_balance_to_coins(l_datoshi_buy_again)); + debug_if(s_debug_more, L_NOTICE, "l_value_unselled = %s", dap_chain_balance_to_coins(l_value_back)); dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_xchange( c_dap_chain_net_srv_xchange_uid, a_price->net->pub.id, l_value_back, a_price->net->pub.id, a_price->token_buy, a_price->rate, l_seller_addr, NULL, 0); if (!l_tx_out) { dap_chain_datum_tx_delete(l_tx); - log_it(L_WARNING, "Can't add selling coins back conditioned output (cond cashback)"); + log_it(L_ERROR, "Can't add selling coins back conditioned output (cond cashback)"); return NULL; } dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); @@ -677,16 +682,14 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha // transfer buying coins if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_datoshi_buy, a_price->token_buy) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add buying coins output"); return NULL; } - debug_if(s_debug_more, L_NOTICE, "l_datoshi_buy = %s", dap_chain_balance_to_coins(l_datoshi_buy)); + debug_if(s_debug_more, L_NOTICE, "l_value_buy = %s %s", dap_chain_balance_to_coins(l_datoshi_buy), a_price->token_buy); // transfer validator's fee if (!IS_ZERO_256(a_datoshi_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_datoshi_fee) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add validator fee output"); return NULL; } @@ -696,7 +699,6 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha if (l_net_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_net_fee_addr, l_net_fee, l_native_ticker) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add net fee output"); return NULL; } @@ -706,18 +708,16 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha if (l_service_fee_used) { if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_service_fee_addr, l_service_fee, l_service_ticker) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add net fee output"); return NULL; } - debug_if(s_debug_more, L_NOTICE, "l_service_fee = %s", dap_chain_balance_to_coins(l_net_fee)); + debug_if(s_debug_more, L_NOTICE, "l_service_fee = %s %s", dap_chain_balance_to_coins(l_net_fee), l_service_ticker); } // coin back SUBTRACT_256_256(l_value_transfer, l_value_need, &l_value_back); if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, a_price->token_buy) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, a_price->token_buy) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add buying coins back output"); return NULL; } @@ -728,28 +728,26 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha if (!l_pay_with_native) { SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_value_back); if (!IS_ZERO_256(l_value_back)) { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, l_buyer_addr, l_value_back, l_native_ticker) == -1) { + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_buyer_addr, l_value_back, l_native_ticker) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_buyer_addr); log_it(L_ERROR, "Can't add buying coins back output"); return NULL; } } debug_if(s_debug_more, L_NOTICE, "l_fee_transfer = %s", dap_chain_balance_to_coins(l_fee_transfer)); - debug_if(s_debug_more, L_NOTICE, "l_value_back = %s", dap_chain_balance_to_coins(l_value_back)); + debug_if(s_debug_more, L_NOTICE, "l_fee_back = %s", dap_chain_balance_to_coins(l_value_back)); } - // add 'sign' items - dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); - if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { + // add 'sign' items + dap_enc_key_t *l_buyer_key = dap_chain_wallet_get_key(a_wallet, 0); + if (dap_chain_datum_tx_add_sign_item(&l_tx, l_buyer_key) != 1) { dap_chain_datum_tx_delete(l_tx); - dap_enc_key_delete(l_seller_key); + dap_enc_key_delete(l_buyer_key); log_it( L_ERROR, "Can't add sign output"); - DAP_DELETE(l_buyer_addr); return NULL; } - dap_enc_key_delete(l_seller_key); - DAP_DELETE(l_buyer_addr); + dap_enc_key_delete(l_buyer_key); + return l_tx; } @@ -787,133 +785,121 @@ static char* s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, return l_ret; } const char *l_native_ticker = a_price->net->pub.native_ticker; - // create empty transaction - dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); dap_ledger_t *l_ledger = dap_ledger_by_net_name(a_price->net->pub.name); - dap_chain_addr_t *l_seller_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); + dap_chain_addr_t *l_wallet_addr = dap_chain_wallet_get_addr(a_wallet, a_price->net->pub.id); + dap_chain_addr_t l_seller_addr = *l_wallet_addr; + DAP_DELETE(l_wallet_addr); - // create and add reciept - dap_chain_datum_tx_receipt_t *l_receipt = s_xchange_receipt_create(a_price, uint256_0); - if (!l_receipt) { - log_it(L_WARNING, "Can't create receipt"); - dap_chain_datum_tx_delete(l_tx); - return l_ret; - } - dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt); - DAP_DELETE(l_receipt); - - // add 'in' item to buy from conditional transaction dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_price->tx_hash); if (!l_cond_tx) { log_it(L_WARNING, "Requested conditional transaction not found"); - dap_chain_datum_tx_delete(l_tx); return l_ret; } const char *l_tx_ticker = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &a_price->tx_hash); - if(!l_tx_ticker){ + if (!l_tx_ticker) { log_it(L_WARNING, "Can't get ticker from tx"); - dap_chain_datum_tx_delete(l_tx); return l_ret; } bool l_single_channel = !dap_strcmp(l_tx_ticker, l_native_ticker); + + // check 'out_cond' item int l_prev_cond_idx = 0; dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, &l_prev_cond_idx); - if (!l_tx_out_cond || dap_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) { + if (!l_tx_out_cond) { + log_it(L_WARNING, "Requested conditional transaction has no XCHANGE output"); + return l_ret; + } + if (dap_ledger_tx_hash_is_used_out_item(l_ledger, &a_price->tx_hash, l_prev_cond_idx, NULL)) { log_it(L_WARNING, "Requested conditional transaction is already used out"); - dap_chain_datum_tx_delete(l_tx); return l_ret; } - dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); - - // check 'out_cond' item - dap_chain_addr_t *l_cond_addr = &l_tx_out_cond->subtype.srv_xchange.seller_addr; - if (!dap_hash_fast_compare(&l_seller_addr->data.hash_fast, &l_cond_addr->data.hash_fast)) { + if (!dap_chain_addr_compare(&l_seller_addr, &l_tx_out_cond->subtype.srv_xchange.seller_addr)) { log_it(L_WARNING, "Only owner can invalidate exchange transaction"); - dap_chain_datum_tx_delete(l_tx); return l_ret; } - uint256_t l_net_fee = {}, l_transfer_fee; + + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + // add 'in' item to buy from conditional transaction + dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_price->tx_hash, l_prev_cond_idx, 0); + uint256_t l_net_fee = {}; dap_chain_addr_t l_addr_fee = {}; bool l_net_fee_used = dap_chain_net_tx_get_fee(a_price->net->pub.id, &l_net_fee, &l_addr_fee); - uint256_t l_total_fee = {}; - SUM_256_256(a_price->fee, l_net_fee, &l_total_fee); - // list of transaction with 'out' items to get net fee - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - l_seller_addr, l_total_fee, &l_transfer_fee); - if(!l_list_used_out) { - dap_chain_datum_tx_delete(l_tx); - log_it(L_WARNING, "Nothing to pay for network fee (not enough funds)"); - return l_ret; - } - // add 'in' items to net fee - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - dap_list_free_full(l_list_used_out, NULL); - if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { - dap_chain_datum_tx_delete(l_tx); - log_it(L_ERROR, "Can't compose the transaction input"); - return l_ret; - } - - // return coins to owner - if (dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_tx_out_cond->header.value) == -1) { - dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); - log_it(L_ERROR, "Cant add returning coins output"); - return l_ret; - } + uint256_t l_total_fee = a_price->fee; + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); - // Network fee - if (l_net_fee_used) { - if (l_single_channel) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) { - dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); - log_it(L_ERROR, "Cant add network fee output"); - return l_ret; - } - } else { - if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) != 1) { - dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); - log_it(L_ERROR, "Cant add network fee output"); - return l_ret; - } + if (!l_single_channel) { + uint256_t l_transfer_fee = {}, l_fee_back = {}; + // list of transaction with 'out' items to get net fee + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, + &l_seller_addr, l_total_fee, &l_transfer_fee); + if (!l_list_used_out) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Nothing to pay for network fee (not enough funds)"); + return l_ret; + } + // add 'in' items to net fee + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + dap_list_free_full(l_list_used_out, NULL); + if (!EQUAL_256(l_value_to_items, l_transfer_fee)) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Can't compose the transaction input"); + return l_ret; + } + // return coins to owner + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_tx_out_cond->header.value, l_tx_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add returning coins output"); + return l_ret; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add network fee output"); + return l_ret; + } + // put fee coinback + SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); + if (!IS_ZERO_256(l_fee_back) && + dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_seller_addr, l_fee_back, l_native_ticker) == -1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add fee cachback output"); + return l_ret; + } + } else { + uint256_t l_coin_back = {}; + if (compare256(l_total_fee, l_tx_out_cond->header.value) >= 0) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Total fee is greater or equal than order liquidity"); + return l_ret; + } + SUBTRACT_256_256(l_tx_out_cond->header.value, l_total_fee, &l_coin_back); + // return coins to owner + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_seller_addr, l_coin_back) == -1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add returning coins output"); + return l_ret; + } + // Network fee + if (l_net_fee_used && + dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add network fee output"); + return l_ret; } } // Validator's fee if (!IS_ZERO_256(a_price->fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx, a_price->fee) == -1) { dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); log_it(L_ERROR, "Cant add validator's fee output"); return l_ret; } } - - // put the net fee cashback - uint256_t l_fee_back = {}; - SUBTRACT_256_256(l_transfer_fee, l_total_fee, &l_fee_back); - if (!IS_ZERO_256(l_fee_back)){ - if (l_single_channel) { - if ((dap_chain_datum_tx_add_out_item(&l_tx, l_seller_addr, l_fee_back) == -1)){ - dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); - log_it(L_ERROR, "Cant add fee cachback output"); - return l_ret; - } - } else{ - if ((dap_chain_datum_tx_add_out_ext_item(&l_tx, l_seller_addr, l_fee_back, l_native_ticker) == -1)){ - dap_chain_datum_tx_delete(l_tx); - DAP_DELETE(l_seller_addr); - log_it(L_ERROR, "Cant add fee cachback output"); - return l_ret; - } - } - } - DAP_DELETE(l_seller_addr); - // add 'sign' items dap_enc_key_t *l_seller_key = dap_chain_wallet_get_key(a_wallet, 0); if(dap_chain_datum_tx_add_sign_item(&l_tx, l_seller_key) != 1) { @@ -928,32 +914,6 @@ static char* s_xchange_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, return l_ret; } -/** - * @brief s_xchange_order_create - * @param a_price - * @param a_tx - * @return - */ -char *s_xchange_order_create(dap_chain_net_srv_xchange_price_t *a_price, dap_chain_datum_tx_t *a_tx) -{ - dap_chain_hash_fast_t l_tx_hash = {}; - dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash); - a_price->tx_hash = l_tx_hash; - dap_chain_node_addr_t *l_node_addr = &g_node_addr; - dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED}; - dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_XCHANGE_ID }; - uint256_t l_datoshi_buy = uint256_0; - MULT_256_COIN(a_price->datoshi_sell, a_price->rate, &l_datoshi_buy); - dap_srv_xchange_order_ext_t l_ext={0}; - l_ext.datoshi_buy = l_datoshi_buy; - strncpy(l_ext.token_buy, a_price->token_buy, DAP_CHAIN_TICKER_SIZE_MAX); - uint32_t l_ext_size = sizeof(dap_srv_xchange_order_ext_t); - char *l_order_hash_str = dap_chain_net_srv_order_create(a_price->net, SERV_DIR_SELL, l_uid, *l_node_addr, - l_tx_hash, &a_price->datoshi_sell, l_unit, a_price->token_sell, 0, - (uint8_t *)&l_ext, l_ext_size, 0, NULL, 0, a_price->wallet_key); - return l_order_hash_str; -} - /** * @brief s_xchange_price_from_order * @param a_net @@ -1054,7 +1014,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_sell", &l_token_sell_str); if (!l_token_sell_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -token_sell"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -token_sell"); return -5; } if (!dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_sell_str)) { @@ -1063,7 +1023,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-token_buy", &l_token_buy_str); if (!l_token_buy_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -token_buy"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -token_buy"); return -5; } if (!dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_buy_str)) { @@ -1073,7 +1033,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c const char *l_val_sell_str = NULL, *l_val_rate_str = NULL; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_val_sell_str); if (!l_val_sell_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -value"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -value"); return -8; } uint256_t l_datoshi_sell = dap_chain_balance_scan(l_val_sell_str); @@ -1083,7 +1043,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-rate", &l_val_rate_str); if (!l_val_rate_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -rate"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -rate"); return -8; } uint256_t l_rate = dap_chain_coins_to_balance(l_val_rate_str); @@ -1094,7 +1054,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c const char *l_fee_str = NULL; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); if (!l_fee_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -fee"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -fee"); return -20; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); @@ -1104,7 +1064,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); if (!l_wallet_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price create' requires parameter -w"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -w"); return -10; } dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); @@ -1260,7 +1220,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c const char * l_fee_str = NULL; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'price %s' requires parameter -net", + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order %s' requires parameter -net", l_cmd_num == CMD_REMOVE ? "remove" : "update"); return -2; } @@ -1326,7 +1286,7 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, c DAP_DELETE(l_tx_hash_str); } } else - dap_string_append_printf(l_str_reply, "Price successfully removed. Created inactivate tx with hash %s", l_ret); + dap_string_append_printf(l_str_reply, "Order successfully removed. Created inactivate tx with hash %s", l_ret); DAP_DELETE(l_price); DAP_DEL_Z(l_ret); *a_str_reply = dap_string_free(l_str_reply, false); diff --git a/modules/type/none/dap_chain_cs_none.c b/modules/type/none/dap_chain_cs_none.c index 27fc8913f7d8f37939b3c2886bf1221c4adc1782..acdfb121599fc21167216490ccc67b8cde46d4ae 100644 --- a/modules/type/none/dap_chain_cs_none.c +++ b/modules/type/none/dap_chain_cs_none.c @@ -89,6 +89,14 @@ static size_t s_nonconsensus_callback_datums_pool_proc(dap_chain_t * a_chain, da size_t a_datums_size); static void s_nonconsensus_ledger_load(dap_chain_t *a_chain); +// Datum ops +static dap_chain_datum_iter_t *s_nonconsensus_callback_datum_iter_create(dap_chain_t *a_chain); +static void s_nonconsensus_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter); +static dap_chain_datum_t *s_nonconsensus_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter); +static dap_chain_datum_t *s_nonconsensus_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter); +static dap_chain_datum_t *s_nonconsensus_callback_datum_find_by_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash, + dap_chain_hash_fast_t *a_atom_hash, int *a_ret_code); + static int s_cs_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg); static void s_nonconsensus_delete(dap_chain_t *a_chain); @@ -184,19 +192,26 @@ static int s_cs_callback_new(dap_chain_t *a_chain, dap_config_t UNUSED_ARG *a_ch a_chain->callback_atom_iter_create = s_nonconsensus_callback_atom_iter_create; a_chain->callback_atom_iter_create_from = s_nonconsensus_callback_atom_iter_create_from; a_chain->callback_atom_iter_delete = s_nonconsensus_callback_atom_iter_delete; - - a_chain->callback_atom_find_by_hash = s_nonconsensus_callback_atom_iter_find_by_hash; - a_chain->callback_add_datums = s_nonconsensus_callback_datums_pool_proc; - // Linear pass through a_chain->callback_atom_iter_get_first = s_nonconsensus_callback_atom_iter_get_first; // Get the fisrt element from chain a_chain->callback_atom_iter_get_next = s_nonconsensus_callback_atom_iter_get_next; // Get the next element from chain from the current one + a_chain->callback_atom_find_by_hash = s_nonconsensus_callback_atom_iter_find_by_hash; a_chain->callback_atom_iter_get_links = s_nonconsensus_callback_atom_iter_get_links; // Get the next element from chain from the current one a_chain->callback_atom_iter_get_lasts = s_nonconsensus_callback_atom_iter_get_lasts; a_chain->callback_atom_get_datums = s_nonconsensus_callback_atom_get_datum; a_chain->callback_atom_get_timestamp = s_nonconsensus_callback_atom_get_timestamp; + // Datum callbacks + a_chain->callback_datum_iter_create = s_nonconsensus_callback_datum_iter_create; + a_chain->callback_datum_iter_delete = s_nonconsensus_callback_datum_iter_delete; + // Linear pass through + a_chain->callback_datum_iter_get_first = s_nonconsensus_callback_datum_iter_get_first; // Get the fisrt datum from chain + a_chain->callback_datum_iter_get_next = s_nonconsensus_callback_datum_iter_get_next; // Get the next datum from chain from the current one + + a_chain->callback_datum_find_by_hash = s_nonconsensus_callback_datum_find_by_hash; + a_chain->callback_add_datums = s_nonconsensus_callback_datums_pool_proc; + a_chain->callback_load_from_gdb = s_nonconsensus_ledger_load; return 0; @@ -511,7 +526,6 @@ static dap_chain_atom_ptr_t s_nonconsensus_callback_atom_iter_get_first(dap_chai size_t l_datum_size = 0; l_datum = (dap_chain_datum_t*)dap_global_db_get_sync(PVT(DAP_NONCONSENSUS(a_atom_iter->chain))->group_datums, l_item->key, &l_datum_size, NULL, NULL); - DAP_DEL_Z(a_atom_iter->cur); a_atom_iter->cur = l_datum; a_atom_iter->cur_size = l_datum_size; a_atom_iter->cur_hash = DAP_NEW_Z(dap_hash_fast_t); @@ -623,3 +637,94 @@ static dap_chain_datum_t **s_nonconsensus_callback_atom_get_datum(dap_chain_atom }else return NULL; } + +static dap_chain_datum_iter_t *s_nonconsensus_callback_datum_iter_create(dap_chain_t *a_chain) +{ + dap_chain_datum_iter_t *l_ret = DAP_NEW_Z(dap_chain_datum_iter_t); + if (!l_ret) { + log_it(L_CRITICAL, "Memory allocation error"); + return NULL; + } + l_ret->chain = a_chain; + return l_ret; +} + +static void s_nonconsensus_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter) +{ + if (a_datum_iter->cur_item) { + DAP_DEL_Z(a_datum_iter->cur); + DAP_DEL_Z(a_datum_iter->cur_hash); + } + DAP_DELETE(a_datum_iter); +} + +static dap_chain_datum_t *s_nonconsensus_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter) +{ + if (!a_datum_iter) + return NULL; + if (a_datum_iter->cur_item) { /* Iterator creates copies, free them at delete routine! */ + DAP_DEL_Z(a_datum_iter->cur); + DAP_DEL_Z(a_datum_iter->cur_hash); + } + dap_chain_datum_t * l_datum = NULL; + dap_nonconsensus_datum_hash_item_t *l_item = PVT(DAP_NONCONSENSUS(a_datum_iter->chain))->hash_items; + a_datum_iter->cur_item = l_item; + if (a_datum_iter->cur_item) { + size_t l_datum_size = 0; + l_datum = (dap_chain_datum_t*)dap_global_db_get_sync(PVT(DAP_NONCONSENSUS(a_datum_iter->chain))->group_datums, + l_item->key, &l_datum_size, NULL, NULL); + a_datum_iter->cur = l_datum; + a_datum_iter->cur_size = l_datum_size; + a_datum_iter->cur_hash = DAP_NEW_Z(dap_hash_fast_t); + dap_chain_hash_fast_from_str(l_item->key, a_datum_iter->cur_hash); + a_datum_iter->cur_atom_hash = a_datum_iter->cur_hash; + } else + a_datum_iter->cur_size = 0; + return l_datum; +} + +static dap_chain_datum_t *s_nonconsensus_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter) +{ + if (!a_datum_iter) + return NULL; + dap_chain_datum_t *l_datum = NULL; + dap_nonconsensus_datum_hash_item_t *l_item = (dap_nonconsensus_datum_hash_item_t*)a_datum_iter->cur_item; + if (l_item) + l_item = l_item->next; + a_datum_iter->cur_item = l_item; + if (a_datum_iter->cur_item) { + size_t l_datum_size = 0; + l_datum = (dap_chain_datum_t*)dap_global_db_get_sync(PVT(DAP_NONCONSENSUS(a_datum_iter->chain))->group_datums, + l_item->key, &l_datum_size, NULL, NULL); + DAP_DEL_Z(a_datum_iter->cur); + a_datum_iter->cur = l_datum; + a_datum_iter->cur_size = l_datum_size; + a_datum_iter->cur_hash = DAP_NEW_Z(dap_hash_fast_t); + dap_chain_hash_fast_from_str(l_item->key, a_datum_iter->cur_hash); + a_datum_iter->cur_atom_hash = a_datum_iter->cur_hash; + } else { + DAP_DEL_Z(a_datum_iter->cur_hash); + DAP_DEL_Z(a_datum_iter->cur); + a_datum_iter->cur_size = 0; + } + return l_datum; +} + +static dap_chain_datum_t *s_nonconsensus_callback_datum_find_by_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash, + dap_chain_hash_fast_t *a_atom_hash, int *a_ret_code) +{ + dap_nonconsensus_datum_hash_item_t *l_item; + DL_FOREACH(PVT(DAP_NONCONSENSUS(a_chain))->hash_items, l_item) { + if (dap_hash_fast_compare(a_datum_hash, &l_item->datum_data_hash)) { + if (a_atom_hash) + *a_atom_hash = l_item->datum_data_hash; + if (a_ret_code) + *a_ret_code = 0; + size_t l_datum_size = 0; + // Memory leak here until assumed allocated memory returned in other data storage types + return (dap_chain_datum_t *)dap_global_db_get_sync(PVT(DAP_NONCONSENSUS(a_chain))->group_datums, + l_item->key, &l_datum_size, NULL, NULL); + } + } + return NULL; +}