diff --git a/dap-sdk b/dap-sdk index 1f0c4caf7a9cec9ddee67e9019e337c4c9278168..66bb11721a6f5726b9f2479b361fd95da62319b9 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit 1f0c4caf7a9cec9ddee67e9019e337c4c9278168 +Subproject commit 66bb11721a6f5726b9f2479b361fd95da62319b9 diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index 7dbf04b51274ef029b745509fa14f186eb41158e..44fe70e5886e581aed4c1eaa83e100cd0b42cf2f 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -1449,7 +1449,7 @@ void chain_mempool_proc(struct dap_http_simple *cl_st, void * arg) * @param sh HTTP server instance * @param url URL string */ -void dap_chain_mempool_add_proc(dap_http_t * a_http_server, const char * a_url) +void dap_chain_mempool_add_proc(dap_http_server_t * a_http_server, const char * a_url) { dap_http_simple_proc_add(a_http_server, a_url, 4096, chain_mempool_proc); } diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h index d18df1e803e53ec819a4f0635fe31e00efb368d9..a2221296a2a3e5de36bd2360878f659bcb4b53a9 100644 --- a/modules/mempool/include/dap_chain_mempool.h +++ b/modules/mempool/include/dap_chain_mempool.h @@ -4,7 +4,7 @@ #include "dap_chain_net.h" #include "dap_chain_datum.h" #include "dap_chain_ledger.h" -#include "dap_http.h" +#include "dap_http_server.h" #include "dap_cert.h" #include "dap_chain_block_cache.h" /* @@ -56,7 +56,7 @@ dap_datum_mempool_t * dap_datum_mempool_deserialize(uint8_t *datum_mempool_str, void dap_datum_mempool_clean(dap_datum_mempool_t *datum); void dap_datum_mempool_free(dap_datum_mempool_t *datum); -void dap_chain_mempool_add_proc(dap_http_t * a_http_server, const char * a_url); +void dap_chain_mempool_add_proc(dap_http_server_t * a_http_server, const char * a_url); void dap_chain_mempool_filter(dap_chain_t *a_chain, int *a_removed); diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 227d5c0bd2c7d138c07e75a955ec20bdee7ca103..bc549582557f87509b80b4e74fcf1188a543bc3a 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -4783,6 +4783,7 @@ int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_c */ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db) { + dap_return_if_fail(a_ledger); dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); pthread_rwlock_wrlock(&l_ledger_pvt->ledger_rwlock); pthread_rwlock_wrlock(&l_ledger_pvt->tokens_rwlock); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index d85f0058f2441c2996521ad0e88c8f71bcf2ed8b..0f5ca1b87e4100f4ab84a3dc0d0bec60538d25ef 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -181,6 +181,9 @@ typedef struct dap_chain_net_pvt{ uint16_t permanent_links_count; dap_stream_node_addr_t *permanent_links; // TODO realize permanent links from config + uint16_t poa_nodes_count; + dap_stream_node_addr_t *poa_nodes_addrs; + uint16_t seed_nodes_count; struct sockaddr_in *seed_nodes_ipv4; struct sockaddr_in6 *seed_nodes_ipv6; // TODO @@ -577,6 +580,7 @@ static void s_fill_links_from_root_aliases(dap_chain_net_t * a_net) dap_chain_node_info_t l_link_node_info = {}; l_link_node_info.hdr.ext_addr_v4 = l_net_pvt->seed_nodes_ipv4[i].sin_addr; l_link_node_info.hdr.ext_port = l_net_pvt->seed_nodes_ipv4[i].sin_port; + l_link_node_info.hdr.address = l_net_pvt->poa_nodes_addrs[i]; if (s_net_link_add(a_net, &l_link_node_info) > 0) // Maximum links count reached break; } @@ -2414,11 +2418,14 @@ void dap_chain_net_delete(dap_chain_net_t *a_net) } if (PVT(a_net)->main_timer) dap_interval_timer_delete(PVT(a_net)->main_timer); + DAP_DEL_Z(PVT(a_net)->poa_nodes_addrs); DAP_DEL_Z(PVT(a_net)->seed_nodes_ipv4); DAP_DEL_Z(PVT(a_net)->seed_nodes_ipv6); DAP_DEL_Z(PVT(a_net)->node_info); - dap_ledger_purge(a_net->pub.ledger, true); - dap_ledger_handle_free(a_net->pub.ledger); + if (a_net->pub.ledger) { + dap_ledger_purge(a_net->pub.ledger, true); + dap_ledger_handle_free(a_net->pub.ledger); + } DAP_DELETE(a_net); } @@ -2506,6 +2513,28 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx) // Wait time before reconnect attempt with same link l_net_pvt->reconnect_delay = dap_config_get_item_int16_default(l_cfg, "general", "reconnect_delay", 10); + char **l_poa_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "seed_nodes_addrs", &l_net_pvt->poa_nodes_count); + if (!l_net_pvt->poa_nodes_count) { + log_it(L_ERROR, "Can't read seed nodes addresses"); + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -15; + } + l_net_pvt->poa_nodes_addrs = DAP_NEW_SIZE(dap_stream_node_addr_t, l_net_pvt->poa_nodes_count * sizeof(dap_stream_node_addr_t)); + if (!l_net_pvt->poa_nodes_addrs) { + log_it(L_CRITICAL, g_error_memory_alloc); + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -1; + } + for (uint16_t i = 0; i < l_net_pvt->poa_nodes_count; i++) { + if (dap_stream_node_addr_from_str(l_net_pvt->poa_nodes_addrs + i, l_poa_nodes_addrs[i])) { + log_it(L_ERROR, "Incorrect format for address #%hu", i); + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -16; + } + } uint16_t l_seed_nodes_ipv4_len = 0; char **l_seed_nodes_ipv4 = dap_config_get_array_str(l_cfg, "general", "seed_nodes_ipv4", &l_seed_nodes_ipv4_len); uint16_t l_seed_nodes_ipv6_len = 0; @@ -2519,9 +2548,12 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx) if (l_seed_nodes_port_len) { if ((l_seed_nodes_ipv4_len && l_seed_nodes_ipv4_len != l_seed_nodes_port_len) || (l_seed_nodes_ipv6_len && l_seed_nodes_ipv6_len != l_seed_nodes_port_len) || - (l_seed_nodes_hostnames_len && l_seed_nodes_hostnames_len != l_seed_nodes_port_len)) { + (l_seed_nodes_hostnames_len && l_seed_nodes_hostnames_len != l_seed_nodes_port_len) || + (!l_seed_nodes_ipv4_len && !l_seed_nodes_ipv6_len && !l_seed_nodes_hostnames_len)) { log_it (L_ERROR, "Configuration mistake for seed nodes"); - + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -6; } l_net_pvt->seed_nodes_count = l_seed_nodes_port_len; } else { @@ -2530,8 +2562,23 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx) l_net_pvt->seed_nodes_count = l_bootstrap_nodes_len; } log_it (L_DEBUG, "Read %u seed nodes params", l_net_pvt->seed_nodes_count); - l_net_pvt->seed_nodes_ipv4 = DAP_NEW_SIZE(struct sockaddr_in, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in)); - l_net_pvt->seed_nodes_ipv6 = DAP_NEW_SIZE(struct sockaddr_in6, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in6)); + if (l_seed_nodes_ipv6_len) { + l_net_pvt->seed_nodes_ipv6 = DAP_NEW_SIZE(struct sockaddr_in6, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in6)); + if (!l_net_pvt->seed_nodes_ipv6) { + log_it(L_CRITICAL, g_error_memory_alloc); + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -1; + } + } else { // Just only IPv4 can be resolved for now + l_net_pvt->seed_nodes_ipv4 = DAP_NEW_SIZE(struct sockaddr_in, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in)); + if (!l_net_pvt->seed_nodes_ipv4) { + log_it(L_CRITICAL, g_error_memory_alloc); + dap_chain_net_delete(l_net); + dap_config_close(l_cfg); + return -1; + } + } // Load seed nodes from cfg file for (uint16_t i = 0; i < l_net_pvt->seed_nodes_count; i++) { char *l_node_hostname = NULL; @@ -2551,16 +2598,16 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx) l_node_port = atoi(l_bootstrap_port_str); l_node_hostname = l_bootstrap_nodes[i]; } - if (!l_node_port) - l_node_port = dap_config_get_item_uint16_default(g_config, "server", "listen_port_tcp", 8079); if (!l_node_port) { log_it(L_ERROR, "Can't find port for seed node #%hu", i); dap_chain_net_delete(l_net); dap_config_close(l_cfg); return -12; } else { - l_net_pvt->seed_nodes_ipv4[i].sin_port = l_node_port; - l_net_pvt->seed_nodes_ipv6[i].sin6_port = l_node_port; + if (l_seed_nodes_ipv6_len) + l_net_pvt->seed_nodes_ipv6[i].sin6_port = l_node_port; + else + l_net_pvt->seed_nodes_ipv4[i].sin_port = l_node_port; } if (l_node_hostname) { struct in_addr l_res = {}; @@ -2845,7 +2892,7 @@ int s_net_load(dap_chain_net_t *a_net) } dap_chain_net_add_poa_certs_to_cluster(l_net, l_cluster); DAP_DELETE(l_gdb_groups_mask); - if (l_net->pub.chains == l_chain) + if (l_net->pub.chains == l_chain) // Pointer for first mempool cluster in global double-linked list of clusters l_net_pvt->mempool_clusters = l_cluster; } // Service orders cluster @@ -3042,11 +3089,8 @@ void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_sto int dap_chain_net_add_poa_certs_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster) { dap_return_val_if_fail(a_net && a_cluster, -1); - for (dap_list_t *it = a_net->pub.keys; it; it = it->next) { - dap_pkey_t *l_pkey = it->data; - dap_stream_node_addr_t l_poa_addr = dap_stream_node_addr_from_pkey(l_pkey); - dap_global_db_cluster_member_add(a_cluster, &l_poa_addr, DAP_GDB_MEMBER_ROLE_ROOT); - } + for (uint16_t i = 0; i < PVT(a_net)->poa_nodes_count; i++) + dap_global_db_cluster_member_add(a_cluster, PVT(a_net)->poa_nodes_addrs + i, DAP_GDB_MEMBER_ROLE_ROOT); return 0; } diff --git a/modules/net/dap_chain_net_news.h b/modules/net/dap_chain_net_news.h deleted file mode 100644 index d3c82ce4658987c30e207472e51015d55c326c0f..0000000000000000000000000000000000000000 --- a/modules/net/dap_chain_net_news.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Authors: - * Alexander Lysikov <alexander.lysikov@demlabs.net> - * DeM Labs Inc. https://demlabs.net - * Kelvin Project https://github.com/kelvinblockchain - * Copyright (c) 2020 - * All rights reserved. - - This file is part of DAP (Deus Applications Prototypes) the open source project - - DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DAP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "dap_http.h" - -int dap_chain_net_news_init(dap_http_t * a_http); -void dap_chain_net_srv_vpn_cdb_news_cache_reset(void); diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c index 324ca95a2dd52c2aab94d105091bbe22319c5fec..36574892638d87ff2c1d59f90004da326799e391 100644 --- a/modules/net/dap_chain_node_cli.c +++ b/modules/net/dap_chain_node_cli.c @@ -256,7 +256,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "-addr <addr> [-chain_emission <chain_name>] -net <net_name> -certs <cert list>\n"); dap_cli_server_cmd_add("mempool", com_mempool, "Command for working with mempool", - "mempool list -net <net_name> [-chain <chain_name>] [-addr <addr>] [-fast]\n" + "mempool list -net <net_name> [-chain <chain_name>] [-addr <addr>] [-brief]\n" "\tList mempool (entries or transaction) for (selected chain network or wallet)\n" "mempool check -net <net_name> [-chain <chain_name>] -datum <datum_hash>\n" "\tCheck mempool entrie for presence in selected chain network\n" @@ -269,7 +269,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config) "\tDelete datum with hash <datum hash> for selected chain network\n" "mempool dump -net <net_name> -chain <chain_name> -datum <datum_hash>\n" "\tOutput information about datum in mempool\n" - "mempool add_ca -net <net_name> [-chain <chain_name>] -ca_name <priv_cert_name>\n" + "mempool add_ca -net <net_name> [-chain <chain_name>] -ca_name <pub_cert_name>\n" "\tAdd pubic certificate into the mempool to prepare its way to chains\n" "mempool count -net <net_name> [-chain <chain_name>]\n" "\tDisplays the number of elements in the mempool of a given network."); diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 29f121c2a5052a73fb274d223f19a081571c6c4d..330cc816a1973c3215b8590be5fdb172a19ab155 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -82,12 +82,8 @@ #include "dap_chain_block.h" #include "dap_chain_cs_blocks.h" -#ifndef _WIN32 -#include "dap_chain_net_news.h" -#endif #include "dap_chain_cell.h" - #include "dap_enc_base64.h" #include "json.h" #ifdef DAP_OS_UNIX @@ -102,6 +98,7 @@ #include "dap_chain_mempool.h" #include "dap_global_db.h" #include "dap_global_db_cluster.h" +#include "dap_global_db_pkt.h" #include "dap_stream_ch_chain_net.h" #include "dap_chain_ch.h" @@ -2413,7 +2410,8 @@ typedef enum dap_chain_node_cli_cmd_values_parse_net_chain_err_to_json { DAP_CHAIN_NODE_CLI_CMD_VALUES_PARSE_NET_CHAIN_ERR_CHAIN_NOT_FOUND = 104, DAP_CHAIN_NODE_CLI_CMD_VALUES_PARSE_NET_CHAIN_ERR_CHAIN_STR_IS_NULL = 105, DAP_CHAIN_NODE_CLI_CMD_VALUES_PARSE_NET_CHAIN_ERR_CONFIG_DEFAULT_DATUM = 106, - DAP_CHAIN_NODE_CLI_CMD_VALUE_PARSE_CONVERT_BASE58_TO_ADDR_WALLET = 107 + DAP_CHAIN_NODE_CLI_CMD_VALUE_PARSE_CONVERT_BASE58_TO_ADDR_WALLET = 107, + DAP_CHAIN_NODE_CLI_CMD_VALUE_PARSE_FAST_AND_BASE58_ADDR } dap_chain_node_cli_cmd_values_parse_net_chain_err_to_json; int dap_chain_node_cli_cmd_values_parse_net_chain_for_json(int *a_arg_index, int a_argc, char **a_argv, @@ -2929,11 +2927,18 @@ const char* s_tx_get_main_ticker(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_ * @param a_str_tmp * @param a_hash_out_type */ -void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a_chain, const char * a_add, json_object *a_json_obj, const char *a_hash_out_type) { +void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a_chain, const char * a_add, json_object *a_json_obj, const char *a_hash_out_type, bool a_fast) { dap_chain_addr_t *l_wallet_addr = dap_chain_addr_from_str(a_add); if (a_add && !l_wallet_addr) { dap_json_rpc_error_add(DAP_CHAIN_NODE_CLI_CMD_VALUE_PARSE_CONVERT_BASE58_TO_ADDR_WALLET, "Cannot convert " - "string '%s' to binary address.\n", a_add); + "string '%s' to binary address.\n", a_add); + return; + } + if (l_wallet_addr && a_fast) { + dap_json_rpc_error_add(DAP_CHAIN_NODE_CLI_CMD_VALUE_PARSE_FAST_AND_BASE58_ADDR, + "In fast mode, it is impossible to count the number of transactions and emissions " + "for a specific address. The -brief and -addr options are mutually exclusive.\n"); + DAP_DELETE(l_wallet_addr); return; } char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain); @@ -2977,7 +2982,7 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value; if (!l_datum->header.data_size || (l_datum->header.data_size > l_objs[i].value_len)) { log_it(L_ERROR, "Trash datum in GDB %s.%s, key: %s data_size:%u, value_len:%zu", - a_net->pub.name, a_chain->name, l_objs[i].key, l_datum->header.data_size, l_objs[i].value_len); + a_net->pub.name, a_chain->name, l_objs[i].key, l_datum->header.data_size, l_objs[i].value_len); dap_global_db_del_sync(l_gdb_group_mempool, l_objs[i].key); continue; } @@ -3058,256 +3063,438 @@ void s_com_mempool_list_print_for_chain(dap_chain_net_t * a_net, dap_chain_t * a json_object_object_add(l_jobj_datum, "type", l_jobj_type); json_object_object_add(l_jobj_datum, "created", l_jobj_ts_created); bool datum_is_accepted_addr = false; - switch (l_datum->header.type_id) { - case DAP_CHAIN_DATUM_TX: { - dap_chain_addr_t l_addr_from; - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)l_datum->data; - const char *l_main_token = s_tx_get_main_ticker(l_tx, a_net, NULL); - dap_list_t *l_list_sig_item = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_SIG, NULL); - if (!l_list_sig_item) { - json_object *l_jobj_wgn = json_object_new_string("An item with a type TX_ITEM_TYPE_SIG for the " - "transaction was not found, the transaction may " - "be corrupted."); - json_object_object_add(l_jobj_datum, "warning", l_jobj_wgn); - break; - } - dap_chain_tx_sig_t *l_sig = l_list_sig_item->data; - dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_sig); - dap_chain_addr_fill_from_sign(&l_addr_from, l_sign, a_net->pub.id); - if (l_wallet_addr && dap_chain_addr_compare(l_wallet_addr, &l_addr_from)) { - datum_is_accepted_addr = true; - } - dap_list_free(l_list_sig_item); - char *l_addr_from_str = dap_chain_addr_to_str(&l_addr_from); - if (!l_addr_from_str) { - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - dap_json_rpc_allocation_error; - return; - } - json_object *l_jobj_addr_from = json_object_new_string(l_addr_from_str); - DAP_DELETE(l_addr_from_str); - if (!l_jobj_addr_from) { - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - dap_json_rpc_allocation_error; - return; - } - json_object_object_add(l_jobj_datum, "from", l_jobj_addr_from); - dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL); - json_object *l_jobj_to_list = json_object_new_array(); - json_object *l_jobj_change_list = json_object_new_array(); - json_object *l_jobj_fee_list = json_object_new_array(); - if (!l_jobj_to_list || !l_jobj_change_list || !l_jobj_fee_list) { - json_object_put(l_jobj_to_list); - json_object_put(l_jobj_change_list); - json_object_put(l_jobj_fee_list); - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - dap_json_rpc_allocation_error; - return; - } - for (dap_list_t *it = l_list_out_items; it; it = it->next) { - dap_chain_addr_t *l_dist_addr = NULL; - uint256_t l_value = uint256_0; - const char *l_dist_token = NULL; - uint8_t l_type = *(uint8_t*)it->data; - switch (l_type) { - case TX_ITEM_TYPE_OUT: { - l_value = ((dap_chain_tx_out_t*)it->data)->header.value; - l_dist_token = l_main_token; - l_dist_addr = &((dap_chain_tx_out_t*)it->data)->addr; - } break; - case TX_ITEM_TYPE_OUT_EXT: { - l_value = ((dap_chain_tx_out_ext_t*)it->data)->header.value; - l_dist_token = ((dap_chain_tx_out_ext_t*)it->data)->token; - l_dist_addr = &((dap_chain_tx_out_ext_t*)it->data)->addr; - } break; - 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) { - l_dist_token = a_net->pub.native_ticker; - } - } break; - default: break; + if (!a_fast) { + switch (l_datum->header.type_id) { + case DAP_CHAIN_DATUM_TX: { + dap_chain_addr_t l_addr_from; + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *) l_datum->data; + const char *l_main_token = s_tx_get_main_ticker(l_tx, a_net, NULL); + if (l_main_token) { + json_object *l_jobj_main_ticker = json_object_new_string(l_main_token); + if (!l_jobj_main_ticker) { + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_object_add(l_jobj_datum, "main_ticker", l_jobj_main_ticker); } - json_object *l_jobj_money = json_object_new_object(); - if (!l_jobj_money){ - json_object_put(l_jobj_to_list); - json_object_put(l_jobj_change_list); - json_object_put(l_jobj_fee_list); - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - return; + dap_list_t *l_list_sig_item = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_SIG, NULL); + dap_list_t *l_list_in_ems = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_EMS, NULL); + if (!l_list_sig_item) { + json_object *l_jobj_wgn = json_object_new_string("An item with a type TX_ITEM_TYPE_SIG for the " + "transaction was not found, the transaction may " + "be corrupted."); + json_object_object_add(l_jobj_datum, "warning", l_jobj_wgn); + break; } - char *l_value_str = dap_chain_balance_print(l_value); - if (!l_value_str) { - json_object_put(l_jobj_to_list); - json_object_put(l_jobj_change_list); - json_object_put(l_jobj_fee_list); - json_object_put(l_jobj_money); - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - return; + dap_chain_tx_sig_t *l_sig = l_list_sig_item->data; + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_sig); + dap_chain_addr_fill_from_sign(&l_addr_from, l_sign, a_net->pub.id); + if (l_wallet_addr && dap_chain_addr_compare(l_wallet_addr, &l_addr_from)) { + datum_is_accepted_addr = true; } - char *l_value_coins_str = dap_chain_balance_to_coins(l_value); - if (!l_value_coins_str) { - json_object_put(l_jobj_to_list); - json_object_put(l_jobj_change_list); - json_object_put(l_jobj_fee_list); - DAP_DELETE(l_value_str); - json_object_put(l_jobj_money); + dap_list_free(l_list_sig_item); + char *l_addr_from_str = dap_chain_addr_to_str(&l_addr_from); + if (!l_addr_from_str) { json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; return; } - json_object *l_jobj_value = json_object_new_string(l_value_str); - if (!l_jobj_value) { - json_object_put(l_jobj_to_list); - json_object_put(l_jobj_change_list); - json_object_put(l_jobj_fee_list); - DAP_DELETE(l_value_str); - DAP_DELETE(l_value_coins_str); - json_object_put(l_jobj_money); - json_object_put(l_jobj_datum); - json_object_put(l_jobj_datums); - json_object_put(l_obj_chain); - dap_global_db_objs_delete(l_objs, l_objs_count); - return; + dap_list_t *l_list_in_reward = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_REWARD, NULL); + if (l_list_in_reward) { + json_object *l_obj_in_reward_arary = json_object_new_array(); + if (!l_obj_in_reward_arary) { + dap_list_free(l_list_in_reward); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + for (dap_list_t *it = l_list_in_reward; it; it = it->next) { + dap_chain_tx_in_reward_t *l_in_reward = (dap_chain_tx_in_reward_t *) it->data; + char *l_block_hash = dap_chain_hash_fast_to_str_new(&l_in_reward->block_hash); + json_object *l_jobj_block_hash = json_object_new_string(l_block_hash); + if (!l_jobj_block_hash) { + DAP_DELETE(l_block_hash); + json_object_put(l_obj_in_reward_arary); + dap_list_free(l_list_in_reward); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_array_add(l_obj_in_reward_arary, l_jobj_block_hash); + DAP_DELETE(l_block_hash); + } + } else { + json_object *l_jobj_addr_from = json_object_new_string(l_addr_from_str); + if (!l_jobj_addr_from) { + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_object_add(l_jobj_datum, "from", l_jobj_addr_from); } - json_object_object_add(l_jobj_money, "value", l_jobj_value); - json_object *l_jobj_value_coins = json_object_new_string(l_value_coins_str); - if (!l_jobj_value_coins){ + DAP_DELETE(l_addr_from_str); + dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL); + json_object *l_jobj_to_list = json_object_new_array(); + json_object *l_jobj_change_list = json_object_new_array(); + json_object *l_jobj_to_from_emi = json_object_new_array(); + json_object *l_jobj_fee_list = json_object_new_array(); + json_object *l_jobj_stake_lock_list = json_object_new_array(); + json_object *l_jobj_xchange_list = json_object_new_array(); + json_object *l_jobj_stake_pos_delegate_list = json_object_new_array(); + json_object *l_jobj_pay_list = json_object_new_array(); + if (!l_jobj_to_list || !l_jobj_change_list || !l_jobj_fee_list || !l_jobj_stake_lock_list || + !l_jobj_xchange_list || !l_jobj_stake_pos_delegate_list || !l_jobj_pay_list) { json_object_put(l_jobj_to_list); json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); json_object_put(l_jobj_fee_list); - DAP_DELETE(l_value_str); - DAP_DELETE(l_value_coins_str); - json_object_put(l_jobj_money); + json_object_put(l_jobj_stake_lock_list); + json_object_put(l_jobj_xchange_list); + json_object_put(l_jobj_stake_pos_delegate_list); + json_object_put(l_jobj_pay_list); json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; return; } - json_object_object_add(l_jobj_money, "coins", l_jobj_value_coins); - if (l_dist_token) { - json_object *l_jobj_token = json_object_new_string(l_dist_token); - if (!l_jobj_token) { + enum { + OUT_COND_TYPE_UNKNOWN, + OUT_COND_TYPE_PAY, + OUT_COND_TYPE_FEE, + OUT_COND_TYPE_STAKE_LOCK, + OUT_COND_TYPE_XCHANGE, + OUT_COND_TYPE_POS_DELEGATE + }l_out_cond_subtype={0}; + for (dap_list_t *it = l_list_out_items; it; it = it->next) { + dap_chain_addr_t *l_dist_addr = NULL; + uint256_t l_value = uint256_0; + const char *l_dist_token = NULL; + uint8_t l_type = *(uint8_t *) it->data; + switch (l_type) { + case TX_ITEM_TYPE_OUT: { + l_value = ((dap_chain_tx_out_t *) it->data)->header.value; + l_dist_token = l_main_token; + l_dist_addr = &((dap_chain_tx_out_t *) it->data)->addr; + } + break; + case TX_ITEM_TYPE_OUT_EXT: { + l_value = ((dap_chain_tx_out_ext_t *) it->data)->header.value; + l_dist_token = ((dap_chain_tx_out_ext_t *) it->data)->token; + l_dist_addr = &((dap_chain_tx_out_ext_t *) it->data)->addr; + } + break; + case TX_ITEM_TYPE_OUT_COND: { + dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t*)it->data; + l_value = ((dap_chain_tx_out_cond_t *) it->data)->header.value; + switch (l_out_cond->header.subtype) { + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE: { + l_dist_token = a_net->pub.native_ticker; + l_out_cond_subtype = OUT_COND_TYPE_FEE; + } break; + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK: { + l_dist_token = l_main_token; + l_out_cond_subtype = OUT_COND_TYPE_STAKE_LOCK; + } break; + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: { + l_dist_token = l_main_token; + l_out_cond_subtype = OUT_COND_TYPE_XCHANGE; + } break; + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE: { + l_dist_token = l_main_token; + l_out_cond_subtype = OUT_COND_TYPE_POS_DELEGATE; + } break; + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: { + l_dist_token = l_main_token; + l_out_cond_subtype = OUT_COND_TYPE_PAY; + } break; + default: + break; + } + } + break; + default: + break; + } + json_object *l_jobj_money = json_object_new_object(); + if (!l_jobj_money) { json_object_put(l_jobj_to_list); json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + char *l_value_str = dap_chain_balance_print(l_value); + if (!l_value_str) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); json_object_put(l_jobj_fee_list); json_object_put(l_jobj_money); json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); - DAP_DELETE(l_value_str); - DAP_DELETE(l_value_coins_str); dap_global_db_objs_delete(l_objs, l_objs_count); dap_json_rpc_allocation_error; return; } - json_object_object_add(l_jobj_money, "token", l_jobj_token); - } - - if (l_dist_addr) { - char *l_addr_str = dap_chain_addr_to_str(l_dist_addr); - if (!l_addr_str) { + char *l_value_coins_str = dap_chain_balance_to_coins(l_value); + if (!l_value_coins_str) { json_object_put(l_jobj_to_list); json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); json_object_put(l_jobj_fee_list); DAP_DELETE(l_value_str); - DAP_DELETE(l_value_coins_str); json_object_put(l_jobj_money); json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; return; - } - json_object *l_jobj_addr = json_object_new_string(l_addr_str); - if (!l_jobj_addr) { + } + json_object *l_jobj_value = json_object_new_string(l_value_str); + if (!l_jobj_value) { json_object_put(l_jobj_to_list); json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); json_object_put(l_jobj_fee_list); DAP_DELETE(l_value_str); DAP_DELETE(l_value_coins_str); - DAP_DELETE(l_addr_str); json_object_put(l_jobj_money); json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; return; } - if (!datum_is_accepted_addr && l_wallet_addr) { - datum_is_accepted_addr = dap_chain_addr_compare(l_wallet_addr, l_dist_addr); - } - json_object *l_jobj_f = json_object_new_object(); - if (!l_jobj_f) { + json_object_object_add(l_jobj_money, "value", l_jobj_value); + json_object *l_jobj_value_coins = json_object_new_string(l_value_coins_str); + if (!l_jobj_value_coins) { json_object_put(l_jobj_to_list); json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); json_object_put(l_jobj_fee_list); DAP_DELETE(l_value_str); DAP_DELETE(l_value_coins_str); - DAP_DELETE(l_addr_str); - json_object_put(l_jobj_addr); json_object_put(l_jobj_money); json_object_put(l_jobj_datum); json_object_put(l_jobj_datums); json_object_put(l_obj_chain); dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; return; } - json_object_object_add(l_jobj_f, "money", l_jobj_money); - if (dap_chain_addr_compare(&l_addr_from, l_dist_addr)) { - json_object_array_add(l_jobj_change_list, l_jobj_f); + json_object_object_add(l_jobj_money, "coins", l_jobj_value_coins); + if (l_dist_token) { + json_object *l_jobj_token = json_object_new_string(l_dist_token); + if (!l_jobj_token) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + json_object_put(l_jobj_money); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + DAP_DELETE(l_value_str); + DAP_DELETE(l_value_coins_str); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_object_add(l_jobj_money, "token", l_jobj_token); + } + + if (l_dist_addr) { + char *l_addr_str = dap_chain_addr_to_str(l_dist_addr); + if (!l_addr_str) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + DAP_DELETE(l_value_str); + DAP_DELETE(l_value_coins_str); + json_object_put(l_jobj_money); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object *l_jobj_addr = json_object_new_string(l_addr_str); + if (!l_jobj_addr) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + DAP_DELETE(l_value_str); + DAP_DELETE(l_value_coins_str); + DAP_DELETE(l_addr_str); + json_object_put(l_jobj_money); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + if (!datum_is_accepted_addr && l_wallet_addr) { + datum_is_accepted_addr = dap_chain_addr_compare(l_wallet_addr, l_dist_addr); + } + json_object *l_jobj_f = json_object_new_object(); + if (!l_jobj_f) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + DAP_DELETE(l_value_str); + DAP_DELETE(l_value_coins_str); + DAP_DELETE(l_addr_str); + json_object_put(l_jobj_addr); + json_object_put(l_jobj_money); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_object_add(l_jobj_f, "money", l_jobj_money); + if (dap_chain_addr_compare(&l_addr_from, l_dist_addr)) { + bool l_in_from_emi = false; + for (dap_list_t *it_ems = l_list_in_ems; it_ems; it_ems = it_ems->next) { + dap_chain_tx_in_ems_t *l_in_ems = (dap_chain_tx_in_ems_t*)it_ems->data; + if (!dap_strcmp(l_in_ems->header.ticker, l_dist_token)) { + l_in_from_emi = true; + dap_hash_fast_t l_ems_hash = l_in_ems->header.token_emission_hash; + char l_ems_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_hash_fast_to_str(&l_ems_hash, l_ems_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE); + json_object * l_obj_ems_hash = json_object_new_string(l_ems_hash_str); + if (!l_obj_ems_hash) { + json_object_put(l_jobj_to_list); + json_object_put(l_jobj_change_list); + json_object_put(l_jobj_to_from_emi); + json_object_put(l_jobj_fee_list); + DAP_DELETE(l_value_str); + DAP_DELETE(l_value_coins_str); + DAP_DELETE(l_addr_str); + json_object_put(l_jobj_addr); + json_object_put(l_jobj_money); + json_object_put(l_jobj_datum); + json_object_put(l_jobj_datums); + json_object_put(l_obj_chain); + json_object_put(l_jobj_f); + dap_global_db_objs_delete(l_objs, l_objs_count); + dap_json_rpc_allocation_error; + return; + } + json_object_object_add(l_jobj_f, "token_emission_hash", l_obj_ems_hash); + break; + } + } + if (l_in_from_emi) + json_object_array_add(l_jobj_to_from_emi, l_jobj_f); + else + json_object_array_add(l_jobj_change_list, l_jobj_f); + } else { + json_object_object_add(l_jobj_f, "addr", l_jobj_addr); + json_object_array_add(l_jobj_to_list, l_jobj_f); + } + DAP_DELETE(l_addr_str); } else { - json_object_object_add(l_jobj_f, "addr", l_jobj_addr); - json_object_array_add(l_jobj_to_list, l_jobj_f); + switch (l_out_cond_subtype) { + case OUT_COND_TYPE_PAY: + json_object_array_add(l_jobj_pay_list, l_jobj_money); + break; + case OUT_COND_TYPE_FEE: + json_object_array_add(l_jobj_fee_list, l_jobj_money); + break; + case OUT_COND_TYPE_STAKE_LOCK: + json_object_array_add(l_jobj_stake_lock_list, l_jobj_money); + break; + case OUT_COND_TYPE_XCHANGE: + json_object_array_add(l_jobj_xchange_list, l_jobj_money); + break; + case OUT_COND_TYPE_POS_DELEGATE: + json_object_array_add(l_jobj_stake_pos_delegate_list, l_jobj_money); + break; + default: + log_it(L_ERROR, "An unknown subtype output was found in a transaction in the mempool list."); + break; + } } - DAP_DELETE(l_value_str); DAP_DELETE(l_value_coins_str); - DAP_DELETE(l_addr_str); - } else { - json_object_array_add(l_jobj_fee_list, l_jobj_money); } + json_object_object_add(l_jobj_datum, "to", l_jobj_to_list); + json_object_object_add(l_jobj_datum, "change", l_jobj_change_list); + json_object_object_add(l_jobj_datum, "fee", l_jobj_fee_list); + json_object_array_length(l_jobj_pay_list) > 0 ? + json_object_object_add(l_jobj_datum, "srv_pay", l_jobj_pay_list) : json_object_put(l_jobj_pay_list); + json_object_array_length(l_jobj_xchange_list) > 0 ? + json_object_object_add(l_jobj_datum, "srv_xchange", l_jobj_xchange_list) : json_object_put(l_jobj_xchange_list); + json_object_array_length(l_jobj_stake_lock_list) > 0 ? + json_object_object_add(l_jobj_datum, "srv_stake_lock", l_jobj_stake_lock_list) : json_object_put(l_jobj_stake_lock_list); + json_object_array_length(l_jobj_stake_pos_delegate_list) > 0 ? + json_object_object_add(l_jobj_datum, "srv_stake_pos_delegate", l_jobj_stake_pos_delegate_list) : json_object_put(l_jobj_stake_pos_delegate_list); + json_object_array_length(l_jobj_to_from_emi) > 0 ? + json_object_object_add(l_jobj_datum, "from_emission", l_jobj_to_from_emi) : json_object_put(l_jobj_to_from_emi); + dap_list_free(l_list_out_items); } - json_object_object_add(l_jobj_datum, "to", l_jobj_to_list); - json_object_object_add(l_jobj_datum, "change", l_jobj_change_list); - json_object_object_add(l_jobj_datum, "fee", l_jobj_fee_list); - dap_list_free(l_list_out_items); - } break; - case DAP_CHAIN_DATUM_TOKEN_EMISSION: { - size_t l_emi_size = l_datum->header.data_size; - dap_chain_datum_token_emission_t *l_emi = dap_chain_datum_emission_read(l_datum->data, &l_emi_size); - if (l_wallet_addr && l_emi && dap_chain_addr_compare(l_wallet_addr, &l_emi->hdr.address)) - datum_is_accepted_addr = true; - DAP_DELETE(l_emi); - json_object_object_add(l_jobj_datum, "data", dap_chain_datum_data_to_json(l_datum)); - } break; - default: - json_object_object_add(l_jobj_datum, "data", dap_chain_datum_data_to_json(l_datum)); + break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION: { + size_t l_emi_size = l_datum->header.data_size; + dap_chain_datum_token_emission_t *l_emi = dap_chain_datum_emission_read(l_datum->data, &l_emi_size); + if (l_wallet_addr && l_emi && dap_chain_addr_compare(l_wallet_addr, &l_emi->hdr.address)) + datum_is_accepted_addr = true; + DAP_DELETE(l_emi); + json_object_object_add(l_jobj_datum, "data", dap_chain_datum_data_to_json(l_datum)); + } + break; + default: + json_object_object_add(l_jobj_datum, "data", dap_chain_datum_data_to_json(l_datum)); + } } - json_object_array_add(l_jobj_datums, l_jobj_datum); + if (l_wallet_addr) { + if (datum_is_accepted_addr) { + json_object_array_add(l_jobj_datums, l_jobj_datum); + } else + json_object_put(l_jobj_datum); + } else + json_object_array_add(l_jobj_datums, l_jobj_datum); } - dap_global_db_objs_delete(l_objs, l_objs_count); + json_object_object_add(l_obj_chain, "datums", l_jobj_datums); - + + dap_global_db_objs_delete(l_objs, l_objs_count); + char l_net_chain_count_total[64] = {0}; + sprintf(l_net_chain_count_total, "%s.%s: %zu", a_net->pub.name, a_chain->name, l_objs_count); json_object * l_object_total = json_object_new_string(l_net_chain_count_total); if (!l_object_total) { @@ -3325,7 +3512,11 @@ static int mempool_delete_for_chain(dap_chain_t *a_chain, const char * a_datum_h char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain); uint8_t *l_data_tmp = dap_global_db_get_sync(l_gdb_group_mempool, a_datum_hash_str, NULL, NULL, NULL); - if(l_data_tmp && dap_global_db_del_sync(l_gdb_group_mempool, a_datum_hash_str) == 0) { + if (!l_data_tmp) { + DAP_DELETE(l_gdb_group_mempool); + return 1; + } + if (dap_global_db_del_sync(l_gdb_group_mempool, a_datum_hash_str) == 0) { char *l_msg_str = dap_strdup_printf("Datum %s deleted", a_datum_hash_str); json_object *l_msg = json_object_new_string(l_msg_str); DAP_DELETE(l_msg_str); @@ -3342,7 +3533,7 @@ static int mempool_delete_for_chain(dap_chain_t *a_chain, const char * a_datum_h } else { DAP_DELETE(l_gdb_group_mempool); DAP_DELETE(l_data_tmp); - return 1; + return 2; } } @@ -3378,7 +3569,7 @@ int _cmd_mempool_delete(dap_chain_net_t *a_net, dap_chain_t *a_chain, const char res = mempool_delete_for_chain(a_chain, a_datum_hash, a_json_reply); } if (res) { - char *l_msg_str = dap_strdup_printf("Error! Can't find datum %s", a_datum_hash); + char *l_msg_str = dap_strdup_printf("Error! Can't %s datum %s", res == 1 ? "find" : "delete", a_datum_hash); if (!l_msg_str) { dap_json_rpc_allocation_error; return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED; @@ -3529,7 +3720,7 @@ int _cmd_mempool_check(dap_chain_net_t *a_net, dap_chain_t *a_chain, const char return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED; } json_object_object_add(l_obj_atom, "hash", l_jobj_atom_hash); - json_object_object_add(l_obj_atom, "err", l_jobj_atom_err); + json_object_object_add(l_obj_atom, "ledger_response_code", l_jobj_atom_err); json_object_object_add(l_jobj_datum, "atom", l_obj_atom); } json_object *l_datum_obj_inf = dap_chain_datum_to_json(l_datum); @@ -3953,11 +4144,12 @@ int com_mempool(int a_argc, char **a_argv, void **a_str_reply) dap_json_rpc_allocation_error; return -1; } + bool l_fast = (dap_cli_server_cmd_check_option(a_argv, arg_index, a_argc, "-brief") != -1) ? true : false; if(l_chain) { - s_com_mempool_list_print_for_chain(l_net, l_chain, l_wallet_addr, l_jobj_chains, l_hash_out_type); + s_com_mempool_list_print_for_chain(l_net, l_chain, l_wallet_addr, l_jobj_chains, l_hash_out_type, l_fast); } else { DL_FOREACH(l_net->pub.chains, l_chain) { - s_com_mempool_list_print_for_chain(l_net, l_chain, l_wallet_addr, l_jobj_chains, l_hash_out_type); + s_com_mempool_list_print_for_chain(l_net, l_chain, l_wallet_addr, l_jobj_chains, l_hash_out_type, l_fast); } } json_object_object_add(obj_ret, "chains", l_jobj_chains); @@ -6907,19 +7099,25 @@ int cmd_gdb_export(int a_argc, char **a_argv, void **a_str_reply) for (size_t i = 0; i < l_store_obj_count; ++i) { size_t l_out_size = DAP_ENC_BASE64_ENCODE_SIZE((int64_t)l_store_obj[i].value_len) + 1; + dap_sign_t *l_sign = l_store_obj[i].sign; + size_t l_sign_size = DAP_ENC_BASE64_ENCODE_SIZE(dap_sign_get_size(l_sign))+1; char *l_value_enc_str = DAP_NEW_Z_SIZE(char, l_out_size); + char *l_sign_str = DAP_NEW_Z_SIZE(char, l_sign_size); if(!l_value_enc_str) { log_it(L_CRITICAL, "Memory allocation error"); return -1; } dap_enc_base64_encode(l_store_obj[i].value, l_store_obj[i].value_len, l_value_enc_str, DAP_ENC_DATA_TYPE_B64); + dap_enc_base64_encode(l_sign, dap_sign_get_size(l_sign), l_sign_str, DAP_ENC_DATA_TYPE_B64); struct json_object *jobj = json_object_new_object(); - // TODO export sign and CRC and flags //json_object_object_add(jobj, "id", json_object_new_int64((int64_t)l_store_obj[i].id)); json_object_object_add(jobj, "key", json_object_new_string(l_store_obj[i].key)); json_object_object_add(jobj, "value", json_object_new_string(l_value_enc_str)); json_object_object_add(jobj, "value_len", json_object_new_int64((int64_t)l_store_obj[i].value_len)); + json_object_object_add(jobj, "flags", json_object_new_uint64((uint64_t)l_store_obj[i].flags)); + json_object_object_add(jobj, "sign", json_object_new_string(l_sign_str)); json_object_object_add(jobj, "timestamp", json_object_new_int64((int64_t)l_store_obj[i].timestamp)); + json_object_object_add(jobj, "crc", json_object_new_uint64(l_store_obj[i].crc)); json_object_array_add(l_json_group, jobj); DAP_DELETE(l_value_enc_str); @@ -7006,9 +7204,9 @@ int cmd_gdb_import(int a_argc, char **a_argv, void **a_str_reply) //l_id = json_object_object_get(l_record, "id"); l_key = json_object_object_get(l_record, "key"); l_value = json_object_object_get(l_record, "value"); + size_t l_record_size = json_object_object_length(l_record); l_value_len = json_object_object_get(l_record, "value_len"); l_ts = json_object_object_get(l_record, "timestamp"); - // TODO import sign and CRC and flags // l_group_store[j].id = (uint64_t)json_object_get_int64(l_id); l_group_store[j].key = dap_strdup(json_object_get_string(l_key)); l_group_store[j].group = dap_strdup(l_group_name); @@ -7025,6 +7223,26 @@ int cmd_gdb_import(int a_argc, char **a_argv, void **a_str_reply) } dap_enc_base64_decode(l_value_str, strlen(l_value_str), l_val, DAP_ENC_DATA_TYPE_B64); l_group_store[j].value = (uint8_t*)l_val; + if (l_record_size > 5) { + json_object *l_jobj_crc = json_object_object_get(l_record, "crc"); + json_object *l_jobj_sign = json_object_object_get(l_record, "sign"); + json_object *l_jobj_flags = json_object_object_get(l_record, "flags"); + uint8_t l_flags = (uint8_t)json_object_get_uint64(l_jobj_flags); + uint64_t l_crc = json_object_get_uint64(l_jobj_crc); + const char *l_sign_str = json_object_get_string(l_jobj_sign); + dap_sign_t *l_sign = DAP_NEW_Z_SIZE(dap_sign_t, dap_strlen(l_sign_str) + 1); + size_t l_sign_decree_size = dap_enc_base64_decode(l_sign_str, dap_strlen(l_sign_str), l_sign, DAP_ENC_DATA_TYPE_B64); + if (dap_sign_get_size(l_sign) != l_sign_decree_size) { + log_it(L_ERROR, "Can't reade signature from record with key %s", l_group_store[j].key); + } + l_group_store[j].sign = l_sign; + l_group_store[j].flags = l_flags; + l_group_store[j].crc = l_crc; + } else { + //Loading old record + dap_cert_t *l_cert_record = dap_cert_find_by_name(DAP_STREAM_NODE_ADDR_CERT_NAME); + l_group_store[j].sign = dap_store_obj_sign(&l_group_store[j], l_cert_record->enc_key, &l_group_store[j].crc); + } } if (dap_global_db_driver_apply(l_group_store, l_records_count)) { log_it(L_CRITICAL, "An error occured on importing group %s...", l_group_name); diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 1c9f797c54955bbad513f3f2d0cac1fb7a1d3000..077af7ad71f2dd7ff8c1b9a4e3811895156b2fec 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -551,6 +551,9 @@ json_object* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, DAP_DELETE(l_coins_str); } } + if (json_object_array_length(j_arr_data) > 0) { + json_object_object_add(j_obj_tx, "data", j_arr_data); + } dap_list_free(l_list_out_items); if (l_is_need_correction) { SUM_256_256(l_corr_value, l_fee_sum, &l_corr_value); @@ -563,10 +566,6 @@ json_object* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, DAP_DELETE(l_coins_str); l_is_need_correction = false; } - if (json_object_array_length(j_arr_data) > 0) { - json_object_object_add(j_obj_tx, "data", j_arr_data); - json_object_array_add(json_obj_datum, j_obj_tx); - } } a_chain->callback_datum_iter_delete(l_datum_iter); // delete hashes diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c index fadccfe53697b5ff48d867299c1c51717c43c5b9..eac80ec86b27bd2f7ef3182264e0eaaf13ec123c 100644 --- a/modules/net/dap_chain_node_client.c +++ b/modules/net/dap_chain_node_client.c @@ -268,8 +268,17 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg) l_node_client->callbacks.connected(l_node_client, l_node_client->callbacks_arg); dap_stream_ch_chain_net_pkt_hdr_t l_announce = { .version = DAP_STREAM_CH_CHAIN_NET_PKT_VERSION, .net_id = l_node_client->net->pub.id }; + // Announce net on downlink dap_client_write_unsafe(a_client, 'N', DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ANNOUNCE, &l_announce, sizeof(l_announce)); + // Add uplink to clusters + dap_stream_node_addr_t *l_uplink_addr = &l_node_client->info->hdr.address; + dap_global_db_cluster_t *it; + DL_FOREACH(dap_global_db_instance_get_default()->clusters, it) + if (dap_cluster_member_find_unsafe(it->role_cluster, l_uplink_addr)) + dap_cluster_member_add(it->links_cluster, l_uplink_addr, 0, NULL); + dap_chain_net_add_cluster_link(l_node_client->net, l_uplink_addr); + pthread_mutex_lock(&l_node_client->wait_mutex); l_node_client->state = NODE_CLIENT_STATE_ESTABLISHED; if (s_stream_ch_chain_debug_more) diff --git a/modules/net/include/dap_chain_net_bugreport.h b/modules/net/include/dap_chain_net_bugreport.h index c930015f0b79897ba7502452b74da80595b89872..d4ca32a594bfc38129acb7504ea0dfe72fde2ade 100644 --- a/modules/net/include/dap_chain_net_bugreport.h +++ b/modules/net/include/dap_chain_net_bugreport.h @@ -22,6 +22,6 @@ along with any DAP based project. If not, see <http://www.gnu.org/licenses/>. */ -#include "dap_http.h" +#include "dap_http_server.h" -int dap_chain_net_bugreport_init(dap_http_t * a_http); +int dap_chain_net_bugreport_init(dap_http_server_t * a_http); diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index a8b7d359f67a776e4e9d73f7d63dcc38a8a75c13..be4dc5d5c7db959bbf037181267497274b9cf6d6 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -865,7 +865,7 @@ dap_chain_net_srv_price_t * dap_chain_net_srv_get_price_from_order(dap_chain_net } uint64_t l_max_price_cfg = dap_config_get_item_uint64_default(g_config, a_config_section, "max_price", 0xFFFFFFFFFFFFFFF); - if (l_order->node_addr.uint64 != l_node_addr->uint64 && + if (l_order->node_addr.uint64 != g_node_addr.uint64 && l_order->srv_uid.uint64 != a_srv->uid.uint64) { DAP_DELETE(l_price); DAP_DEL_Z(l_order); @@ -962,9 +962,14 @@ int dap_chain_net_srv_price_apply_from_my_order(dap_chain_net_srv_t *a_srv, cons uint64_t l_max_price_cfg = dap_config_get_item_uint64_default(g_config, a_config_section, "max_price", 0xFFFFFFFFFFFFFFF); char *l_gdb_order_group = dap_chain_net_srv_order_get_gdb_group(l_net); dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_gdb_order_group, &l_orders_count); + log_it(L_INFO, "Found %"DAP_UINT64_FORMAT_U" orders.", l_orders_count); for (size_t i=0; i < l_orders_count; i++){ l_err_code = -4; dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len); + if(!l_order){ + log_it(L_ERROR, "Invalid order: NULL. Skip order."); + continue; + } if (l_order->node_addr.uint64 == g_node_addr.uint64 && l_order->srv_uid.uint64 == a_srv->uid.uint64) { l_err_code = 0; diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index d448dfa7877f708e65e56fbca106fe53e04aae14..0d49e1cbf4a280689545bf7531f2aeff27bb3731 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -2547,7 +2547,8 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply) char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; dap_chain_hash_fast_to_str(&l_datum_hash, l_hash_str, sizeof(l_hash_str)); dap_string_append_printf(l_str_tmp,"%s \n",spaces); - dap_string_append_printf(l_str_tmp, "%s \n", dap_time_to_str_rfc822(buf, DAP_TIME_STR_SIZE, l_datum_tx->header.ts_created)); + dap_time_to_str_rfc822(buf, DAP_TIME_STR_SIZE, l_datum_tx->header.ts_created); + dap_string_append_printf(l_str_tmp, "%s \n", buf); dap_string_append_printf(l_str_tmp,"tx_hash:\t%s \n",l_hash_str); l_signing_addr_str = dap_chain_addr_to_str(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr); diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index 1dca52acb800f8eb6a43637acfe6156478bff9a2..3e0630c055cfac649bb14a19887b240afc3ddd91 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -1023,19 +1023,11 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v 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)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_sell_str); - return -6; - } 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 'order create' requires parameter -token_buy"); return -5; } - if (!dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_buy_str)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_buy_str); - return -6; - } 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) { @@ -1043,20 +1035,12 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v return -8; } uint256_t l_datoshi_sell = dap_chain_balance_scan(l_val_sell_str); - if (IS_ZERO_256(l_datoshi_sell)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned integer 256>"); - return -9; - } 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 'order create' requires parameter -rate"); return -8; } uint256_t l_rate = dap_chain_coins_to_balance(l_val_rate_str); - if (IS_ZERO_256(l_rate)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -rate n.n = buy / sell (eg: 1.0, 1.135)"); - return -9; - } 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) { @@ -1064,10 +1048,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v return -20; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); - if (IS_ZERO_256(l_fee)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -fee <unsigned integer 256>"); - return -21; - } 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 'order create' requires parameter -w"); @@ -1081,27 +1061,78 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v } else { l_sign_str = dap_chain_wallet_check_sign(l_wallet); } - uint256_t l_value = dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_token_sell_str); - uint256_t l_value_sell = l_datoshi_sell; - if (!dap_strcmp(l_net->pub.native_ticker, l_token_sell_str)) { - if (SUM_256_256(l_value_sell, l_fee, &l_value_sell)) { - dap_chain_wallet_close(l_wallet); + char *l_hash_ret = NULL; + int ret_code = dap_chain_net_srv_xchange_create(l_net, l_token_buy_str, l_token_sell_str, l_datoshi_sell, l_rate, l_fee, l_wallet, &l_hash_ret); + dap_chain_wallet_close(l_wallet); + switch (ret_code) { + case XCHANGE_CREATE_ERROR_OK: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSuccessfully created order %s", l_sign_str, l_hash_ret); + DAP_DELETE(l_hash_ret); + return 0; + } + case XCHANGE_CREATE_ERROR_INVALID_ARGUMENT: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Some parameters could not be set during a function call"); + DAP_DELETE(l_hash_ret); + return -24; + } + case XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_IS_NOT_FOUND_LEDGER: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_sell_str); + DAP_DELETE(l_hash_ret); + return -6; + } + case XCHANGE_CREATE_ERROR_TOKEN_TICKER_BUY_IS_NOT_FOUND_LEDGER: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_buy_str); + DAP_DELETE(l_hash_ret); + return -6; + } + case XCHANGE_CREATE_ERROR_RATE_IS_ZERO: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -rate n.n = buy / sell (eg: 1.0, 1.135)"); + DAP_DELETE(l_hash_ret); + return -9; + } + case XCHANGE_CREATE_ERROR_FEE_IS_ZERO: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned integer 256>"); + DAP_DELETE(l_hash_ret); + return -21; + } + case XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned integer 256>"); + DAP_DELETE(l_hash_ret); + return -9; + } + case XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE: { log_it(L_ERROR, "Integer overflow with sum of value and fee"); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Integer overflow with sum of value and fee"); + DAP_DELETE(l_hash_ret); return -22; } - } else { // sell non-native ticker - uint256_t l_fee_value = dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_net->pub.native_ticker); - if (compare256(l_fee_value, l_fee) == -1) { + case XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET: { dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nNot enough cash for fee in specified wallet", l_sign_str); - dap_chain_wallet_close(l_wallet); + DAP_DELETE(l_hash_ret); return -23; } + case XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nNot enough cash in specified wallet", l_sign_str); + DAP_DELETE(l_hash_ret); + return -12; + } + case XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Out of memory"); + DAP_DELETE(l_hash_ret); + return -1; + } + case XCHANGE_CREATE_ERROR_CAN_NOT_COMPOSE_THE_CONDITIONAL_TRANSACTION: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str); + DAP_DELETE(l_hash_ret); + return -14; + } + case XCHANGE_CREATE_ERROR_CAN_NOT_PUT_TRANSACTION_TO_MEMPOOL: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str); + DAP_DELETE(l_hash_ret); + return -15; + } } - if (compare256(l_value, l_value_sell) == -1) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nNot enough cash in specified wallet", l_sign_str); - dap_chain_wallet_close(l_wallet); - return -12; - } + // Create the price dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); if (!l_price) { @@ -1110,7 +1141,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v dap_chain_wallet_close(l_wallet); return -1; } - l_price->wallet_str = dap_strdup(l_wallet_str); dap_stpcpy(l_price->token_sell, l_token_sell_str); l_price->net = l_net; dap_stpcpy(l_price->token_buy, l_token_buy_str); @@ -1121,7 +1151,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, l_wallet); if (!l_tx) { dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't compose the conditional transaction", l_sign_str); - DAP_DELETE(l_price->wallet_str); DAP_DELETE(l_price); dap_chain_wallet_close(l_wallet); return -14; @@ -1131,7 +1160,6 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v char* l_ret = NULL; if(!(l_ret = s_xchange_tx_put(l_tx, l_net))) { dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't put transaction to mempool", l_sign_str); - DAP_DELETE(l_price->wallet_str); DAP_DELETE(l_price); return -15; } @@ -1262,41 +1290,39 @@ static int s_cli_srv_xchange_order(int a_argc, char **a_argv, int a_arg_index, v return -12; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); - if(IS_ZERO_256(l_fee)){ - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get fee value."); - return -13; - } dap_hash_fast_t l_tx_hash = {}; dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); - dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash); - if (!l_cond_tx) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSpecified order not found", l_sign_str); - return -13; - } - dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, &l_fee, false); - if (!l_price) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't create price object from order", l_sign_str); - return -13; - } - - if (l_cmd_num == CMD_REMOVE) { - dap_string_t *l_str_reply = dap_string_new(l_sign_str); - char* l_ret = s_xchange_tx_invalidate(l_price, l_wallet); - dap_chain_wallet_close(l_wallet); - if (!l_ret) { - if (!l_price) { - dap_string_append_printf(l_str_reply, "Can't get price for order %s\n", l_order_hash_str); - } else { - char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); - dap_string_append_printf(l_str_reply, "Can't invalidate transaction %s\n", l_tx_hash_str); - DAP_DELETE(l_tx_hash_str); - } - } else - 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); + dap_chain_wallet_close(l_wallet); + char *l_tx_hash_ret = NULL; + int l_ret_code = dap_chain_net_srv_xchange_remove(l_net, &l_tx_hash, l_fee, l_wallet, &l_tx_hash_ret); + switch (l_ret_code) { + case XCHANGE_REMOVE_ERROR_OK: + dap_cli_server_cmd_set_reply_text(a_str_reply, "Order successfully removed. Created inactivate tx with hash %s", l_tx_hash_ret); + DAP_DELETE(l_tx_hash_ret); + break; + case XCHANGE_REMOVE_ERROR_CAN_NOT_FIND_TX: + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSpecified order not found", l_sign_str); + break; + case XCHANGE_REMOVE_ERROR_CAN_NOT_CREATE_PRICE: + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't create price object from order", l_sign_str); + break; + case XCHANGE_REMOVE_ERROR_FEE_IS_ZERO: + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't get fee value."); + break; + case XCHANGE_REMOVE_ERROR_CAN_NOT_INVALIDATE_TX: { + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash); + dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, &l_fee, false); + char *l_finaly_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_price->tx_hash); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create invalidate transaction from: %s\n", l_finaly_tx_hash_str); + DAP_DELETE(l_price); + DAP_DELETE(l_finaly_tx_hash_str); + } break; + default: + dap_cli_server_cmd_set_reply_text(a_str_reply, "An error occurred with an unknown code: %d.", l_ret_code); + break; } + DAP_DELETE(l_sign_str); + return l_ret_code; } break; case CMD_STATUS: { @@ -1968,47 +1994,39 @@ static int s_cli_srv_xchange(int a_argc, char **a_argv, void **a_str_reply) return -8; } uint256_t l_datoshi_buy = dap_chain_balance_scan(l_val_buy_str); - if (IS_ZERO_256(l_datoshi_buy)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <unsigned int256>"); - return -9; - } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_val_fee_str); if (!l_val_fee_str) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'purchase' requires parameter -fee"); return -8; } uint256_t l_datoshi_fee = dap_chain_balance_scan(l_val_fee_str); - if (IS_ZERO_256(l_datoshi_fee)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -fee <unsigned int256>"); - return -9; - } dap_hash_fast_t l_tx_hash = {}; dap_chain_hash_fast_from_str(l_order_hash_str, &l_tx_hash); - dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash); - - if (l_cond_tx) { - dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(l_net, l_cond_tx, &l_datoshi_fee, false); - if(!l_price){ + char *l_str_ret_hash = NULL; + int l_ret_code = dap_chain_net_srv_xchange_purchase(l_net, &l_tx_hash, l_datoshi_buy, l_datoshi_fee, + l_wallet, &l_str_ret_hash); + switch (l_ret_code) { + case XCHANGE_PURCHASE_ERROR_OK: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Exchange transaction has done. tx hash: %s", l_str_ret_hash); + DAP_DELETE(l_str_ret_hash); + return 0; + } + case XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found"); + return -13; + } + case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE: { dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create price from order"); return -13; } - // Create conditional transaction - dap_chain_hash_fast_from_str(l_order_hash_str, &l_price->order_hash); - char *l_ret = NULL; - dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, l_wallet, l_datoshi_buy, l_datoshi_fee); - if (l_tx && (l_ret = s_xchange_tx_put(l_tx, l_net)) && - dap_hash_fast_is_blank(&l_price->order_hash)) - dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str); - DAP_DELETE(l_price); - if (l_tx && l_ret){ - dap_cli_server_cmd_set_reply_text(a_str_reply, "Exchange transaction has done. tx hash: %s", l_ret); - } else + case XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX: { dap_cli_server_cmd_set_reply_text(a_str_reply, "Exchange transaction error"); - - DAP_DEL_Z(l_ret); - } else { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found"); - return -13; + return -13; + } + default: { + dap_cli_server_cmd_set_reply_text(a_str_reply, "An error occurred with an unknown code: %d.", l_ret_code); + return -14; + } } } break; case CMD_ENABLE: { @@ -2419,3 +2437,151 @@ void dap_chain_net_srv_xchange_print_fee(dap_chain_net_t *a_net, dap_string_t *a "\t\tThe xchanger service has not announced a commission fee.\n"); } } + +dap_list_t *dap_chain_net_srv_xchange_get_prices(dap_chain_net_t *a_net) { + dap_list_t *l_list_prices = NULL; + dap_list_t *l_list_tx = dap_chain_net_get_tx_cond_all_by_srv_uid(a_net, c_dap_chain_net_srv_xchange_uid, 0, 0,TX_SEARCH_TYPE_NET); + dap_list_t *l_temp = l_list_tx; + while(l_temp) + { + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_temp->data; + + dap_chain_net_srv_xchange_price_t * l_price = NULL; + l_price = s_xchange_price_from_order(a_net, l_tx, NULL, true); + if(!l_price ){ + log_it(L_WARNING,"Can't create price from order"); + l_temp = l_temp->next; + continue; + } + l_list_prices = dap_list_append(l_list_prices, l_price); + l_temp = l_temp->next; + } + dap_list_free(l_list_tx); + return l_list_prices; +} + +int dap_chain_net_srv_xchange_create(dap_chain_net_t *a_net, const char *a_token_buy, + const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, + char **a_out_tx_hash){ + if (!a_net || !a_token_buy || !a_token_sell || !a_wallet || !a_out_tx_hash) { + return XCHANGE_CREATE_ERROR_INVALID_ARGUMENT; + } + if (!dap_ledger_token_ticker_check(a_net->pub.ledger, a_token_sell)) { + return XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_IS_NOT_FOUND_LEDGER; + } + if (!dap_ledger_token_ticker_check(a_net->pub.ledger, a_token_buy)) { + return XCHANGE_CREATE_ERROR_TOKEN_TICKER_BUY_IS_NOT_FOUND_LEDGER; + } + if (IS_ZERO_256(a_rate)) { + return XCHANGE_CREATE_ERROR_RATE_IS_ZERO; + } + if (IS_ZERO_256(a_fee)) { + return XCHANGE_CREATE_ERROR_FEE_IS_ZERO; + } + if (IS_ZERO_256(a_datoshi_sell)) { + return XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO; + } + const char* l_sign_str = dap_chain_wallet_check_sign(a_wallet); + uint256_t l_value = dap_chain_wallet_get_balance(a_wallet, a_net->pub.id, a_token_sell); + uint256_t l_value_sell = a_datoshi_sell; + if (!dap_strcmp(a_net->pub.native_ticker, a_token_sell)) { + if (SUM_256_256(l_value_sell, a_fee, &l_value_sell)) { + log_it(L_ERROR, "Integer overflow with sum of value and fee"); + return XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE; + } + } else { // sell non-native ticker + uint256_t l_fee_value = dap_chain_wallet_get_balance(a_wallet, a_net->pub.id, a_net->pub.native_ticker); + if (compare256(l_fee_value, a_fee) == -1) { + return XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET; + } + } + if (compare256(l_value, l_value_sell) == -1) { + return XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET; + } + // Create the price + dap_chain_net_srv_xchange_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_xchange_price_t); + if (!l_price) { + log_it(L_CRITICAL, "Memory allocation error"); + return XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED; + } + dap_stpcpy(l_price->token_sell, a_token_sell); + l_price->net = a_net; + dap_stpcpy(l_price->token_buy, a_token_buy); + l_price->datoshi_sell = a_datoshi_sell; + l_price->rate = a_rate; + l_price->fee = a_fee; + // Create conditional transaction + dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_request(l_price, a_wallet); + if (!l_tx) { + DAP_DELETE(l_price); + return XCHANGE_CREATE_ERROR_CAN_NOT_COMPOSE_THE_CONDITIONAL_TRANSACTION; + } + dap_hash_fast_t l_tx_hash ={}; + dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash); + char* l_ret = NULL; + if(!(l_ret = s_xchange_tx_put(l_tx, a_net))) { + DAP_DELETE(l_price); + return XCHANGE_CREATE_ERROR_CAN_NOT_PUT_TRANSACTION_TO_MEMPOOL; + } + // To avoid confusion, the term "order" will apply to the original conditional exchange offer transactions. + *a_out_tx_hash = l_ret; + return XCHANGE_CREATE_ERROR_OK; +} + +int dap_chain_net_srv_xchange_remove(dap_chain_net_t *a_net, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, char **a_out_hash_tx) { + if (!a_net || !a_hash_tx || !a_wallet) { + return XCHANGE_REMOVE_ERROR_INVALID_ARGUMENT; + } + if(IS_ZERO_256(a_fee)){ + return XCHANGE_REMOVE_ERROR_FEE_IS_ZERO; + } + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_hash_tx); + if (!l_cond_tx) { + return XCHANGE_REMOVE_ERROR_CAN_NOT_FIND_TX; + } + dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, &a_fee, false); + if (!l_price) { + return XCHANGE_REMOVE_ERROR_CAN_NOT_CREATE_PRICE; + } + char* l_ret = s_xchange_tx_invalidate(l_price, a_wallet); + if (!l_ret){ + DAP_DELETE(l_price); + return XCHANGE_REMOVE_ERROR_CAN_NOT_INVALIDATE_TX; + } + *a_out_hash_tx = l_ret; + DAP_DELETE(l_price); + return XCHANGE_REMOVE_ERROR_OK; +} + +int dap_chain_net_srv_xchange_purchase(dap_chain_net_t *a_net, dap_hash_fast_t *a_order_hash, uint256_t a_value, + uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out){ + if (!a_net || !a_order_hash || !a_wallet || !a_hash_out) { + return XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT; + } + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_order_hash); + if (l_cond_tx) { + dap_chain_net_srv_xchange_price_t *l_price = s_xchange_price_from_order(a_net, l_cond_tx, &a_fee, false); + if(!l_price){ + return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE; + } + // Create conditional transaction + char *l_ret = NULL; + dap_chain_datum_tx_t *l_tx = s_xchange_tx_create_exchange(l_price, a_wallet, a_value, a_fee); + if (l_tx && (l_ret = s_xchange_tx_put(l_tx, a_net)) && + dap_hash_fast_is_blank(&l_price->order_hash)) { + char *l_order_hash_str = dap_hash_fast_to_str_new(a_order_hash); + dap_chain_net_srv_order_delete_by_hash_str_sync(l_price->net, l_order_hash_str); + DAP_DELETE(l_order_hash_str); + } + DAP_DELETE(l_price); + if (l_tx && l_ret){ + *a_hash_out = l_ret; + return XCHANGE_PURCHASE_ERROR_OK; + } else + return XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX; + } else { + return XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND; + } +} diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h index 1d8ac20c694eb2f847b2ec197c8b25d8eedb3369..0cd59476943d77e14e1a4e96fc3c71c660013a0e 100644 --- a/modules/service/xchange/include/dap_chain_net_srv_xchange.h +++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h @@ -31,7 +31,6 @@ #define GROUP_LOCAL_XCHANGE "local.xchange" typedef struct dap_chain_net_srv_xchange_price { - char *wallet_str; char token_sell[DAP_CHAIN_TICKER_SIZE_MAX]; uint256_t datoshi_sell; dap_chain_net_t *net; @@ -62,3 +61,47 @@ void dap_chain_net_srv_xchange_deinit(); json_object *dap_chain_net_srv_xchange_print_fee_json(dap_chain_net_t *a_net); void dap_chain_net_srv_xchange_print_fee(dap_chain_net_t *a_net, dap_string_t *a_string_ret); + +enum dap_chain_net_srv_xchange_create_error_list{ + XCHANGE_CREATE_ERROR_OK = 0, + XCHANGE_CREATE_ERROR_INVALID_ARGUMENT, + XCHANGE_CREATE_ERROR_TOKEN_TICKER_SELL_IS_NOT_FOUND_LEDGER, + XCHANGE_CREATE_ERROR_TOKEN_TICKER_BUY_IS_NOT_FOUND_LEDGER, + XCHANGE_CREATE_ERROR_RATE_IS_ZERO, + XCHANGE_CREATE_ERROR_FEE_IS_ZERO, + XCHANGE_CREATE_ERROR_VALUE_SELL_IS_ZERO, + XCHANGE_CREATE_ERROR_INTEGER_OVERFLOW_WITH_SUM_OF_VALUE_AND_FEE, + XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_FOR_FEE_IN_SPECIFIED_WALLET, + XCHANGE_CREATE_ERROR_NOT_ENOUGH_CASH_IN_SPECIFIED_WALLET, + XCHANGE_CREATE_ERROR_MEMORY_ALLOCATED, + XCHANGE_CREATE_ERROR_CAN_NOT_COMPOSE_THE_CONDITIONAL_TRANSACTION, + XCHANGE_CREATE_ERROR_CAN_NOT_PUT_TRANSACTION_TO_MEMPOOL, +}; +int dap_chain_net_srv_xchange_create(dap_chain_net_t *a_net, const char *a_token_buy, + const char *a_token_sell, uint256_t a_datoshi_sell, + uint256_t a_rate, uint256_t a_fee, dap_chain_wallet_t *a_wallet, + char **a_out_tx_hash); + +enum dap_chain_net_srv_xchange_remove_error_list{ + XCHANGE_REMOVE_ERROR_OK = 0, + XCHANGE_REMOVE_ERROR_INVALID_ARGUMENT, + XCHANGE_REMOVE_ERROR_FEE_IS_ZERO, + XCHANGE_REMOVE_ERROR_CAN_NOT_FIND_TX, + XCHANGE_REMOVE_ERROR_CAN_NOT_CREATE_PRICE, + XCHANGE_REMOVE_ERROR_CAN_NOT_INVALIDATE_TX +}; +int dap_chain_net_srv_xchange_remove(dap_chain_net_t *a_net, dap_hash_fast_t *a_hash_tx, uint256_t a_fee, + dap_chain_wallet_t *a_wallet, char **a_out_hash_tx); + +dap_list_t *dap_chain_net_srv_xchange_get_tx_xchange(dap_chain_net_t *a_net); +dap_list_t *dap_chain_net_srv_xchange_get_prices(dap_chain_net_t *a_net); + +enum dap_chain_net_srv_xchange_purchase_error_list{ + XCHANGE_PURCHASE_ERROR_OK = 0, + XCHANGE_PURCHASE_ERROR_INVALID_ARGUMENT, + XCHANGE_PURCHASE_ERROR_SPECIFIED_ORDER_NOT_FOUND, + XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_PRICE, + XCHANGE_PURCHASE_ERROR_CAN_NOT_CREATE_EXCHANGE_TX, +}; +int dap_chain_net_srv_xchange_purchase(dap_chain_net_t *a_net, dap_hash_fast_t *a_order_hash, uint256_t a_value, + uint256_t a_fee, dap_chain_wallet_t *a_wallet, char **a_hash_out);