-
8d4c6f45
dap_chain_net_srv_order.c 29.70 KiB
/*
* Authors:
* Dmitrii Gerasimov <naeper@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Cellframe https://cellframe.net
* Copyright (c) 2017-2019
* 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 <stdio.h>
#include <strings.h>
#include "dap_chain_net_srv_order.h"
#include "dap_hash.h"
#include "dap_enc_base58.h"
#include "dap_global_db.h"
#include "dap_chain_net_srv_countries.h"
#include "dap_chain_net_srv_stake_pos_delegate.h"
#define LOG_TAG "dap_chain_net_srv_order"
/*
Continent codes :
AF : Africa geonameId=6255146
AS : Asia geonameId=6255147
EU : Europe geonameId=6255148
NA : North America geonameId=6255149
OC : Oceania geonameId=6255151
SA : South America geonameId=6255150
AN : Antarctica geonameId=6255152
*/
char *s_server_continents[]={
"None",
"Africa",
"Europe",
"North America",
"South America",
"Southeast Asia",
"Asia",
//"Near East",
"Oceania",
"Antarctica"
};
struct dap_order_notify {
dap_chain_net_t *net;
dap_store_obj_callback_notify_t callback;
void *cb_arg;
};
static dap_list_t *s_order_notify_callbacks = NULL;
static void s_srv_order_callback_notify(dap_global_db_context_t *a_context, dap_store_obj_t *a_obj, void *a_arg);
static dap_timerfd_t *s_timer_order_check_decree_sign = NULL;
static void s_srv_order_check_decree_sign_timer() {
uint32_t l_unverified_orders_lifetime = dap_config_get_item_uint32_default(g_config, "srv", "unverified_orders_lifetime", 21600);
dap_time_t l_time_cut_off = dap_time_now();
l_time_cut_off -= l_unverified_orders_lifetime; // 6 Hours;
uint16_t l_net_count = 0;
dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
for (uint16_t i = 0; i < l_net_count; i++) {
if (dap_chain_net_get_role(l_net_list[i]).enums == NODE_ROLE_MASTER) {
char *l_order_group = dap_chain_net_srv_order_get_gdb_group(l_net_list[i]);
size_t l_order_count = 0;
dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_order_group, &l_order_count);
for (size_t j = 0; j < l_order_count; j++) {
dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *) (l_orders[j].value);
if (!l_order)
continue;
if (l_order->ts_created < l_time_cut_off) {
dap_sign_t *l_sign = (dap_sign_t *) (l_order->ext_n_sign + l_order->ext_size);
dap_hash_fast_t l_sign_pkey_hash = {0};
dap_sign_get_pkey_hash(l_sign, &l_sign_pkey_hash);
dap_chain_addr_t l_signed_addr = {0};
dap_chain_addr_fill(&l_signed_addr, l_sign->header.type, &l_sign_pkey_hash, l_net_list[i]->pub.id);
if (!dap_chain_net_srv_stake_key_delegated(&l_signed_addr)) {
char *l_pkey_hash_str = dap_hash_fast_to_str_new(&l_sign_pkey_hash);
log_it(L_NOTICE, "Order %s signed by the non-delegated public key %s. Order deleted",
l_orders[j].key,
l_pkey_hash_str);
DAP_DELETE(l_pkey_hash_str);
dap_global_db_del(l_order_group, l_orders[j].key, NULL, NULL);
}
}
}
dap_global_db_objs_delete(l_orders, l_order_count);
DAP_DELETE(l_order_group);
}
}
DAP_DELETE(l_net_list);
}
/**
* @brief dap_chain_net_srv_order_init
* @return
*/
int dap_chain_net_srv_order_init()
{
uint16_t l_net_count = 0;
dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
for (uint16_t i = 0; i < l_net_count; i++) {
dap_chain_net_add_gdb_notify_callback(l_net_list[i], s_srv_order_callback_notify, l_net_list[i]);
}
//geoip_info_t *l_ipinfo = chain_net_geoip_get_ip_info("8.8.8.8");
if (!dap_config_get_item_bool_default(g_config, "srv", "allow_unverified_orders", true)) {
uint32_t l_unverified_orders_lifetime = dap_config_get_item_uint32_default(g_config, "srv", "unverified_orders_lifetime", 21600); // 6 Hours
s_timer_order_check_decree_sign = dap_interval_timer_create(l_unverified_orders_lifetime * 1000,
(dap_timer_callback_t)s_srv_order_check_decree_sign_timer,
NULL);
} else {
log_it(L_DEBUG, "A mode is enabled that disables verification that the signature was put by "
"the node by the validator.");
}
DAP_DELETE(l_net_list);
return 0;
}
/**
* @brief dap_chain_net_srv_order_deinit
*/
void dap_chain_net_srv_order_deinit()
{
dap_list_free_full(s_order_notify_callbacks, NULL);
}
size_t dap_chain_net_srv_order_get_size(dap_chain_net_srv_order_t *a_order)
{
if (!a_order)
return 0;
size_t l_sign_size = 0;
if (a_order->version == 3) {
dap_sign_t *l_sign = (dap_sign_t *)(a_order->ext_n_sign + a_order->ext_size);
if (l_sign->header.type.type == SIG_TYPE_NULL)
l_sign_size = sizeof(dap_sign_type_t);
else
l_sign_size = dap_sign_get_size(l_sign);
return sizeof(dap_chain_net_srv_order_t) + a_order->ext_size + l_sign_size;
}
dap_chain_net_srv_order_old_t *l_order = (dap_chain_net_srv_order_old_t *)a_order;
if(l_order->version == 2) {
dap_sign_t *l_sign = (dap_sign_t *)&l_order->ext[l_order->ext_size];
if (l_sign->header.type.type == SIG_TYPE_NULL)
l_sign_size = sizeof(dap_sign_type_t);
else
l_sign_size = dap_sign_get_size(l_sign);
}
return sizeof(dap_chain_net_srv_order_old_t) + l_order->ext_size + l_sign_size;
}
/**
* @brief dap_chain_net_srv_order_get_region_continent
* @param a_continent_num [in]
* @param a_region [in]
*/
bool dap_chain_net_srv_order_set_continent_region(dap_chain_net_srv_order_t **a_order, uint8_t a_continent_num, const char *a_region)
{
dap_chain_net_srv_order_t *l_order = *a_order;
if(!l_order || (!a_continent_num && !a_region))
return false;
uint8_t l_continent_num_prev = 0;
char *l_region_prev = NULL;
dap_chain_net_srv_order_get_continent_region(*a_order, &l_continent_num_prev, &l_region_prev);
uint32_t l_ext_size = 1 + sizeof(uint8_t);
if(a_region)
l_ext_size += strlen(a_region) + 1;
else if(l_region_prev)
l_ext_size += strlen(l_region_prev) + 1;
l_order = DAP_REALLOC(l_order, sizeof(dap_chain_net_srv_order_t) + l_ext_size);
l_order->ext_n_sign[0] =0x52;
if(a_continent_num > 0)
memcpy(l_order->ext_n_sign + 1, &a_continent_num, sizeof(uint8_t));
else
memcpy(l_order->ext_n_sign + 1, &l_continent_num_prev, sizeof(uint8_t));
if(a_region)
memcpy(l_order->ext_n_sign + 1 + sizeof(uint8_t), a_region, strlen(a_region) + 1);
else if(l_region_prev)
memcpy(l_order->ext_n_sign + 1 + sizeof(uint8_t), l_region_prev, strlen(l_region_prev) + 1);
//sprintf(l_order->ext, "\52%d-%s", a_continent_num, a_region);
l_order->ext_size = l_ext_size;
*a_order = l_order;
DAP_DELETE(l_region_prev);
return true;
}
/**
* @brief dap_chain_net_srv_order_get_region_continent
* @param a_continent_num [out]
* @param a_region [out]
*/
bool dap_chain_net_srv_order_get_continent_region(dap_chain_net_srv_order_t *a_order_static, uint8_t *a_continent_num, char **a_region)
{
if(!a_order_static || !a_order_static->ext_size || a_order_static->ext_n_sign[0]!=0x52)
return false;
if(a_continent_num) {
if((uint8_t)a_order_static->ext_n_sign[1]!=0xff)
memcpy(a_continent_num, a_order_static->ext_n_sign + 1, sizeof(uint8_t));
else
a_continent_num = 0;
}
if(a_region) {
size_t l_size = a_order_static->ext_size - sizeof(uint8_t) - 1;
if(l_size > 0) {
*a_region = DAP_NEW_SIZE(char, l_size);
if (!a_region) {
log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
return false;
}
memcpy(*a_region, a_order_static->ext_n_sign + 1 + sizeof(uint8_t), l_size);
}
else
*a_region = NULL;
}
return true;
}
/**
* @brief dap_chain_net_srv_order_get_country_code
* @param a_order
*/
const char* dap_chain_net_srv_order_get_country_code(dap_chain_net_srv_order_t *a_order)
{
char *l_region = NULL;
if (!dap_chain_net_srv_order_get_continent_region(a_order, NULL, &l_region))
return NULL;
int l_countries = sizeof(s_server_countries)/sizeof(char*);
for (int i = 0; i < l_countries; i+=4) {
if(l_region && (!strcasecmp(l_region, s_server_countries[i+1]) || !strcasecmp(l_region, s_server_countries[i+2]))){
const char *l_country_code = s_server_countries[i];
DAP_DELETE(l_region);
return l_country_code;
}
}
DAP_DELETE(l_region);
return NULL;
}
/**
* @brief dap_chain_net_srv_order_continents_count
*/
size_t dap_chain_net_srv_order_continents_count(void)
{
size_t l_count = sizeof(s_server_continents) / sizeof(char*);
return l_count;
}
/**
* @brief dap_chain_net_srv_order_get_continent_str
*/
const char* dap_chain_net_srv_order_continent_to_str(int8_t a_num)
{
int8_t l_count = dap_chain_net_srv_order_continents_count();
if(a_num >= l_count)
return NULL;
return s_server_continents[a_num];
}
/**
* @brief dap_chain_net_srv_order_get_continent_num
*/
int8_t dap_chain_net_srv_order_continent_to_num(const char *a_continent_str)
{
int8_t l_count = dap_chain_net_srv_order_continents_count();
// convert to to upper case
char *l_continent_str = dap_strup(a_continent_str, -1);
for(int8_t i = 1; i < l_count; i++) {
// convert to to upper case
char *l_server_continents = dap_strup(s_server_continents[i], -1);
// compare strings in upper case
if(!dap_strcmp(l_continent_str, l_server_continents)) {
DAP_DELETE(l_server_continents);
DAP_DELETE(l_continent_str);
return i;
}
DAP_DELETE(l_server_continents);
}
DAP_DELETE(l_continent_str);
// none
return 0;
}
char * dap_chain_net_srv_order_create(
dap_chain_net_t * a_net,
dap_chain_net_srv_order_direction_t a_direction,
dap_chain_net_srv_uid_t a_srv_uid, // Service UID
dap_chain_node_addr_t a_node_addr, // Node address that servs the order (if present)
dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
uint256_t *a_price, // service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT for one unit.
dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
dap_time_t a_expires, // TS when the service expires
const uint8_t *a_ext,
uint32_t a_ext_size,
uint64_t a_units,
const char *a_region,
int8_t a_continent_num,
dap_enc_key_t *a_key
)
{
dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_compose(a_net, a_direction, a_srv_uid, a_node_addr, a_tx_cond_hash, a_price,
a_price_unit, a_price_ticker, a_expires, a_ext, a_ext_size, a_units,
a_region, a_continent_num, a_key);
if (!l_order)
return NULL;
char *l_ret = dap_chain_net_srv_order_save(a_net, l_order);
DAP_DELETE(l_order);
return l_ret;
}
dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose(dap_chain_net_t *a_net,
dap_chain_net_srv_order_direction_t a_direction,
dap_chain_net_srv_uid_t a_srv_uid, // Service UID
dap_chain_node_addr_t a_node_addr, // Node address that servs the order (if present)
dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
uint256_t *a_price, // service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT for one unit.
dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
dap_time_t a_expires, // TS when the service expires
const uint8_t *a_ext,
uint32_t a_ext_size,
uint64_t a_units,
const char *a_region,
int8_t a_continent_num,
dap_enc_key_t *a_key
)
{
UNUSED(a_expires);
// Order must have network & sign
if (!a_net) {
log_it(L_WARNING, "Order mast have a network");
return NULL;
}
if (!a_key) {
log_it(L_WARNING, "The key with which the order should be signed is not specified.");
return NULL;
}
dap_chain_net_srv_order_t *l_order;
if (a_ext_size) {
l_order = (dap_chain_net_srv_order_t *)DAP_NEW_Z_SIZE(void, sizeof(dap_chain_net_srv_order_t) + a_ext_size);
if (!l_order) {
log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
return NULL;
}
memcpy(l_order->ext_n_sign, a_ext, a_ext_size);
l_order->ext_size = a_ext_size;
}
else {
l_order = DAP_NEW_Z(dap_chain_net_srv_order_t);
if (!l_order) {
log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
return NULL;
}
dap_chain_net_srv_order_set_continent_region(&l_order, a_continent_num, a_region);
}
l_order->version = 3;
l_order->srv_uid = a_srv_uid;
l_order->direction = a_direction;
l_order->ts_created = dap_time_now();
if ( a_node_addr.uint64)
l_order->node_addr.uint64 = a_node_addr.uint64;
l_order->tx_cond_hash = a_tx_cond_hash;
l_order->price = *a_price;
l_order->price_unit.uint32 = a_price_unit.uint32;
if ( a_price_ticker)
strncpy(l_order->price_ticker, a_price_ticker, DAP_CHAIN_TICKER_SIZE_MAX - 1);
l_order->units = a_units;
dap_sign_t *l_sign = dap_sign_create(a_key, l_order, sizeof(dap_chain_net_srv_order_t) + l_order->ext_size, 0);
if (!l_sign) {
DAP_DELETE(l_order);
return NULL;
}
size_t l_sign_size = dap_sign_get_size(l_sign); // sign data
l_order = DAP_REALLOC(l_order, sizeof(dap_chain_net_srv_order_t) + l_order->ext_size + l_sign_size);
memcpy(l_order->ext_n_sign + l_order->ext_size, l_sign, l_sign_size);
return l_order;
}
/**
* @brief dap_chain_net_srv_order_update
* @param a_net
* @param a_order
* @return
*/
char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order)
{
if (!a_net || !a_order)
return NULL;
dap_chain_hash_fast_t l_order_hash;
size_t l_order_size = dap_chain_net_srv_order_get_size(a_order);
dap_hash_fast(a_order, l_order_size, &l_order_hash);
char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_order_hash);
char *l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(a_net);
if ( dap_global_db_set_sync( l_gdb_group_str,l_order_hash_str, a_order, l_order_size, false ) != 0) {
DAP_DELETE(l_gdb_group_str);
return NULL;
}
DAP_DELETE(l_gdb_group_str);
return l_order_hash_str;
}
dap_chain_net_srv_order_t *dap_chain_net_srv_order_read(byte_t *a_order, size_t a_order_size)
{
if (NULL == a_order) {
log_it(L_ERROR, "Argumets are NULL for dap_chain_net_srv_order_read");
return NULL;
}
dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)a_order;
size_t l_order_size = dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)a_order);
if (l_order->version > 3 || l_order->direction > SERV_DIR_SELL || l_order_size != a_order_size)
return NULL;
if (l_order->version == 3)
return DAP_DUP_SIZE(a_order, l_order_size);
dap_chain_net_srv_order_old_t *l_old = (dap_chain_net_srv_order_old_t *)a_order;
size_t l_ret_size = dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)l_old) +
sizeof(dap_chain_net_srv_order_t) - sizeof(dap_chain_net_srv_order_old_t);
if (l_old->version == 1)
l_ret_size += sizeof(dap_sign_type_t);
dap_chain_net_srv_order_t *l_ret = DAP_NEW_Z_SIZE(dap_chain_net_srv_order_t, l_ret_size);
l_ret->version = 3;
#if DAP_CHAIN_NET_SRV_UID_SIZE == 8
l_ret->srv_uid.uint64 = l_old->srv_uid.uint64;
#else
l_ret->srv_uid.uint128 = dap_chain_uint128_from(l_old->srv_uid.uint64);
#endif
l_ret->direction = l_old->direction;
l_ret->node_addr.uint64 = l_old->node_addr.uint64;
l_ret->tx_cond_hash = l_old->tx_cond_hash;
l_ret->price_unit.uint32 = l_old->price_unit.uint32;
l_ret->ts_created = l_old->ts_created;
l_ret->ts_expires = l_old->ts_expires;
l_ret->price = dap_chain_uint256_from(l_old->price);
strncpy(l_ret->price_ticker, l_old->price_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
l_ret->ext_size = l_old->ext_size;
memcpy(l_ret->ext_n_sign, l_old->ext, l_old->ext_size);
dap_sign_t *l_sign = (dap_sign_t *)&l_old->ext[l_old->ext_size];
size_t l_sign_size = l_old->version == 1 ? 0 : dap_sign_get_size(l_sign);
if (l_sign_size)
memcpy(l_ret->ext_n_sign + l_ret->ext_size, l_sign, l_sign_size);
else
((dap_sign_type_t *)(l_ret->ext_n_sign + l_ret->ext_size))->type = SIG_TYPE_NULL;
return l_ret;
}
/**
* @brief dap_chain_net_srv_order_find_by_hash_str
* @param a_net
* @param a_hash_str
* @return
*/
dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash_str(dap_chain_net_t * a_net, const char * a_hash_str)
{
dap_chain_net_srv_order_t * l_order = NULL;
if ( a_net && a_hash_str ){
char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net);
size_t l_order_size =0;
l_order = (dap_chain_net_srv_order_t *) dap_global_db_get_sync(l_gdb_group_str, a_hash_str, &l_order_size, NULL, NULL );
// check order size
if(l_order_size != dap_chain_net_srv_order_get_size(l_order)) {
log_it( L_ERROR, "Found wrong size order");
DAP_DELETE( l_order );
DAP_DELETE( l_gdb_group_str );
return NULL;
}
DAP_DELETE( l_gdb_group_str );
}
return l_order;
}
/**
* @brief dap_chain_net_srv_order_find_all_by
* @param a_net
* @param a_srv_uid
* @param a_srv_class
* @param a_price_unit
* @param a_price_min
* @param a_price_max
* @param a_output_orders
* @param a_output_orders_count
* @return
*/
int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_net_srv_order_direction_t a_direction,
const dap_chain_net_srv_uid_t a_srv_uid,
const dap_chain_net_srv_price_unit_uid_t a_price_unit,const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
const uint256_t a_price_min, const uint256_t a_price_max,
dap_chain_net_srv_order_t ** a_output_orders, size_t * a_output_orders_count)
{
if (!a_net || !a_output_orders || !a_output_orders_count)
return -1;
char *l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(a_net);
size_t l_orders_count = 0;
dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count);
log_it( L_DEBUG, "Loaded %zu orders", l_orders_count);
dap_chain_net_srv_order_t *l_order = NULL;
*a_output_orders = NULL;
size_t l_output_orders_count = 0;
size_t l_orders_size = 0;
for (size_t i = 0; i < l_orders_count; i++) {
DAP_DEL_Z(l_order);
l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len);
if (!l_order) {
dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key);
continue; // order is corrupted
}
dap_chain_hash_fast_t l_hash, l_hash_gdb;
dap_hash_fast(l_orders[i].value, l_orders[i].value_len, &l_hash);
dap_chain_hash_fast_from_str(l_orders[i].key, &l_hash_gdb);
if (memcmp(&l_hash, &l_hash_gdb, sizeof(dap_chain_hash_fast_t))) {
dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key);
continue; // order is corrupted
}
// Check direction
if (a_direction != SERV_DIR_UNDEFINED && l_order->direction != a_direction)
continue;
// Check srv uid
if (a_srv_uid.uint64 && l_order->srv_uid.uint64 != a_srv_uid.uint64)
continue;
// check price unit
if (a_price_unit.uint32 && a_price_unit.uint32 != l_order->price_unit.uint32)
continue;
// Check price minimum
if (!IS_ZERO_256(a_price_min) && compare256(l_order->price, a_price_min) == -1)
continue;
// Check price maximum
if (!IS_ZERO_256(a_price_max) && compare256(l_order->price, a_price_max) == 1)
continue;
// Check ticker
if (a_price_ticker && strcmp( l_order->price_ticker, a_price_ticker))
continue;
size_t l_order_mem_size = dap_chain_net_srv_order_get_size(l_order);
*a_output_orders = DAP_REALLOC(*a_output_orders, l_orders_size + l_order_mem_size);
memcpy((byte_t *)*a_output_orders + l_orders_size, l_order, l_order_mem_size);
l_orders_size += l_order_mem_size;
l_output_orders_count++;
}
*a_output_orders_count = l_output_orders_count;
DAP_DEL_Z(l_order);
dap_global_db_objs_delete(l_orders, l_orders_count);
DAP_DELETE(l_gdb_group_str);
return 0;
}
/**
* @brief dap_chain_net_srv_order_delete_by_hash_str
* @param a_net
* @param a_hash_str
* @return
*/
int dap_chain_net_srv_order_delete_by_hash_str_sync(dap_chain_net_t * a_net, const char * a_hash_str )
{
int l_ret = -2;
if ( a_net && a_hash_str ){
char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net);
l_ret = dap_global_db_del_sync( l_gdb_group_str, a_hash_str) ;
DAP_DELETE( l_gdb_group_str );
}
return l_ret;
}
/**
* @brief dap_chain_net_srv_order_dump_to_string
* @param a_orders
* @param a_str_out
*/
void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,dap_string_t * a_str_out, const char *a_hash_out_type)
{
if (a_order && a_str_out ){
dap_chain_hash_fast_t l_hash;
dap_hash_fast(a_order, dap_chain_net_srv_order_get_size(a_order), &l_hash);
char *l_hash_str = dap_strcmp(a_hash_out_type,"hex")
? dap_enc_base58_encode_hash_to_str(&l_hash)
: dap_chain_hash_fast_to_str_new(&l_hash);
dap_string_append_printf(a_str_out, "== Order %s ==\n", l_hash_str);
dap_string_append_printf(a_str_out, " version: %u\n", a_order->version );
switch ( a_order->direction) {
case SERV_DIR_UNDEFINED: dap_string_append_printf(a_str_out, " direction: SERV_DIR_UNDEFINED\n" ); break;
case SERV_DIR_SELL: dap_string_append_printf(a_str_out, " direction: SERV_DIR_SELL\n" ); break;
case SERV_DIR_BUY: dap_string_append_printf(a_str_out, " direction: SERV_DIR_BUY\n" ); break;
}
dap_string_append_printf(a_str_out, " srv_uid: 0x%016"DAP_UINT64_FORMAT_X"\n", a_order->srv_uid.uint64 );
char *l_balance_coins = dap_chain_balance_to_coins(a_order->price);
char *l_balance = dap_chain_balance_print(a_order->price);
dap_string_append_printf(a_str_out, " price: %s (%s)\n", l_balance_coins, l_balance);
DAP_DELETE(l_balance_coins);
DAP_DELETE(l_balance);
if( a_order->price_unit.uint32 )
dap_string_append_printf(a_str_out, " price_unit: %s\n", dap_chain_net_srv_price_unit_uid_to_str(a_order->price_unit) );
if ( a_order->node_addr.uint64)
dap_string_append_printf(a_str_out, " node_addr: "NODE_ADDR_FP_STR"\n", NODE_ADDR_FP_ARGS_S(a_order->node_addr) );
char *l_region = NULL;
uint8_t l_continent_num = 0;
const char *l_continent_str = NULL;
if(dap_chain_net_srv_order_get_continent_region(a_order, &l_continent_num, &l_region))
l_continent_str = dap_chain_net_srv_order_continent_to_str(l_continent_num);
dap_string_append_printf(a_str_out, " node_location: %s - %s\n", l_continent_str ? l_continent_str : "None" , l_region ? l_region : "None");
DAP_DELETE(l_region);
DAP_DELETE(l_hash_str);
l_hash_str = dap_strcmp(a_hash_out_type, "hex")
? dap_enc_base58_encode_hash_to_str(&a_order->tx_cond_hash)
: dap_chain_hash_fast_to_str_new(&a_order->tx_cond_hash);
dap_string_append_printf(a_str_out, " tx_cond_hash: %s\n", l_hash_str );
char *l_ext_out = a_order->ext_size ? DAP_NEW_Z_SIZE(char, a_order->ext_size * 2 + 1) : NULL;
if(l_ext_out) {
dap_bin2hex(l_ext_out, a_order->ext_n_sign, a_order->ext_size);
dap_string_append_printf(a_str_out, " ext: 0x%s\n", l_ext_out);
}
else
dap_string_append_printf(a_str_out, " ext: 0x0\n");
dap_sign_t *l_sign = (dap_sign_t*)((byte_t*)a_order->ext_n_sign + a_order->ext_size);
dap_hash_fast_t l_sign_pkey = {0};
dap_sign_get_pkey_hash(l_sign, &l_sign_pkey);
char *l_sign_pkey_hash_str = dap_hash_fast_to_str_new(&l_sign_pkey);
dap_string_append_printf(a_str_out, " pkey: %s\n", l_sign_pkey_hash_str);
dap_string_append_printf(a_str_out, " units: %zu\n", a_order->units);
DAP_DELETE(l_sign_pkey_hash_str);
// order state
/* {
int l_order_state = get_order_state(a_order->node_addr);
// if order is not tested
if(l_order_state == -1)
dap_string_append_printf(a_str_out, " \"State\":\"unknown\"\n");
// if order off-line
else if(l_order_state == 1)
dap_string_append_printf(a_str_out, " \"State\":\"available\"\n");
// if order on-line
else
dap_string_append_printf(a_str_out, " \"State\":\"not available\"\n");
}*/
DAP_DELETE(l_hash_str);
DAP_DELETE(l_ext_out);
}
}
static void s_srv_order_callback_notify(dap_global_db_context_t *a_context, dap_store_obj_t *a_obj, void *a_arg)
{
if (!a_arg || !a_obj || !a_obj->key)
return;
dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
dap_global_db_context_t * l_gdb_context = dap_global_db_context_current();
assert(l_net);
assert(l_gdb_context);
char *l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(l_net);
if (!dap_strcmp(a_obj->group, l_gdb_group_str)) {
for (dap_list_t *it = s_order_notify_callbacks; it; it = it->next) {
struct dap_order_notify *l_notifier = (struct dap_order_notify *)it->data;
if ((l_notifier->net == NULL || l_notifier->net == l_net) &&
l_notifier->callback) {
l_notifier->callback(a_context, a_obj, l_notifier->cb_arg);
}
}
bool l_allow_unsigned_orders = dap_config_get_item_bool_default(g_config, "srv", "allow_unsigned_orders", false);
if (a_obj->value && a_obj->type == DAP_DB$K_OPTYPE_ADD) {
dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)a_obj->value;
if (l_order->version != 3) {
log_it(L_NOTICE, "Order %s removed version != 3.", a_obj->key);
dap_global_db_del_unsafe(l_gdb_context, a_obj->group, a_obj->key);
} else {
if (l_allow_unsigned_orders) {
log_it(L_DEBUG, "The mode that disables verification of the order signature is enabled.");
} else {
dap_sign_t *l_sign = (dap_sign_t *) (l_order->ext_n_sign + l_order->ext_size);
size_t l_max_size = a_obj->value_len - sizeof(dap_chain_net_srv_order_t) - l_order->ext_size;
int l_verify = dap_sign_verify_all(l_sign, l_max_size, l_order,
sizeof(dap_chain_net_srv_order_t) + l_order->ext_size);
if (l_verify) {
log_it(L_ERROR, "Order unverified, err %d", l_verify);
dap_global_db_del_unsafe(l_gdb_context, a_obj->group, a_obj->key);
}
}
}
}
}
DAP_DELETE(l_gdb_group_str);
}
void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg)
{
struct dap_order_notify *l_notifier = DAP_NEW(struct dap_order_notify);
if (!l_notifier) {
log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
return;
}
l_notifier->net = a_net;
l_notifier->callback = a_callback;
l_notifier->cb_arg = a_cb_arg;
s_order_notify_callbacks = dap_list_append(s_order_notify_callbacks, l_notifier);
}