Newer
Older
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* Alexander Lysikov <alexander.lysikov@demlabs.net>
* Kelvin Project https://github.com/kelvinblockchain
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 <string.h>
#include <stdbool.h>
#include <errno.h>
#ifdef WIN32
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#include <winsock2.h>
#include <windows.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <io.h>
#include <wepoll.h>
#include <pthread.h>
#else
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include "uthash.h"
#include "utlist.h"
#include "dap_string.h"
#include "dap_chain_common.h"
#include "dap_strfuncs.h"
#include "dap_list.h"
#include "dap_string.h"
#include "dap_chain_node.h"
#include "dap_chain_global_db.h"
#include "dap_chain_node_cli_cmd.h"
#include "dap_chain_datum_tx_items.h"
#include "dap_chain_global_db.h"
#include "dap_chain_global_db_remote.h"
#include "dap_stream_ch_chain_net.h"
#include "dap_stream_ch_chain.h"
#include "dap_stream_ch_chain_pkt.h"
#include "dap_stream_ch_chain_net_pkt.h"
/**
* Find in base addr by alias
*
* return addr, NULL if not found
*/
dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias( dap_chain_net_t * a_net, const char *a_alias)
dap_chain_node_addr_t *l_addr = NULL;
if(!a_alias)
const char *a_key = a_alias;
l_addr = (dap_chain_node_addr_t*) (void*) dap_chain_global_db_gr_get(a_key, &l_addr_size, a_net->pub.gdb_nodes_aliases);
if(l_addr_size != sizeof(dap_chain_node_addr_t)) {
// l_addr = DAP_NEW_Z(dap_chain_node_addr_t);
// if(hex2bin((char*) l_addr, (const unsigned char *) addr_str, sizeof(dap_chain_node_addr_t) * 2) == -1) {
DAP_DELETE(l_addr);
// l_addr = NULL;
// }
// DAP_DELETE(addr_str);
return l_addr;
* return list of addr, NULL if not found
static dap_list_t* get_aliases_by_name(dap_chain_net_t * l_net, dap_chain_node_addr_t *a_addr)
dap_list_t *list_aliases = NULL;
size_t data_size = 0;
// read all aliases
dap_global_db_obj_t *objs = dap_chain_global_db_gr_load(l_net->pub.gdb_nodes_aliases, &data_size);
for(size_t i = 0; i < data_size; i++) {
//dap_chain_node_addr_t addr_i;
dap_chain_node_addr_t *l_addr = (dap_chain_node_addr_t*) (void*) obj->value;
if(l_addr && obj->value_len == sizeof(dap_chain_node_addr_t) && a_addr->uint64 == l_addr->uint64) {
list_aliases = dap_list_prepend(list_aliases, strdup(obj->key));
}
dap_chain_global_db_objs_delete(objs, data_size);
static dap_chain_node_addr_t* node_info_get_addr(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info,
dap_chain_node_addr_t *a_addr, const char *a_alias_str)
dap_chain_node_addr_t *l_address = NULL;
if(a_alias_str && !a_addr->uint64) {
l_address = dap_chain_node_addr_get_by_alias(a_net, a_alias_str);
if(a_addr->uint64) {
l_address = DAP_NEW(dap_chain_node_addr_t);
l_address->uint64 = a_addr->uint64;
static dap_chain_node_info_t* node_info_read_and_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_address, char **a_str_reply)
char *l_key = dap_chain_node_addr_to_hash_str(a_address);
dap_chain_node_cli_set_reply_text(a_str_reply, "can't calculate hash of addr");
size_t node_info_size = 0;
dap_chain_node_info_t *node_info;
node_info = (dap_chain_node_info_t *) dap_chain_global_db_gr_get(l_key, &node_info_size, a_net->pub.gdb_nodes);
dap_chain_node_cli_set_reply_text(a_str_reply, "node not found in base");
size_t node_info_size_must_be = dap_chain_node_info_get_size(node_info);
if(node_info_size_must_be != node_info_size) {
dap_chain_node_cli_set_reply_text(a_str_reply, "node has bad size in base=%u (must be %u)", node_info_size,
DAP_DELETE(node_info);
DAP_DELETE(l_key);
return NULL;
// dap_chain_node_info_t *node_info = dap_chain_node_info_deserialize(str, (str) ? strlen(str) : 0);
// if(!node_info) {
// set_reply_text(str_reply, "node has invalid format in base");
// }
// DAP_DELETE(str);
DAP_DELETE(l_key);
static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *node_info, char **str_reply)
{
if(!node_info || !node_info->hdr.address.uint64) {
dap_chain_node_cli_set_reply_text(str_reply, "node addr not found");
char *a_key = dap_chain_node_addr_to_hash_str(&node_info->hdr.address);
dap_chain_node_cli_set_reply_text(str_reply, "can't calculate hash for addr");
//char *a_value = dap_chain_node_info_serialize(node_info, NULL);
size_t node_info_size = dap_chain_node_info_get_size(node_info);
bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t *) node_info, node_info_size,a_net->pub.gdb_nodes);
//DAP_DELETE(a_value);
/**
* Handler of command 'global_db node add'
*
* str_reply[out] for reply
* return 0 Ok, -1 error
*/
static int node_info_add_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *a_alias_str,
const char *a_cell_str, const char *a_ipv4_str, const char *a_ipv6_str, char **a_str_reply)
if(!a_node_info->hdr.address.uint64) {
dap_chain_node_cli_set_reply_text(a_str_reply, "not found -addr parameter");
if(!a_cell_str) {
dap_chain_node_cli_set_reply_text(a_str_reply, "not found -cell parameter");
if(a_ipv4_str)
inet_pton(AF_INET, a_ipv4_str, &(a_node_info->hdr.ext_addr_v4));
if(a_ipv6_str)
inet_pton(AF_INET6, a_ipv6_str, &(a_node_info->hdr.ext_addr_v6));
// check match addr to cell or no
/*dap_chain_node_addr_t *addr = dap_chain_node_gen_addr(&node_info->hdr.cell_id);
if(!dap_chain_node_check_addr(&node_info->hdr.address, &node_info->hdr.cell_id)) {
set_reply_text(str_reply, "cell does not match addr");
if(!dap_chain_node_alias_register( a_net, a_alias_str, &a_node_info->hdr.address)) {
log_it(L_WARNING, "can't save alias %s", a_alias_str);
dap_chain_node_cli_set_reply_text(a_str_reply, "alias '%s' can't be mapped to addr=0x%lld",
a_alias_str, a_node_info->hdr.address.uint64);
bool res = node_info_save_and_reply(a_net,a_node_info, a_str_reply);
dap_chain_node_cli_set_reply_text(a_str_reply, "node added");
if(res)
return 0;
return -1;
}
/**
* Handler of command 'global_db node add'
*
* str_reply[out] for reply
* return 0 Ok, -1 error
*/
static int node_info_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *alias_str, char **str_reply)
if(!a_node_info->hdr.address.uint64 && !alias_str) {
dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
// check, current node have this addr or no
uint64_t l_cur_addr = dap_db_get_cur_node_addr();
if(l_cur_addr && l_cur_addr == a_node_info->hdr.address.uint64) {
dap_chain_node_cli_set_reply_text(str_reply, "current node cannot be deleted");
dap_chain_node_addr_t *address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, alias_str);
dap_chain_node_cli_set_reply_text(str_reply, "alias not found");
char *a_key = dap_chain_node_addr_to_hash_str(address);
bool res = dap_chain_global_db_gr_del(a_key, a_net->pub.gdb_nodes);
if(res) {
// delete all aliases for node address
{
dap_list_t *list_aliases = get_aliases_by_name(a_net, address);
dap_list_t *list = list_aliases;
while(list)
{
const char *alias = (const char *) list->data;
dap_chain_node_alias_delete(a_net, alias);
dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
dap_chain_node_cli_set_reply_text(str_reply, "node deleted");
dap_chain_node_cli_set_reply_text(str_reply, "node not deleted");
dap_chain_node_cli_set_reply_text(str_reply, "addr to delete can't be defined");
DAP_DELETE(address);
return -1;
}
/**
* Handler of command 'global_db node link'
*
* str_reply[out] for reply
* return 0 Ok, -1 error
*/
static int link_add_or_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *cmd, const char *a_alias_str,
dap_chain_node_addr_t *link, char **a_str_reply)
if(!a_node_info->hdr.address.uint64 && !a_alias_str) {
dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
return -1;
}
if(!link->uint64) {
dap_chain_node_cli_set_reply_text(a_str_reply, "link not found");
return -1;
}
// TODO check the presence of link in the node base
if(0) {
dap_chain_node_cli_set_reply_text(a_str_reply, "node 0x%016llx not found in base", link->uint64);
// find addr by alias or addr_str
dap_chain_node_addr_t *l_address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, a_alias_str);
if(!l_address) {
dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
dap_chain_node_info_t * l_node_info_read = node_info_read_and_reply(a_net, l_address, a_str_reply);
size_t l_node_info_read_size = dap_chain_node_info_get_size(l_node_info_read);
if(!l_node_info_read)
return -1;
int cmd_int = 0;
if(!strcmp(cmd, "add"))
cmd_int = 1;
else if(!strcmp(cmd, "del"))
cmd_int = 2;
// find link in node_info_read
int index_link = -1;
for(size_t i = 0; i < l_node_info_read->hdr.links_number; i++) {
if(l_node_info_read->links[i].uint64 == link->uint64) {
bool res_successful = false; // is successful whether add/del
// add link
if(cmd_int == 1) {
if(index_link == -1) {
l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size += sizeof(*link));
memcpy(&(l_node_info_read->links[l_node_info_read->hdr.links_number]), link, sizeof(dap_chain_node_addr_t));
l_node_info_read->hdr.links_number++;
res_successful = true;
}
}
// delete link
else if(cmd_int == 2) {
// move link list to one item prev
if(index_link >= 0) {
for(unsigned int j = (unsigned int) index_link; j < (l_node_info_read->hdr.links_number - 1); j++) {
memcpy(&(l_node_info_read->links[j]), &(l_node_info_read->links[j + 1]), sizeof(dap_chain_node_addr_t));
l_node_info_read->hdr.links_number--;
l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size -= sizeof(*link));
}
}
// save edited node_info
if(res_successful) {
bool res = node_info_save_and_reply(a_net, l_node_info_read, a_str_reply);
if(res) {
res_successful = true;
if(cmd_int == 1)
dap_chain_node_cli_set_reply_text(a_str_reply, "link added");
dap_chain_node_cli_set_reply_text(a_str_reply, "link deleted");
else {
res_successful = false;
}
else {
if(cmd_int == 1) {
if(index_link >= 0)
dap_chain_node_cli_set_reply_text(a_str_reply, "link not added because it is already present");
dap_chain_node_cli_set_reply_text(a_str_reply, "link not added");
}
if(cmd_int == 2) {
if(index_link == -1)
dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted because not found");
dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted");
DAP_DELETE(l_address);
return -1;
}
/**
* Handler of command 'global_db node dump'
*
* str_reply[out] for reply
* return 0 Ok, -1 error
*/
static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t * a_addr, const char *a_alias, char **a_str_reply)
int l_ret = 0;
dap_string_t *l_string_reply = dap_string_new("Node dump:\n");
if( (a_addr && a_addr->uint64 ) || a_alias) {
dap_chain_node_addr_t *l_addr;
if (a_addr && a_addr->uint64){
l_addr = DAP_NEW(dap_chain_node_addr_t);
l_addr->uint64 = a_addr->uint64;
} else if (a_alias) {
l_addr = dap_chain_node_alias_find(a_net,a_alias);
}
if ( l_addr ) {
}
}else { // Dump list
dap_global_db_obj_t **l_objs = NULL;
size_t l_nodes_count = 0;
dap_chain_node_info_t *l_node_info;
l_objs = dap_chain_global_db_gr_load( a_net->pub.gdb_nodes, &l_nodes_count);
if(!l_nodes_count || !l_objs) {
dap_string_append_printf(l_string_reply, "No records\n");
l_ret = -1;
}else {
dap_string_append_printf(l_string_reply,"Got %u records:\n",l_nodes_count);
for(size_t i = 0; i < l_nodes_count; i++) {
dap_chain_node_info_t *node_info = (dap_chain_node_info_t *) l_objs[i]->value;
// find addr by alias or addr_str
dap_chain_node_addr_t *address = node_info_get_addr(a_net, node_info, &node_info->hdr.address, a_alias);
if(!address) {
dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
break;
}
// read node
dap_chain_node_info_t *node_info_read = node_info_read_and_reply( a_net, address, a_str_reply);
if(!node_info_read) {
DAP_DELETE(address);
break;
}
const int hostlen = 128;
char *host4 = (char*) alloca(hostlen);
char *host6 = (char*) alloca(hostlen);
struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info_read->hdr.ext_addr_v4 };
const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, hostlen);
struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info_read->hdr.ext_addr_v6 };
const char* str_ip6 = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host6, hostlen);
// get aliases in form of string
dap_string_t *aliases_string = dap_string_new(NULL);
dap_list_t *list_aliases = get_aliases_by_name(a_net,address);
if(list_aliases)
{
dap_list_t *list = list_aliases;
while(list)
{
const char *alias = (const char *) list->data;
dap_string_append_printf(aliases_string, "\nalias %s", alias);
list = dap_list_next(list);
}
dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
}
else
dap_string_append(aliases_string, "\nno aliases");
// get links in form of string
dap_string_t *links_string = dap_string_new(NULL);
for(unsigned int i = 0; i < node_info_read->hdr.links_number; i++) {
dap_chain_node_addr_t link_addr = node_info_read->links[i];
dap_string_append_printf(links_string, "\nlink%02d address : " NODE_ADDR_FP_STR, i,
NODE_ADDR_FP_ARGS_S(link_addr) );
if(i)
dap_string_append_printf(l_string_reply, "\n");
// set short reply with node param
if(l_objs)
dap_string_append_printf(l_string_reply,
"node address "NODE_ADDR_FP_STR"\tcell 0x%016llx\tipv4 %s\tnumber of links %u",
NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
node_info_read->hdr.cell_id.uint64, str_ip4,
node_info_read->hdr.links_number);
else
// set full reply with node param
dap_string_append_printf(l_string_reply,
"node address " NODE_ADDR_FP_STR "\ncell 0x%016llx%s\nipv4 %s\nipv6 %s\nlinks %u%s",
NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address),
node_info_read->hdr.cell_id.uint64,
str_ip4, str_ip6, aliases_string->str,
node_info_read->hdr.links_number, links_string->str);
dap_string_free(aliases_string, true);
dap_string_free(links_string, true);
DAP_DELETE(address);
DAP_DELETE(node_info_read);
}
dap_chain_node_cli_set_reply_text(a_str_reply, l_string_reply->str);
dap_string_free(l_string_reply, true);
/**
* global_db command
*
* return 0 OK, -1 Err
*/
int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
CMD_NONE, CMD_ADD, CMD_DEL, CMD_LINK };
//printf("com_global_db\n");
arg_index = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "node", NULL);
if(!arg_index || a_argc < 3) {
dap_chain_node_cli_set_reply_text(a_str_reply, "parameters are not valid");
dap_chain_net_t * l_net = NULL;
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, a_argc, a_argv, a_str_reply, NULL, &l_net) < 0)
return -11;
// find command (add, delete, etc) as second parameter only
if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del",
NULL))
else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "link",
NULL))
dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
//arg_index = arg_index_n; // no need, they are already equal must be
assert(arg_index == arg_index_n);
arg_index++;
const char *l_addr_str = NULL, *alias_str = NULL, *l_cell_str = NULL, *l_link_str = NULL;
const char *a_ipv4_str = NULL, *a_ipv6_str = NULL;
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-cell", &l_cell_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv4", &a_ipv4_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv6", &a_ipv6_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-link", &l_link_str);
dap_chain_node_info_t *l_node_info;
size_t l_node_info_size = sizeof(l_node_info->hdr) + sizeof(l_link);
l_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, l_node_info_size);
dap_digit_from_string(l_addr_str, l_node_info->hdr.address.raw, sizeof(l_node_info->hdr.address.raw));
if(l_cell_str) {
dap_digit_from_string(l_cell_str, l_node_info->hdr.cell_id.raw, sizeof(l_node_info->hdr.cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
if(l_link_str) {
dap_digit_from_string(l_link_str, l_link.raw, sizeof(l_link.raw));
if(!arg_index || a_argc < 8) {
dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameters");
// handler of command 'global_db node add'
return node_info_add_with_reply(l_net,l_node_info, alias_str, l_cell_str, a_ipv4_str, a_ipv6_str, a_str_reply);
return node_info_del_with_reply(l_net,l_node_info, alias_str, a_str_reply);
if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
// handler of command 'global_db node link add -addr <node address> -link <node address>'
return link_add_or_del_with_reply(l_net, l_node_info, "add", alias_str, &l_link, a_str_reply);
else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del", NULL))
// handler of command 'global_db node link del -addr <node address> -link <node address>'
return link_add_or_del_with_reply(l_net, l_node_info, "del", alias_str, &l_link, a_str_reply);
dap_chain_node_cli_set_reply_text(a_str_reply, "command not recognize, supported format:\n"
"global_db node link <add|del] [-addr <node address> | -alias <node alias>] -link <node address>");
dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
}
}
/**
* Node command
*/
int com_node(int a_argc, char ** a_argv, char **a_str_reply)
CMD_NONE, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT , CMD_DUMP
};
int arg_index = 1;
int cmd_num = CMD_NONE;
const char *cmd_str = NULL;
// find add parameter ('alias' or 'handshake')
if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "handshake", NULL)) {
else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "connect", NULL)) {
else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "alias", NULL)) {
else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "dump", NULL)) {
cmd_num = CMD_DUMP;
}
dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
dap_chain_node_addr_t l_node_addr={0};
const char *l_addr_str = NULL, *alias_str = NULL;
const char * l_net_str = NULL;
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
if (l_addr_str)
if ( dap_chain_node_addr_from_str(&l_node_addr,l_addr_str) != 0 )
dap_digit_from_string(l_addr_str, l_node_addr.raw, sizeof(l_node_addr.raw));
dap_chain_node_cli_set_reply_text(a_str_reply, "No -net <net name> option in command %s", a_argv[1]);
return -11;
}
dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_str);
dap_chain_node_cli_set_reply_text(a_str_reply, "%s: Can't find such network %s", a_argv[1], l_net_str);
return -12;
}
case CMD_DUMP:{
// handler of command 'global_db node dump'
return node_info_dump_with_reply(l_net, &l_node_addr , alias_str, a_str_reply);
}
// add alias
case CMD_ALIAS:
if(alias_str) {
if(!dap_chain_node_alias_register(l_net, alias_str, &l_node_addr))
log_it(L_WARNING, "can't save alias %s", alias_str);
dap_chain_node_cli_set_reply_text(a_str_reply, "alias mapped successfully");
dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -addr is not found");
dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -alias is not found");
break;
// make connect
case CMD_CONNECT: {
// get address from alias if addr not defined
if(alias_str && !l_node_addr.uint64) {
dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net, alias_str);
memcpy(&l_node_addr, address_tmp, sizeof(*address_tmp));
dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
if(!l_node_addr.uint64) {
dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
dap_chain_node_info_t *l_remote_node_info = node_info_read_and_reply(l_net, &l_node_addr, a_str_reply);
if(!l_remote_node_info) {
return -1;
}
// start connect
dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(l_remote_node_info);
if(!l_node_client) {
dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
DAP_DELETE(l_remote_node_info);
return -1;
}
// wait connected
int timeout_ms = 5000; //5 sec = 5000 ms
int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
if(res ) {
dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node: code %d",res);
// clean client struct
dap_chain_node_client_close(l_node_client);
DAP_DELETE(l_remote_node_info);
return -1;
}
log_it(L_NOTICE, "Stream connection established, now lets sync all");
dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
dap_stream_ch_t * l_ch_chain = dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id());
// fill begin id
l_sync_request.id_start = (uint64_t) dap_db_log_get_last_id_remote(
// fill end id = 0 - no time limit
//l_sync_request.ts_end = 0;
l_sync_request.node_addr.uint64 =
dap_chain_net_get_cur_addr(l_net) ? dap_chain_net_get_cur_addr(l_net)->uint64 :
dap_db_get_cur_node_addr();
dap_chain_id_t l_chain_id_null = { { 0 } };
dap_chain_cell_id_t l_chain_cell_id_null = { { 0 } };
l_chain_id_null.uint64 = l_net->pub.id.uint64;
l_chain_cell_id_null.uint64 = dap_chain_net_get_cur_cell(l_net) ? dap_chain_net_get_cur_cell(l_net)->uint64 : 0;
log_it(L_INFO, "Requested GLOBAL_DB syncronizatoin, %llu:%llu period", l_sync_request.id_start,
l_sync_request.id_end);
// copy l_sync_request to current
//dap_stream_ch_chain_t * l_s_ch_chain = DAP_STREAM_CH_CHAIN(l_ch_chain);
//l_s_ch_chain->request_net_id.uint64 = l_net->pub.id.uint64;
//l_s_ch_chain->request_cell_id.uint64 = l_chain_cell_id_null.uint64;
//memcpy(&l_s_ch_chain->request, &l_sync_request, sizeof(l_sync_request));
if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB,
l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
sizeof(l_sync_request))) {
dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
// clean client struct
dap_chain_node_client_close(l_node_client);
DAP_DELETE(l_remote_node_info);
return -1;
}
dap_stream_ch_set_ready_to_write(l_ch_chain, true);
// wait for finishing of request
timeout_ms = 120000; // 20 min = 1200 sec = 1 200 000 ms
// TODO add progress info to console
res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
if ( res <0 ){
dap_chain_node_client_close(l_node_client);
DAP_DELETE(l_remote_node_info);
dap_chain_node_cli_set_reply_text(a_str_reply, "Error: can't sync with node "NODE_ADDR_FP_STR,
NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
return -2;
// Requesting chains
dap_chain_t *l_chain = NULL;
DL_FOREACH(l_net->pub.chains, l_chain)
{
// send request
dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
l_net->pub.id, l_chain->id, l_remote_node_info->hdr.cell_id, &l_sync_request,
sizeof(l_sync_request))) {
dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
// clean client struct
dap_chain_node_client_close(l_node_client);
DAP_DELETE(l_remote_node_info);
log_it(L_NOTICE, "Requested syncronization for chain \"%s\"", l_chain->name);
dap_stream_ch_set_ready_to_write(l_ch_chain, true);
// wait for finishing of request
timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
// TODO add progress info to console
res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
}
log_it(L_INFO, "Chains and gdb are synced");
DAP_DELETE(l_remote_node_info);
dap_client_disconnect(l_node_client->client);
l_node_client->client = NULL;
//dap_chain_node_client_close(l_node_client);
dap_chain_node_cli_set_reply_text(a_str_reply, "Node sync completed: Chains and gdb are synced");
}
// make handshake
case CMD_HANDSHAKE: {
// get address from alias if addr not defined
if(alias_str && !l_node_addr.uint64) {
dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net,alias_str);
memcpy(&l_node_addr, address_tmp, sizeof(*address_tmp));
dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
if(!l_node_addr.uint64) {
dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
dap_chain_node_info_t *node_info = node_info_read_and_reply(l_net,&l_node_addr, a_str_reply);
int timeout_ms = 10000; //10 sec = 10000 ms
// start handshake
dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
if(!client) {
dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
}
// wait handshake
int res = dap_chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
if(res != 1) {
dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node");
// clean client struct
dap_chain_node_client_close(client);
DAP_DELETE(node_info);
//Add new established connection in the list
int ret = dap_chain_node_client_list_add(&l_node_addr, client);
switch (ret)
{
case -1:
dap_chain_node_client_close(client);
dap_chain_node_cli_set_reply_text(a_str_reply, "connection established, but not saved");
case -2:
dap_chain_node_client_close(client);
dap_chain_node_cli_set_reply_text(a_str_reply, "connection already present");
dap_chain_node_cli_set_reply_text(a_str_reply, "connection established");
return 0;
}
/**
* Traceroute command
*
* return 0 OK, -1 Err
*/
int com_traceroute(int argc, char** argv, char **str_reply)
const char *addr = NULL;
int hops = 0, time_usec = 0;
if(argc > 1)
addr = argv[1];
iputils_set_verbose();
int res = (addr) ? traceroute_util(addr, &hops, &time_usec) : -EADDRNOTAVAIL;
if(res >= 0) {
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s hops=%d time=%.1lf ms", addr, hops,
time_usec * 1. / 1000);
}
else {
if(str_reply) {
switch (-res)
{
case EADDRNOTAVAIL:
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", (addr) ? addr : "",
(addr) ? "Name or service not known" : "Host not defined");
break;
case 2:
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"Unknown traceroute module");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "first hop out of range");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"max hops cannot be more than 255");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"no more than 10 probes per hop");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"bad wait specifications");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "too big packetlen ");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"IP version mismatch in addresses specified");
break;
case 9:
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "bad sendtime");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "init_ip_options");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "calloc");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "parse cmdline");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
"trace method's init failed");
dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error(%d) %s", addr, res,
"trace not found");
}
/**
* Tracepath command
*
* return 0 OK, -1 Err
*/
int com_tracepath(int argc, char** argv, char **str_reply)
const char *addr = NULL;
int hops = 0, time_usec = 0;
if(argc > 1)
addr = argv[1];
iputils_set_verbose();
int res = (addr) ? tracepath_util(addr, &hops, &time_usec) : -EADDRNOTAVAIL;
if(res >= 0) {
if(str_reply)
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s hops=%d time=%.1lf ms", addr, hops,
time_usec * 1. / 1000);
}
else {
if(str_reply) {
switch (-res)
{
case EADDRNOTAVAIL:
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", (addr) ? addr : "",
(addr) ? "Name or service not known" : "Host not defined");
break;
case ESOCKTNOSUPPORT:
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't create socket");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IPV6_MTU_DISCOVER");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IPV6_RECVERR");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IPV6_HOPLIMIT");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IP_MTU_DISCOVER");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IP_RECVERR");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IP_RECVTTL");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "malloc");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
"Can't setsockopt IPV6_UNICAST_HOPS");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_TTL");
dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error(%d) %s", addr, res, "trace not found");
}
/**
* Ping command
*
* return 0 OK, -1 Err
*/
int com_ping(int argc, char** argv, char **str_reply)
dap_chain_node_cli_set_reply_text(str_reply, "host not specified");
int argc_host = 1;
int argc_start = 1;
argc_start = dap_chain_node_cli_find_option_val(argv, argc_start, argc, "-n", &n_str);
if(argc_start) {
argc_host = argc_start + 1;
argc_start = dap_chain_node_cli_find_option_val(argv, argc_start, argc, "-c", &n_str);
if(argc_start) {
argc_host = argc_start + 1;
n = (n_str) ? atoi(n_str) : 4;
}
}
const char *addr = argv[argc_host];
iputils_set_verbose();
int res = (addr) ? ping_util(addr, n) : -EADDRNOTAVAIL;
if(res >= 0) {
if(str_reply)
dap_chain_node_cli_set_reply_text(str_reply, "ping %s time=%.1lf ms", addr, res * 1. / 1000);
}
else {
if(str_reply) {
switch (-res)
{
case EDESTADDRREQ:
dap_chain_node_cli_set_reply_text(str_reply, "ping %s error: %s", addr, "Destination address required");
dap_chain_node_cli_set_reply_text(str_reply, "ping %s error: %s", (addr) ? addr : "",
(addr) ? "Host not found" : "Host not defined");
break;
case EPFNOSUPPORT:
dap_chain_node_cli_set_reply_text(str_reply, "ping %s error: %s", addr, "Unknown protocol family");
dap_chain_node_cli_set_reply_text(str_reply, "ping %s error(%d)", addr, -res);
}
/**
* Help command
*/
int com_help(int argc, char ** argv, char **str_reply)
log_it(L_DEBUG, "Help for command %s", argv[1]);
dap_chain_node_cmd_item_t *l_cmd = dap_chain_node_cli_cmd_find(argv[1]);
dap_chain_node_cli_set_reply_text(str_reply, "%s:\n%s", l_cmd->doc, l_cmd->doc_ex);
dap_chain_node_cli_set_reply_text(str_reply, "command \"%s\" not recognized", argv[1]);
return -1;
// TODO Read list of commands & return it
log_it(L_DEBUG, "General help requested");
dap_string_t * l_help_list_str = dap_string_new(NULL);
dap_chain_node_cmd_item_t *l_cmd = dap_chain_node_cli_cmd_get_first();
dap_string_printf(l_help_list_str, "");
while(l_cmd) {
dap_string_append_printf(l_help_list_str, "%s:\t\t\t%s\n",
l_cmd->name, l_cmd->doc ? l_cmd->doc : "(undocumented command)");
l_cmd = (dap_chain_node_cmd_item_t*) l_cmd->hh.next;
}
dap_chain_node_cli_set_reply_text(str_reply,
"Available commands:\n\n%s\n",
l_help_list_str->len ? l_help_list_str->str : "NO ANY COMMAND WERE DEFINED");
}
return -1;
}
/**
* com_tx_create command
*
int com_tx_wallet(int argc, char ** argv, char **str_reply)
const char *c_wallets_path = dap_config_get_item_str(g_config, "general", "wallets_path");
// Get address of wallet
enum {
CMD_NONE, CMD_WALLET_NEW, CMD_WALLET_LIST, CMD_WALLET_INFO
};
int arg_index = 1;
int cmd_num = CMD_NONE;
const char *cmd_str = NULL;
// find add parameter ('alias' or 'handshake')
if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "new", NULL)) {
cmd_num = CMD_WALLET_NEW;
}
else if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "list", NULL)) {
cmd_num = CMD_WALLET_LIST;
}
else if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "info", NULL)) {
cmd_num = CMD_WALLET_INFO;
}
arg_index++;
if(cmd_num == CMD_NONE) {
"format of command: wallet [new -w <wallet_name> | list | info -addr <addr> -w <wallet_name> -net <net_name>]");
return -1;
}
dap_chain_node_addr_t address;
memset(&address, 0, sizeof(dap_chain_node_addr_t));
const char *addr_str = NULL, *wallet_name = NULL, *l_net_name = NULL;
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-addr", &addr_str);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-w", &wallet_name);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_name); // for
dap_string_t *l_string_ret = dap_string_new(NULL);
// new wallet
case CMD_WALLET_NEW: {
if(!wallet_name) {
dap_chain_node_cli_set_reply_text(str_reply,
"wallet name option <-w> not defined");
return -1;
}
dap_chain_sign_type_t l_sign_type = { SIG_TYPE_BLISS };
dap_chain_net_id_t l_net_id = { 0x1 };
// Creates new wallet
dap_chain_wallet_t *l_wallet = dap_chain_wallet_create(wallet_name, c_wallets_path, l_net_id, l_sign_type);
dap_chain_addr_t *l_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet);
if(!l_wallet || !l_addr) {
dap_chain_node_cli_set_reply_text(str_reply, "wallet is not created");
return -1;
}
char *l_addr_str = dap_chain_addr_to_str(l_addr);
dap_string_append_printf(l_string_ret, "wallet '%s' successfully created\n", l_wallet->name);
dap_string_append_printf(l_string_ret, "new address %s", l_addr_str);
DAP_DELETE(l_addr_str);
dap_chain_wallet_close(l_wallet);
}
break;
// wallet list
while((l_dir_entry = readdir(l_dir)) != NULL) {
const char *l_file_name = l_dir_entry->d_name;
size_t l_file_name_len = (l_file_name) ? strlen(l_file_name) : 0;
if((l_file_name_len > 8) && (strcmp(l_file_name + l_file_name_len - 8, ".dwallet") == 0)) {
char *l_file_path_tmp = dap_strdup_printf("%s/%s", c_wallets_path, l_file_name);
dap_chain_wallet_t *l_wallet = dap_chain_wallet_open_file(l_file_path_tmp);
if(l_wallet) {
dap_chain_addr_t *l_addr = dap_chain_wallet_get_addr(l_wallet);
char *l_addr_str = dap_chain_addr_to_str(l_addr);
dap_string_append_printf(l_string_ret, "\nwallet: %s\n", l_wallet->name);
dap_string_append_printf(l_string_ret, "addr: %s\n", (l_addr_str) ? l_addr_str : "-");
DAP_DELETE(l_addr_str);
dap_chain_wallet_close(l_wallet);
}
}
}
break;
// wallet info
case CMD_WALLET_INFO: {
dap_chain_wallet_t *l_wallet = NULL;
dap_chain_addr_t *l_addr = NULL;
if(wallet_name) {
l_wallet = dap_chain_wallet_open(wallet_name, c_wallets_path);
l_addr = (dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet);
}
if(!l_addr && addr_str)
l_addr = dap_chain_addr_from_str(addr_str);
dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name((const char *) l_net_name);
if(!l_net_name) {
dap_chain_node_cli_set_reply_text(str_reply, "wallet info requires parameter 'net'");
return -1;
}
else {
if((l_ledger = dap_chain_ledger_by_net_name(l_net_name)) == NULL) {
dap_chain_node_cli_set_reply_text(str_reply, "not found net by name '%s'", l_net_name);
return -1;
}
}
char *l_addr_str = dap_chain_addr_to_str((dap_chain_addr_t*) l_addr);
dap_string_append_printf(l_string_ret, "wallet: %s\n", l_wallet->name);
dap_string_append_printf(l_string_ret, "addr: %s\n", (l_addr_str) ? l_addr_str : "-");
size_t l_addr_tokens_size = 0;
char **l_addr_tokens = NULL;
//dap_chain_ledger_addr_get_token_ticker_all(l_ledger, l_addr, &l_addr_tokens, &l_addr_tokens_size);
// seriously?...
dap_chain_ledger_addr_get_token_ticker_all_fast(l_ledger, l_addr, &l_addr_tokens, &l_addr_tokens_size);
dap_string_append_printf(l_string_ret, "balance:\n");
else
dap_string_append_printf(l_string_ret, "balance:\u00a00");
for(size_t i = 0; i < l_addr_tokens_size; i++) {
if(l_addr_tokens[i]) {
uint64_t l_balance = dap_chain_ledger_calc_balance(l_ledger, l_addr, l_addr_tokens[i]);
long double l_balance_coins = (long double) l_balance / 1000000000000.0L;
//dap_string_append_printf(l_string_ret, " %.3Lf (%llu) %s\n", l_balance_coins,
dap_string_append_printf(l_string_ret, "\t\u00a0%.3Lf (%llu) %s", l_balance_coins,
if(i < l_addr_tokens_size - 1)
dap_string_append_printf(l_string_ret, "\n");
if(l_wallet)
dap_chain_wallet_close(l_wallet);
if(l_wallet)
dap_chain_wallet_close(l_wallet);
dap_string_free(l_string_ret, true);
dap_chain_node_cli_set_reply_text(str_reply, "wallet not found");
return -1;
}
}
break;
}
char *l_str_ret_tmp = dap_string_free(l_string_ret, false);
char *str_ret = dap_strdup(l_str_ret_tmp);
dap_chain_node_cli_set_reply_text(str_reply, str_ret);
/**
* @brief s_values_parse_net_chain
* @param argc
* @param argv
* @param str_reply
* @param l_chain
* @param l_net
* @return
*/
int dap_chain_node_cli_cmd_values_parse_net_chain(int *a_arg_index, int argc, char ** argv, char ** a_str_reply,
dap_chain_t ** a_chain, dap_chain_net_t ** a_net)
{
const char * l_chain_str = NULL;
const char * l_net_str = NULL;
// Net name
dap_chain_node_cli_find_option_val(argv, *a_arg_index, argc, "-net", &l_net_str);
else
dap_chain_node_cli_set_reply_text(a_str_reply, "%s requires parameter 'net'", argv[0]);
if((*a_net = dap_chain_net_by_name(l_net_str)) == NULL) { // Can't find such network
dap_chain_node_cli_set_reply_text(a_str_reply, "%s cand find network \"%s\"", argv[0], l_net_str);
dap_chain_node_cli_find_option_val(argv, *a_arg_index, argc, "-chain", &l_chain_str);
// Select chain
if(l_chain_str) {
if((*a_chain = dap_chain_net_get_chain_by_name(*a_net, l_chain_str)) == NULL) { // Can't find such chain
dap_chain_node_cli_set_reply_text(a_str_reply,
"%s requires parameter 'chain' to be valid chain name in chain net %s",
argv[0], l_net_str);
}
/**
* @brief com_token_decl_sign
* @param argc
* @param argv
* @param str_reply
* @return
*/
int com_token_decl_sign(int argc, char ** argv, char ** a_str_reply)
{
int arg_index = 1;
const char * l_datum_hash_str = NULL;
// Chain name
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "datum", &l_datum_hash_str);
const char * l_certs_str = NULL;
dap_chain_cert_t ** l_certs = NULL;
size_t l_certs_size = 0;
dap_chain_t * l_chain;
dap_chain_net_t * l_net = NULL;
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) < 0)
size_t l_signs_size = dap_chain_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_size);
if(!l_certs_size) {
dap_chain_node_cli_set_reply_text(a_str_reply,
"token_create command requres at least one valid certificate to sign the basic transaction of emission");
return -7;
}
size_t l_certs_count = l_certs_size / sizeof(dap_chain_cert_t *);
char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
log_it(L_DEBUG, "Requested to sign token declaration %s in gdb://%s with certs %s",
l_gdb_group_mempool, l_datum_hash_str, l_certs_str);
dap_chain_datum_t * l_datum = NULL;
size_t l_datum_size = 0;
if((l_datum = (dap_chain_datum_t*) dap_chain_global_db_gr_get(
l_datum_hash_str, &l_datum_size, l_gdb_group_mempool)) != NULL) {
if(l_datum->header.type_id == DAP_CHAIN_DATUM_TOKEN_DECL) {
dap_chain_datum_token_t * l_datum_token = (dap_chain_datum_token_t *) l_datum->data;
size_t l_datum_token_size = l_datum->header.data_size;
size_t l_signs_size = l_datum_token_size - sizeof(l_datum_token->header);
// Check for signatures, are they all in set and are good enought?
size_t l_signs_count = 0;
for(size_t l_offset = 0; l_offset < l_signs_size; l_signs_count++) {
dap_chain_sign_t * l_sign = (dap_chain_sign_t *) l_datum_token->signs + l_offset;
l_offset += dap_chain_sign_get_size(l_sign);
if(dap_chain_sign_verify(l_sign, &l_datum_token->header, sizeof(l_datum_token->header)) != 1) {
log_it(L_WARNING, "Wrong signature for datum_token with key %s in mempool!", l_datum_hash_str);
dap_chain_node_cli_set_reply_text(a_str_reply,
"Datum %s with datum token has wrong signature %u, break process and exit",
l_datum_hash_str, l_signs_count + 1);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return -666;
}
}
log_it(L_DEBUG, "Datum % with token declaration: %u signatures are verified well", l_signs_count);
if(l_signs_count == l_datum_token->header.signs_total) {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Datum %s with datum token has all signs on board. Can't add anything in it");
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return -7;
} // Check if more signs that could be (corrupted datum)
else if(l_signs_count > l_datum_token->header.signs_total) {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Warning! Datum %s with datum token has more signs on board (%u) than its possible to have (%u)!",
l_signs_count, l_datum_token->header.signs_total);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return -8;
} // Check if we have enough place to sign the datum token declaration
else if(l_datum_token->header.signs_total - l_signs_count < l_certs_count) {
l_datum = DAP_REALLOC(l_datum, l_datum_size + l_signs_size); // add place for new signatures
size_t l_offset = 0;
for(size_t i = 0; i < l_certs_count; i++) {
dap_chain_sign_t * l_sign = dap_chain_sign_create(l_certs[i]->enc_key,
&l_datum_token->header,
sizeof(l_datum_token->header), 0);
size_t l_sign_size = dap_chain_sign_get_size(l_sign);
if(l_offset + l_sign_size <= l_signs_size) {
memcpy(l_datum_token->signs + l_datum_token_size - sizeof(l_datum_token->header) + l_offset,
l_sign, l_sign_size);
log_it(L_DEBUG, "Added datum token declaration sign with cert %s", l_certs[i]->name);
break;
}
}
l_datum_size += l_signs_size;
// Recalc hash, string and place new datum
// Calc datum's hash
dap_chain_hash_fast_t l_key_hash;
dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
// Add datum to mempool with datum_token hash as a key
if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum, l_datum_size, l_gdb_group_mempool)) {
if(dap_chain_global_db_gr_del(l_datum_hash_str, l_gdb_group_mempool)) {
dap_chain_node_cli_set_reply_text(a_str_reply,
"datum %s produced from %s is replacing the %s in datum pool",
l_key_str, l_datum_hash_str, l_datum_hash_str);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
dap_chain_node_cli_set_reply_text(a_str_reply,
"Warning! Can't remove old datum %s ( new datum %s added normaly in datum pool)",
l_datum_hash_str, l_key_str);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return 1;
}
}
else {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! datum %s produced from %s can't be placed in mempool",
l_key_str, l_datum_hash_str);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return -2;
}
} else {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! Not enought place for new signature (%u is left when we need %u signatures)",
l_datum_token->header.signs_total - l_signs_count, l_certs_count);
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! Wrong datum type. token_decl_sign sign only token declarations datum");
} else {
dap_chain_node_cli_set_reply_text(a_str_reply,
"token_decl_sign can't find datum with %s hash in the mempool of %s:%s", l_net->pub.name,
l_chain->name);
dap_chain_node_cli_set_reply_text(a_str_reply, "token_decl_sign need datum <datum hash> argument");
return -2;
}
}
/**
* @brief com_token_decl_list
* @param argc
* @param argv
* @param str_reply
* @return
*/
int com_mempool_list(int argc, char ** argv, char ** a_str_reply)
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) != 0) {
char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
dap_string_t * l_str_tmp = dap_string_new(NULL);
size_t l_objs_size = 0;
dap_global_db_obj_t * l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
dap_string_append_printf(l_str_tmp, "%s.%s: Found %u records :\n", l_net->pub.name, l_chain->name, l_objs_size);
for(size_t i = 0; i < l_objs_size; i++) {
dap_chain_datum_t * l_datum = (dap_chain_datum_t*) l_objs[i].value;
char buf[50];
time_t l_ts_create = (time_t) l_datum->header.ts_create;
dap_string_append_printf(l_str_tmp, "%s: type_id=%s data_size=%u ts_create=%s",
l_objs[i].key, c_datum_type_str[l_datum->header.type_id],
l_datum->header.data_size, ctime_r(&l_ts_create, buf));
}
// Clean up
dap_chain_node_cli_set_reply_text(a_str_reply, l_str_tmp->str);
dap_chain_global_db_objs_delete(l_objs, l_objs_size);
return 0;
} else {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! Need both -net <network name> and -chain <chain name> params\n");
return -2;
}
}
/**
* @brief com_mempool_delete
* @param argc
* @param argv
* @param a_str_reply
* @return
*/
int com_mempool_delete(int argc, char ** argv, char ** a_str_reply)
{
int arg_index = 1;
dap_chain_t * l_chain = NULL;
dap_chain_net_t * l_net = NULL;
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) != 0) {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! Need both -net <network name> and -chain <chain name> params\n");
const char * l_datum_hash_str = NULL;
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-datum", &l_datum_hash_str);
char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
if(dap_chain_global_db_gr_del(l_datum_hash_str, l_gdb_group_mempool)) {
dap_chain_node_cli_set_reply_text(a_str_reply, "Datum %s deleted", l_datum_hash_str);
return 0;
} else {
dap_chain_node_cli_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
return -4;
} else {
dap_chain_node_cli_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", argv[0]);
} else {
dap_chain_node_cli_set_reply_text(a_str_reply,
"Error! Need both -net <network name> and -chain <chain name> params\n");
}
/**
* @brief com_mempool_proc
* @param argc
* @param argv
* @param a_str_reply
* @return
*/
int com_mempool_proc(int argc, char ** argv, char ** a_str_reply)
{
int arg_index = 1;
dap_chain_t * l_chain;
dap_chain_net_t * l_net = NULL;
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, a_str_reply, &l_chain, &l_net) < 0)
return -1;
char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
size_t l_objs_size = 0;
dap_global_db_obj_t * l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
dap_string_t * l_str_tmp = dap_string_new(NULL);
if(l_objs_size) {
dap_string_append_printf(l_str_tmp, "%s.%s: Found %u records :\n", l_net->pub.name, l_chain->name);
size_t l_datums_size = l_objs_size;
dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*, sizeof(dap_chain_datum_t*) * l_datums_size);
size_t l_objs_size_tmp = (l_objs_size > 15) ? min(l_objs_size, 10) : l_objs_size;
for(size_t i = 0; i < l_objs_size; i++) {
dap_chain_datum_t * l_datum = (dap_chain_datum_t*) l_objs[i].value;
l_datums[i] = l_datum;
if(i < l_objs_size_tmp) {
char buf[50];
time_t l_ts_create = (time_t) l_datum->header.ts_create;
dap_string_append_printf(l_str_tmp, "0x%s: type_id=%s ts_create=%s data_size=%u\n",
l_objs[i].key, c_datum_type_str[l_datum->header.type_id],
ctime_r(&l_ts_create, buf), l_datum->header.data_size);
}
}
if(l_objs_size > 15) {
dap_string_append_printf(l_str_tmp, "...\n");
}
size_t l_objs_processed = l_chain->callback_datums_pool_proc(l_chain, l_datums, l_datums_size);
// Delete processed objects
size_t l_objs_processed_tmp = (l_objs_processed > 15) ? min(l_objs_processed, 10) : l_objs_processed;
for(size_t i = 0; i < l_objs_processed; i++) {
dap_chain_global_db_gr_del(l_objs[i].key, l_gdb_group_mempool);
if(i < l_objs_processed_tmp) {
dap_string_append_printf(l_str_tmp, "New event created, removed datum 0x%s from mempool \n",
l_objs[i].key);
}
}
if(l_objs_processed > 15) {
dap_string_append_printf(l_str_tmp, "...\n");
}
dap_chain_global_db_objs_delete(l_objs, l_objs_size);
dap_chain_node_cli_set_reply_text(a_str_reply, l_str_tmp->str);
dap_string_free(l_str_tmp, false);
} else {
dap_chain_node_cli_set_reply_text(a_str_reply, "%s.^s: No records in mempool", l_net->pub.name, l_chain->name);
}
return 0;
}
/**
* @brief com_token_decl
* @param argc
* @param argv
* @param str_reply
* @return
*/
int com_token_decl(int argc, char ** argv, char ** str_reply)
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
{
int arg_index = 1;
const char *str_tmp = NULL;
char *str_reply_tmp = NULL;
const char * l_ticker = NULL;
const char * l_total_supply_str = NULL;
uint64_t l_total_supply = 0;
const char * l_signs_emission_str = NULL;
uint16_t l_signs_emission = 0;
const char * l_signs_total_str = NULL;
uint16_t l_signs_total = 0;
const char * l_certs_str = NULL;
dap_chain_cert_t ** l_certs = NULL;
size_t l_certs_size = 0;
dap_chain_t * l_chain;
dap_chain_net_t * l_net = NULL;
if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, argc, argv, str_reply, &l_chain, &l_net) < 0)
return -1;
// Total supply value
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "total_supply", &l_total_supply_str);
// Token ticker
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "token", &l_ticker);
// Certificates thats will be used to sign currend datum token
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "certs", &l_certs_str);
// Signs number thats own emissioncan't find
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "signs_total", &l_signs_total_str);
// Signs minimum number thats need to authorize the emission
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "signs_emission", &l_signs_emission_str);
if(!l_total_supply_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'total_supply'");
return -11;
if((l_total_supply = strtoull(l_total_supply_str, &l_tmp, 10)) == 0) {
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter 'total_supply' to be unsigned integer value that fits in 8 bytes");
return -2;
}
}
// Signs emission
if(!l_signs_emission_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'signs_emission'");
return -3;
if((l_signs_emission = (uint16_t) strtol(l_signs_emission_str, &l_tmp, 10)) == 0) {
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter 'signs_emission' to be unsigned integer value that fits in 2 bytes");
return -4;
}
}
// Signs total
if(!l_signs_total_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'signs_total'");
return -31;
if((l_signs_total = (uint16_t) strtol(l_signs_total_str, &l_tmp, 10)) == 0) {
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter 'signs_total' to be unsigned integer value that fits in 2 bytes");
return -41;
}
}
// Check for ticker
if(!l_ticker) {
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter 'token'");
return -5;
}
// Check certs list
if(!l_certs_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter 'certs'");
return -6;
}
// Load certs lists
size_t l_certs_count = dap_chain_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_size);
if(!l_certs_size) {
dap_chain_node_cli_set_reply_text(str_reply,
"token_create command requres at least one valid certificate to sign the basic transaction of emission");
return -7;
}
// If we have more certs than we need signs - use only first part of the list
l_certs_size = l_signs_total;
// Create new datum token
dap_chain_datum_token_t * l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, sizeof(l_datum_token->header));
l_datum_token->header.version = 1; // Current version
dap_snprintf(l_datum_token->header.ticker, sizeof(l_datum_token->header.ticker), "%s", l_ticker);
l_datum_token->header.total_supply = l_total_supply;
l_datum_token->header.signs_total = l_signs_total;
l_datum_token->header.signs_valid = l_signs_emission;
size_t l_signs_offset = 0;
// Sign header with all certificates in the list and add signs to the end of ticker declaration
// Important:
for(size_t i = 0; i < l_certs_size; i++) {
dap_chain_sign_t * l_sign = dap_chain_cert_sign(l_certs[i],
l_datum_token,
sizeof(l_datum_token->header),
0);
size_t l_sign_size = dap_chain_sign_get_size(l_sign);
l_datum_token=DAP_REALLOC(l_datum_token,sizeof (l_datum_token->header)+l_signs_offset +l_sign_size);
memcpy(l_datum_token->signs + l_signs_offset, l_sign, l_sign_size);
dap_chain_datum_t * l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_DECL, l_datum_token,
size_t l_datum_size = dap_chain_datum_size(l_datum);
// Calc datum's hash
dap_chain_hash_fast_t l_key_hash;
dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
// Add datum to mempool with datum_token hash as a key
char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum, l_datum_size, l_gdb_group_mempool)) {
dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum %s with token %s is placed in datum pool ",
str_reply_tmp, l_key_str, l_ticker);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
else {
dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is not placed in datum pool ", str_reply_tmp,
l_key_str);
DAP_DELETE(l_datum);
DAP_DELETE(l_datum_token);
DAP_DELETE(l_gdb_group_mempool);
return -2;
}
}
/**
* @brief com_token_emit
* @param argc
* @param argv
* @param str_reply
* @return
*/
int com_token_emit(int argc, char ** argv, char ** str_reply)
{
int arg_index = 1;
const char *str_tmp = NULL;
uint64_t l_emission_value = 0;
const char * l_ticker = NULL;
const char * l_addr_str = NULL;
const char * l_certs_str = NULL;
dap_chain_cert_t ** l_certs = NULL;
const char * l_chain_emission_str = NULL;
dap_chain_t * l_chain_emission = NULL;
const char * l_chain_base_tx_str = NULL;
dap_chain_t * l_chain_base_tx = NULL;
const char * l_net_str = NULL;
dap_chain_net_t * l_net = NULL;
// Wallet address that recieves the emission
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-certs", &l_certs_str);
// Wallet address that recieves the emission
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-addr", &l_addr_str);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-token", &l_ticker);
if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-emission_value", &str_tmp)) {
l_emission_value = strtoull(str_tmp, NULL, 10);
}
if(!l_emission_value) {
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-emission_value'");
return -1;
}
if(!l_addr_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-addr'");
return -2;
}
if(!l_ticker) {
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-token'");
dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-certs'");
dap_chain_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_size);
"token_emit command requres at least one valid certificate to sign the basic transaction of emission");
dap_chain_addr_t * l_addr = dap_chain_addr_from_str(l_addr_str);
dap_chain_node_cli_set_reply_text(str_reply, "address \"%s\" is invalid", l_addr_str);
// Net addr
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_str);
// Select chain network
if(!l_net_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'net'");
return -42;
} else {
if((l_net = dap_chain_net_by_name(l_net_str)) == NULL) { // Can't find such network
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter '-net' to be valid chain network name");
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-chain_emission", &l_chain_emission_str);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-chain_base_tx", &l_chain_base_tx_str);
// Select chain emission
if(!l_chain_emission_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter '-chain_emission'");
} else {
if((l_chain_emission = dap_chain_net_get_chain_by_name(l_net, l_chain_emission_str)) == NULL) { // Can't find such chain
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter 'chain_emission' to be valid chain name in chain net %s",
l_net_str);
// Select chain emission
if(!l_chain_base_tx_str) {
dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'chain_base_tx'");
return -46;
} else {
if((l_chain_base_tx = dap_chain_net_get_chain_by_name(l_net, l_chain_base_tx_str)) == NULL) { // Can't find such chain
dap_chain_node_cli_set_reply_text(str_reply,
"token_create requires parameter 'chain_emission' to be valid chain name in chain net %s",
l_net_str);
char * l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool(l_chain_emission);
char * l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool(l_chain_base_tx);
dap_chain_datum_token_emission_t * l_token_emission;
size_t l_token_emission_size = sizeof (l_token_emission->hdr) +
sizeof (l_token_emission->data.type_auth.signs_count);
l_token_emission = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, l_token_emission_size);
strncpy(l_token_emission->hdr.ticker, l_ticker, sizeof(l_token_emission->hdr.ticker));
l_token_emission->hdr.value = l_emission_value;
l_token_emission->hdr.type = DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH;
memcpy(&l_token_emission->hdr.address, l_addr, sizeof (l_token_emission->hdr.address));
// Then add signs
size_t l_offset=0;
for (size_t i =0; i < l_certs_size; i++ ){
dap_chain_sign_t * l_sign = dap_chain_cert_sign(l_certs[i],&l_token_emission->hdr, sizeof(l_token_emission->hdr),0 );
size_t l_sign_size = dap_chain_sign_get_size(l_sign);
l_token_emission_size += l_sign_size;
l_token_emission= DAP_REALLOC(l_token_emission, l_token_emission_size);
memcpy(l_token_emission->data.type_auth.signs+l_offset,l_sign,l_sign_size);
l_offset+= l_sign_size;
DAP_DELETE(l_sign);
}
// Produce datum
dap_chain_datum_t * l_datum_emission = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_EMISSION,
size_t l_datum_emission_size = sizeof(l_datum_emission->header) + l_datum_emission->header.data_size;
// Calc datum's hash
dap_chain_hash_fast_t l_datum_emission_hash;
dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_datum_emission_hash);
char * l_key_str = dap_chain_hash_fast_to_str_new(&l_datum_emission_hash);
if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum_emission, l_datum_emission_size
, l_gdb_group_mempool_emission)) {
str_reply_tmp = dap_strdup_printf("datum emission %s is placed in datum pool ", l_key_str);
dap_chain_node_cli_set_reply_text(str_reply, "datum emission %s is not placed in datum pool ", l_key_str);
return -1;
}
DAP_DELETE(l_key_str);
// create first transaction (with tx_token)
dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t));
dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
// create items
dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(&l_datum_emission_hash, l_ticker);
dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0);
dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(l_addr, l_emission_value);
// pack items to transaction
dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_token);
dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out);
// Sign all that we have with certs
for(size_t i = 0; i < l_certs_size; i++) {
if(dap_chain_datum_tx_add_sign_item(&l_tx, l_certs[i]->enc_key) < 0) {
dap_chain_node_cli_set_reply_text(str_reply, "No private key for certificate=%s",
l_certs[i]->name);
return -3;
}
}
DAP_DELETE(l_certs);
DAP_DELETE(l_tx_token);
DAP_DELETE(l_in);
DAP_DELETE(l_out);
size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
// Pack transaction into the datum
dap_chain_datum_t * l_datum_tx = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size);
size_t l_datum_tx_size = dap_chain_datum_size(l_datum_tx);
// use l_tx hash for compatible with utho hash
//dap_hash_fast(l_tx, l_tx_size, &l_key_hash); //dap_hash_fast(l_datum_tx, l_datum_tx_size, &l_key_hash);
dap_chain_hash_fast_t l_datum_tx_hash;
dap_hash_fast(l_datum_tx, l_datum_tx_size, &l_datum_tx_hash);
l_key_str = dap_chain_hash_fast_to_str_new(&l_datum_tx_hash);
if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum_tx, l_datum_tx_size
dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is placed in datum pool ", str_reply_tmp,
l_key_str);
else {
dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is not placed in datum pool ", str_reply_tmp,
l_key_str);
return -2;
}
DAP_DELETE(str_reply_tmp);
DAP_DELETE(l_key_str);
/**
* com_tx_cond_create command
*
* Create transaction
*/
int com_tx_cond_create(int argc, char ** argv, char **str_reply)
// test
const char * l_token_ticker = NULL;
const char *c_wallets_path = dap_config_get_item_str(g_config, "general", "wallets_path");
const char *c_wallet_name_from = "w_tesla"; // where to take coins for service
const char *c_wallet_name_cond = "w_picnic"; // who will be use service, usually the same address (addr_from)
const char *c_net_name = "kelvin-testnet";
//debug
{
dap_chain_wallet_t * l_wallet_tesla = dap_chain_wallet_open("w_picnic", c_wallets_path);
const dap_chain_addr_t *l_addr_tesla = dap_chain_wallet_get_addr(l_wallet_tesla);
char *addr = dap_chain_addr_to_str(l_addr_tesla);
addr = 0;
}
dap_chain_wallet_t *l_wallet_from = dap_chain_wallet_open(c_wallet_name_from, c_wallets_path);
dap_enc_key_t *l_key = dap_chain_wallet_get_key(l_wallet_from, 0);
dap_chain_wallet_t *l_wallet_cond = dap_chain_wallet_open(c_wallet_name_cond, c_wallets_path);
dap_enc_key_t *l_key_cond = dap_chain_wallet_get_key(l_wallet_cond, 0);
// where to take coins for service
const dap_chain_addr_t *addr_from = dap_chain_wallet_get_addr(l_wallet_from);
// who will be use service, usually the same address (addr_from)
const dap_chain_addr_t *addr_cond = dap_chain_wallet_get_addr(l_wallet_cond);
dap_chain_net_srv_abstract_t l_cond;
// dap_chain_net_srv_abstract_set(&l_cond, SERV_CLASS_PERMANENT, SERV_ID_VPN, l_value, SERV_UNIT_MB,
// "test vpn service");
dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name((const char *) c_net_name);
int res = dap_chain_mempool_tx_create_cond(NULL, l_key, l_key_cond, addr_from,
NULL, l_token_ticker, l_value, 0, (const void*) &l_cond, sizeof(dap_chain_net_srv_abstract_t));
dap_chain_wallet_close(l_wallet_from);
dap_chain_wallet_close(l_wallet_cond);
dap_chain_node_cli_set_reply_text(str_reply, "cond create=%s\n",
(res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for service fee" : "False");
return res;
/**
* com_tx_create command
*
* Create transaction
int com_tx_create(int argc, char ** argv, char **str_reply)
{
int arg_index = 1;
int cmd_num = 1;
const char *value_str = NULL;
const char *addr_base58_to = NULL;
const char *addr_base58_fee = NULL;
const char *str_tmp = NULL;
const char * l_from_wallet_name = NULL;
const char * l_token_ticker = NULL;
const char * l_tx_num_str = NULL;
size_t l_tx_num =0;
uint64_t value = 0;
uint64_t value_fee = 0;
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-from_wallet", &l_from_wallet_name);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-to_addr", &addr_base58_to);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-chain", &l_chain_name);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-tx_num", &l_tx_num_str);
if ( l_tx_num_str )
l_tx_num = strtoul(l_tx_num_str,NULL,10);
if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-fee", &addr_base58_fee)) {
if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value_fee", &str_tmp)) {
value_fee = strtoull(str_tmp, NULL, 10);
if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value", &str_tmp)) {
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-from_wallet'");
if(!addr_base58_to) {
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-to_addr'");
return -1;
}
if(!value) {
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value'");
return -1;
}
if(addr_base58_fee && !value_fee) {
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value_fee' if '-fee' is specified");
return -1;
}
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name);
dap_ledger_t *l_ledger = l_net? l_net->pub.ledger : NULL ;
if((l_ledger = dap_chain_ledger_by_net_name(l_net_name)) == NULL) {
dap_chain_node_cli_set_reply_text(str_reply, "not found net by name '%s'", l_net_name);
return -1;
}
if(!l_chain_name) {
dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-chain'");
return -1;
}
dap_chain_t * l_chain = dap_chain_net_get_chain_by_name(l_net, l_chain_name);
if ( !l_chain ){
dap_chain_node_cli_set_reply_text(str_reply, "not found chain name '%s'", l_chain_name);
return -1;
const char *c_wallets_path = dap_config_get_item_str(g_config, "general", "wallets_path");
dap_chain_wallet_t * l_wallet = dap_chain_wallet_open(l_from_wallet_name, c_wallets_path);
dap_chain_node_cli_set_reply_text(str_reply, "wallet %s does not exist", l_from_wallet_name);
return -1;
}
const dap_chain_addr_t *addr_from = (const dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet);
dap_chain_addr_t *addr_to = dap_chain_addr_from_str(addr_base58_to);
dap_chain_addr_t *addr_fee = dap_chain_addr_from_str(addr_base58_fee);
dap_chain_node_cli_set_reply_text(str_reply, "source address is invalid");
return -1;
}
if(!addr_to) {
dap_chain_node_cli_set_reply_text(str_reply, "destination address is invalid");
return -1;
}
if(addr_base58_fee && !addr_fee) {
dap_chain_node_cli_set_reply_text(str_reply, "fee address is invalid");
dap_string_t *string_ret = dap_string_new(NULL);
//g_string_printf(string_ret, "from=%s\nto=%s\nval=%lld\nfee=%s\nval_fee=%lld\n\n",
// addr_base58_from, addr_base58_to, value, addr_base58_fee, value_fee);
int res = l_tx_num? dap_chain_mempool_tx_create_massive( l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to, addr_fee,
l_token_ticker, value, value_fee, l_tx_num)
:dap_chain_mempool_tx_create( l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to, addr_fee,
dap_string_append_printf(string_ret, "transfer=%s\n",
(res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
dap_chain_node_cli_set_reply_text(str_reply, string_ret->str);
dap_string_free(string_ret, false);
DAP_DELETE(addr_to);
DAP_DELETE(addr_fee);
/**
* tx_verify command
*
* Verifing transaction
*/
int com_tx_verify(int argc, char ** argv, char **str_reply)
{
if(argc > 1) {
if(str_reply)
dap_chain_node_cli_set_reply_text(str_reply, "command \"%s\" not recognized", argv[1]);
dap_chain_node_cli_set_reply_text(str_reply, "command not defined, enter \"help <cmd name>\"");
/**
* print_log command
*
* Print log info
* print_log [ts_after <timestamp >] [limit <line numbers>]
*/
int com_print_log(int argc, char ** argv, char **str_reply)
{
int arg_index = 1;
const char * l_str_ts_after = NULL;
const char * l_str_limit = NULL;
int64_t l_ts_after = 0;
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "ts_after", &l_str_ts_after);
dap_chain_node_cli_find_option_val(argv, arg_index, argc, "limit", &l_str_limit);
l_ts_after = (l_str_ts_after) ? strtoll(l_str_ts_after, 0, 10) : -1;
l_limit = (l_str_limit) ? strtol(l_str_limit, 0, 10) : -1;
if(l_ts_after < 0 || !l_str_ts_after) {
dap_chain_node_cli_set_reply_text(str_reply, "requires valid parameter 'l_ts_after'");
return -1;
}
if(!l_limit) {
dap_chain_node_cli_set_reply_text(str_reply, "requires valid parameter 'limit'");
return -1;
}
char *l_str_ret = dap_log_get_item(l_ts_after,(int) l_limit);
if(!l_str_ret) {
dap_chain_node_cli_set_reply_text(str_reply, "no logs");
return -1;
}
dap_chain_node_cli_set_reply_text(str_reply, l_str_ret);
DAP_DELETE(l_str_ret);
return 0;