Skip to content
Snippets Groups Projects
dap_chain_node_cli_cmd.c 94.3 KiB
Newer Older
    if(res >= 0) {
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
        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:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                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:
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "Unknown traceroute module");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "first hop out of range");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "max hops cannot be more than 255");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "no more than 10 probes per hop");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "bad wait specifications");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "too big packetlen ");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "IP version mismatch in addresses specified");
                break;
            case 9:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "bad sendtime");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "init_ip_options");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "calloc");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr, "parse cmdline");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "trace method's init failed");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "traceroute %s error(%d) %s", addr, res,
                        "trace not found");
ANTA's avatar
ANTA committed
#endif
return 0;
}

/**
 * Tracepath command
 *
 * return 0 OK, -1 Err
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_tracepath(int argc, char** argv, char **str_reply)
ANTA's avatar
ANTA committed
#ifndef _WIN32
    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)
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
            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:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                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:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't create socket");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IPV6_MTU_DISCOVER");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IPV6_RECVERR");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IPV6_HOPLIMIT");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IP_MTU_DISCOVER");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IP_RECVERR");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IP_RECVTTL");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "malloc");
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr,
                        "Can't setsockopt IPV6_UNICAST_HOPS");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_TTL");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "tracepath %s error(%d) %s", addr, res, "trace not found");
ANTA's avatar
ANTA committed
#endif
  return 0;
}

/**
 * Ping command
 *
 * return 0 OK, -1 Err
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_ping(int argc, char** argv, char **str_reply)
ANTA's avatar
ANTA committed
#ifndef _WIN32

    if(argc < 2) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "host not specified");
    const char *n_str = NULL;
    int argc_host = 1;
    int argc_start = 1;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    argc_start = dap_chain_node_cli_find_option_val(argv, argc_start, argc, "-n", &n_str);
    if(argc_start) {
        argc_host = argc_start + 1;
        n = (n_str) ? atoi(n_str) : 4;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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)
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "ping %s error: %s", addr, "Destination address required");
                break;
            case EADDRNOTAVAIL:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                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:
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "ping %s error: %s", addr, "Unknown protocol family");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                dap_chain_node_cli_set_reply_text(str_reply, "ping %s error(%d)", addr, -res);
ANTA's avatar
ANTA committed
#endif
return 0;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_help(int argc, char ** argv, char **str_reply)
        log_it(L_DEBUG, "Help for command %s", argv[1]);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cmd_item_t *l_cmd = dap_chain_node_cli_cmd_find(argv[1]);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
        if(l_cmd) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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
 *
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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;
    }
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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) {
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
        dap_chain_node_cli_set_reply_text(str_reply,
                "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;
    // find wallet addr
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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);
    switch (cmd_num) {
    // 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
    case CMD_WALLET_LIST: {
        DIR * l_dir = opendir(c_wallets_path);
        if(l_dir) {
            struct dirent * l_dir_entry;
            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);
                    }
                    DAP_DELETE(l_file_path_tmp);
            closedir(l_dir);
        }
    }
        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;
            }
        }

        if(l_addr) {
            char *l_addr_str = dap_chain_addr_to_str((dap_chain_addr_t*) l_addr);
            if(l_wallet)
                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;
p-const's avatar
p-const committed
            //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);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
            if(l_addr_tokens_size > 0)
                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]) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                    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,
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
                                             l_balance, l_addr_tokens[i]);
                    if(i < l_addr_tokens_size - 1)
                        dap_string_append_printf(l_string_ret, "\n");
                DAP_DELETE(l_addr_tokens[i]);
            DAP_DELETE(l_addr_tokens);
            DAP_DELETE(l_addr_str);
            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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            dap_chain_node_cli_set_reply_text(str_reply, "wallet not found");
    char *l_str_ret_tmp = dap_string_free(l_string_ret, false);
    char *str_ret = dap_strdup(l_str_ret_tmp);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    dap_chain_node_cli_set_reply_text(str_reply, str_ret);
    DAP_DELETE(l_str_ret_tmp);
/**
 * @brief s_values_parse_net_chain
 * @param argc
 * @param argv
 * @param str_reply
 * @param l_chain
 * @param l_net
 * @return
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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;

    if(a_net)
        dap_chain_node_cli_find_option_val(argv, *a_arg_index, argc, "-net", &l_net_str);
    else
        return -100;
    // Select network
    if(!l_net_str) {
        dap_chain_node_cli_set_reply_text(a_str_reply, "%s requires parameter 'net'", argv[0]);
        return -101;
    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);
        return -102;
    // Chain name
    if(a_chain) {
        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);
    return 0;

}

/**
 * @brief com_token_decl_sign
 * @param argc
 * @param argv
 * @param str_reply
 * @return
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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);

    if(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)
            return -1;

        // Load certs lists
        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) {

            // Check if its token declaration
            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);

                // Check if all signs are present
                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);
                        DAP_DELETE(l_sign);
                        l_offset += l_sign_size;
                        if(l_offset > l_signs_size) {
                            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)) {
                        // Remove old datum from pool
                        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);
                            return 0;
                        } else {
                            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);
                    return -6;
                }
            } else {
                dap_chain_node_cli_set_reply_text(a_str_reply,
                        "Error! Wrong datum type. token_decl_sign sign only token declarations datum");
                return -61;
            }
        } 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);
            return -5;
        }
    } else {
        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
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_mempool_list(int argc, char ** argv, char ** a_str_reply)
{
    int arg_index = 1;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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) {
        return -1;
    if(l_chain && l_net) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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));
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        }

        // 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);
        dap_string_free(l_str_tmp, false);
        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");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        return -2;
    }
}

/**
 * @brief com_mempool_delete
 * @param argc
 * @param argv
 * @param a_str_reply
 * @return
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_mempool_delete(int argc, char ** argv, char ** a_str_reply)
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
{
    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");
    if(l_chain && l_net) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        const char * l_datum_hash_str = NULL;
        dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-datum", &l_datum_hash_str);
        if(l_datum_hash_str) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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]);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            return -3;
        }
    } else {
        dap_chain_node_cli_set_reply_text(a_str_reply,
                "Error! Need both -net <network name> and -chain <chain name> params\n");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        return -2;
    }
}

/**
 * @brief com_mempool_proc
 * @param argc
 * @param argv
 * @param a_str_reply
 * @return
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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);
        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;
            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);
        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);
}

/**
 * @brief com_token_decl
 * @param argc
 * @param argv
 * @param str_reply
 * @return
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_token_decl(int argc, char ** argv, char ** str_reply)
{
    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;
    } else {
        char * l_tmp = NULL;
        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;
    } else {
        char * l_tmp = NULL;
        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;
    } else {
        char * l_tmp = NULL;
        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
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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
    if(l_certs_size > l_signs_total)
        l_certs_size = l_signs_total;

    // Create new datum token
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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
ANTA's avatar
ANTA committed
    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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        l_signs_offset += l_sign_size;
        DAP_DELETE(l_sign);
    }
    dap_chain_datum_t * l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_DECL, l_datum_token,
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            sizeof(l_datum_token->header) + l_signs_offset );
    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);
        return 0;
    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
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_token_emit(int argc, char ** argv, char ** str_reply)
{
    int arg_index = 1;
    const char *str_tmp = NULL;
    char *str_reply_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;
    size_t l_certs_size = 0;
    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);

    // Token ticker
    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-token", &l_ticker);

    // Token emission
    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'");