Skip to content
Snippets Groups Projects
dap_chain_node_cli_cmd.c 61.2 KiB
Newer Older
            dap_chain_node_client_close(client);
            DAP_DELETE(node_info);
            return -1;
        }

        // send request
        size_t l_data_size_out = 0;
        // Get last timestamp in log
        time_t l_timestamp_start = dap_db_log_get_last_timestamp();
        size_t l_data_send_len = 0;
        uint8_t *l_data_send = dap_stream_ch_chain_net_make_packet(l_cur_node_addr, node_info->hdr.address.uint64,
                l_timestamp_start, NULL, 0, &l_data_send_len);
        uint8_t l_ch_id = dap_stream_ch_chain_net_get_id(); // Channel id for global_db sync
        res = dap_chain_node_client_send_chain_net_request(client, l_ch_id,
        STREAM_CH_CHAIN_NET_PKT_TYPE_GLOBAL_DB_REQUEST_SYNC, l_data_send, l_data_send_len); //, NULL);
        DAP_DELETE(l_data_send);
        if(res != 1) {
            set_reply_text(str_reply, "no request sent");
            // clean client struct
            dap_chain_node_client_close(client);
            DAP_DELETE(node_info);
            return -1;
        }

        // wait for finishing of request
        timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
        // TODO add progress info to console
        res = chain_node_client_wait(client, NODE_CLIENT_STATE_END, timeout_ms);
        DAP_DELETE(node_info);
        dap_client_disconnect(client->client);
        dap_chain_node_client_close(client);
        switch (res) {
        case 0:
            set_reply_text(str_reply, "timeout");
            return -1;
        case 1:
            set_reply_text(str_reply, "nodes sync completed");
            return 0;
        default:
            set_reply_text(str_reply, "error");
            return -1;
        }
        // make handshake
    case CMD_HANDSHAKE: {
        // get address from alias if addr not defined
        if(alias_str && !address.uint64) {
            dap_chain_node_addr_t *address_tmp = get_name_by_alias(alias_str);
            if(address_tmp) {
                memcpy(&address, address_tmp, sizeof(address_tmp));
                DAP_DELETE(address_tmp);
            }
            else {
                set_reply_text(str_reply, "no address found by alias");
                return -1;
            }
        }
        if(!address.uint64) {
            set_reply_text(str_reply, "addr not found");
            return -1;
        }

        dap_chain_node_info_t *node_info = dap_chain_node_info_read(&address, str_reply);
            return -1;
        int timeout_ms = 10000; //10 sec = 10000 ms
        // start handshake
Dmitriy A. Gerasimov's avatar
Dmitriy A. Gerasimov committed
        dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
        if(!client) {
            set_reply_text(str_reply, "can't connect");
            DAP_DELETE(node_info);
            return -1;
        }
        // wait handshake
        int res = chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
        if(res != 1) {
            set_reply_text(str_reply, "no response from node");
            // clean client struct
Dmitriy A. Gerasimov's avatar
Dmitriy A. Gerasimov committed
            dap_chain_node_client_close(client);
            DAP_DELETE(node_info);
            return -1;
        }
        DAP_DELETE(node_info);
        //Add new established connection in the list
        int ret = chain_node_client_list_add(&address, client);
        switch (ret)
        {
        case -1:
            dap_chain_node_client_close(client);
            set_reply_text(str_reply, "connection established, but not saved");
            return -1;
        case -2:
            dap_chain_node_client_close(client);
            set_reply_text(str_reply, "connection already present");
            return -1;
        }
        set_reply_text(str_reply, "connection established");
    return 0;
}

/**
 * Traceroute command
 *
 * return 0 OK, -1 Err
 */
int com_traceroute(int argc, const 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) {
        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:
                set_reply_text(str_reply, "traceroute %s error: %s", (addr) ? addr : "",
                        (addr) ? "Name or service not known" : "Host not defined");
                break;
            case 2:
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "Unknown traceroute module");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "first hop out of range");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "max hops cannot be more than 255");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "no more than 10 probes per hop");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "bad wait specifications");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "too big packetlen ");
                set_reply_text(str_reply, "traceroute %s error: %s", addr,
                        "IP version mismatch in addresses specified");
                break;
            case 9:
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "bad sendtime");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "init_ip_options");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "calloc");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "parse cmdline");
                set_reply_text(str_reply, "traceroute %s error: %s", addr, "trace method's init failed");
                set_reply_text(str_reply, "traceroute %s error(%d) %s", addr, res, "trace not found");
            }
        }
    }
    return res;
}

/**
 * Tracepath command
 *
 * return 0 OK, -1 Err
 */
int com_tracepath(int argc, const 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)
            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:
                set_reply_text(str_reply, "tracepath %s error: %s", (addr) ? addr : "",
                        (addr) ? "Name or service not known" : "Host not defined");
                break;
            case ESOCKTNOSUPPORT:
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't create socket");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IPV6_MTU_DISCOVER");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IPV6_RECVERR");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IPV6_HOPLIMIT");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_MTU_DISCOVER");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_RECVERR");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_RECVTTL");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "malloc");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IPV6_UNICAST_HOPS");
                set_reply_text(str_reply, "tracepath %s error: %s", addr, "Can't setsockopt IP_TTL");
                set_reply_text(str_reply, "tracepath %s error(%d) %s", addr, res, "trace not found");
            }
        }
    }
    return res;
}

/**
 * Ping command
 *
 * return 0 OK, -1 Err
 */
int com_ping(int argc, const char** argv, char **str_reply)
{
    int n = 4;
    if(argc < 2) {
        set_reply_text(str_reply, "host not specified");
        return -1;
    }
    const char *n_str = NULL;
    int argc_host = 1;
    int argc_start = 1;
    argc_start = 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;
    }
    else {
        argc_start = 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)
            set_reply_text(str_reply, "ping %s time=%.1lf ms", addr, res * 1. / 1000);
    }
    else {
        if(str_reply) {
            switch (-res)
            {
            case EDESTADDRREQ:
                set_reply_text(str_reply, "ping %s error: %s", addr, "Destination address required");
                break;
            case EADDRNOTAVAIL:
                set_reply_text(str_reply, "ping %s error: %s", (addr) ? addr : "",
                        (addr) ? "Host not found" : "Host not defined");
                break;
            case EPFNOSUPPORT:
                set_reply_text(str_reply, "ping %s error: %s", addr, "Unknown protocol family");
                set_reply_text(str_reply, "ping %s error(%d)", addr, -res);
            }
        }
    }
    return res;
}

/**
 * Help command
 */
int com_help(int argc, const char ** argv, char **str_reply)
{
    if(argc > 1) {
        const COMMAND *cmd = find_command(argv[1]);
        if(cmd)
        {
            set_reply_text(str_reply, "%s:\n%s", cmd->doc, cmd->doc_ex);
            return 1;
        }
        set_reply_text(str_reply, "command \"%s\" not recognized", argv[1]);
        return -1;
    }
    else {
        // TODO Read list of commands & return it
    }
    if(str_reply)
        set_reply_text(str_reply, "command not defined, enter \"help <cmd name>\"");
    return -1;
}

/**
 * com_tx_create command
 *
 * Wallet info
 */
int com_tx_wallet(int argc, const 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_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(find_option_val(argv, arg_index, min(argc, arg_index + 1), "list", NULL)) {
        cmd_num = CMD_WALLET_LIST;
    }
    else if(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) {
        set_reply_text(str_reply, "format of command: wallet [list | info -addr <addr> -w <wallet_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;
    // find wallet addr
    find_option_val(argv, arg_index, argc, "-addr", &addr_str);
    find_option_val(argv, arg_index, argc, "-w", &wallet_name);

    dap_string_t *l_string_ret = dap_string_new(NULL);
    switch (cmd_num) {
    // wallet list
    case CMD_WALLET_LIST: {
        GDir *l_dir = g_dir_open(c_wallets_path, 0, NULL);
        if(l_dir) {
            const char *l_file = NULL;
            do {
                l_file = g_dir_read_name(l_dir);
                int l_file_len = (l_file) ? strlen(l_file) : 0;
                if(l_file_len > 8 && !g_strcmp0(l_file + l_file_len - 8, ".dwallet")) {
                    char *l_file_path_tmp = dap_strdup_printf("%s/%s", c_wallets_path, l_file);
                    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_addr_t *) dap_chain_wallet_get_addr(l_wallet);
                        char *l_addr_str = dap_chain_addr_to_str((dap_chain_addr_t*) 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);
                }
            }
            while(l_file);
            g_dir_close(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_str_to_addr(addr_str);

        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, "\nwallet: %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_utxo_addr_get_token_ticker_all(l_addr, &l_addr_tokens, &l_addr_tokens_size);
            if(l_addr_tokens_size>0)
                dap_string_append_printf(l_string_ret, "balance:\n");
            else
                dap_string_append_printf(l_string_ret, "balance: 0\n");
            for(size_t i = 0; i < l_addr_tokens_size; i++) {
                if(l_addr_tokens[i]) {
                    uint64_t balance = dap_chain_utxo_calc_balance(l_addr, l_addr_tokens[i]);
                    dap_string_append_printf(l_string_ret, "          %llu %s\n", balance, l_addr_tokens[i]);
                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);
            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);
    set_reply_text(str_reply, str_ret);
    DAP_DELETE(l_str_ret_tmp);
/**
 * @brief com_token_emit
 * @param argc
 * @param argv
 * @param str_reply
 * @return
 */
int com_token_emit(int argc, const 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;

    // Wallet address that recieves the emission
    find_option_val(argv, arg_index, argc, "certs", &l_certs_str);

    // Wallet address that recieves the emission
    find_option_val(argv, arg_index, argc, "addr", &l_addr_str);

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

    // Token emission
    if(find_option_val(argv, arg_index, argc, "emission_value", &str_tmp)) {
        l_emission_value = strtoull(str_tmp, NULL, 10);
    }

    if(!l_emission_value) {
        set_reply_text(str_reply, "token_emit requires parameter 'emission_value'");
        return -1;
    }

    if(!l_addr_str) {
        set_reply_text(str_reply, "token_emit requires parameter 'addr'");
        return -2;
    }

    if(!l_ticker) {
        set_reply_text(str_reply, "token_emit requires parameter 'tokent'");
        return -3;
    }

    if(!l_certs_str) {
        set_reply_text(str_reply, "token_emit requires parameter 'certs'");
        return -4;
    }

    int n = 0;
    char * l_certs_tmp_ptrs = NULL;
    char * l_certs_str_dup = strdup(l_certs_str);
    char *l_cert_str = strtok_r(l_certs_str_dup, ",", &l_certs_tmp_ptrs);
    //debug
    {
        const char * l_wallets_path = dap_config_get_item_str(g_config, "general", "wallets_path");
        dap_chain_net_id_t a_net_id;
        a_net_id.uint64 = 0x123;
        dap_chain_sign_type_t l_type;
        l_type.type = 0x0003;// SIG_TYPE_TESLA=0x0003
        dap_chain_wallet_t *wallet1 = dap_chain_wallet_create("tesla_first", l_wallets_path, a_net_id, l_type);
        dap_chain_wallet_t *wallet2 = dap_chain_wallet_create("tesla_second", l_wallets_path, a_net_id, l_type);
        wallet1 = NULL;
    }

    // First we just calc items
    while(l_cert_str) {
        l_cert_str = strtok_r(NULL, ",", &l_certs_tmp_ptrs);
        l_certs_size++;
    }
    // init certs array
    l_certs = DAP_NEW_Z_SIZE(dap_chain_cert_t*, l_certs_size);

    // Second pass we parse them all
    strcpy(l_certs_str_dup, l_certs_str);
    l_cert_str = strtok_r(l_certs_str_dup, ",", &l_certs_tmp_ptrs);
    size_t l_certs_pos = 0;
    while(l_cert_str) {

        // trim token whitespace
        if(isspace(l_cert_str[0]))
            l_cert_str = l_cert_str + 1;
        if(isspace(l_cert_str[strlen(l_cert_str) - 1]))
            l_cert_str[strlen(l_cert_str) - 1] = 0;
        l_certs[l_certs_pos] = dap_chain_cert_find_by_name(l_cert_str);
        if(l_certs[l_certs_pos]) {
            l_certs_pos++;
        } else {
            set_reply_text(str_reply, "Error: can't find %s certificate", l_cert_str);
            return -6;
        }
        l_cert_str = strtok_r(NULL, ",", &l_certs_tmp_ptrs);
    }
    free(l_certs_str_dup);

    if(!l_certs_size) {
        set_reply_text(str_reply,
                "token_emit command requres at least one valid certificate to sign the basic transaction of emission");
        return -5;
    }

    dap_chain_addr_t * l_addr = dap_chain_str_to_addr(l_addr_str);

    if(!l_addr) {
        set_reply_text(str_reply, "address \"%s\" is invalid", l_addr_str);
        return -4;
    }

    // Create emission datum
    dap_chain_datum_token_emission_t * l_token_emission;
    dap_chain_hash_fast_t l_token_emission_hash;
    l_token_emission = DAP_NEW_Z(dap_chain_datum_token_emission_t);
    strncpy(l_token_emission->ticker, l_ticker, sizeof(l_token_emission->ticker));
    l_token_emission->value = l_emission_value;
    dap_hash_fast(l_token_emission, sizeof(dap_chain_datum_token_emission_t), &l_token_emission_hash);
    dap_chain_datum_t * l_datum_emission = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_EMISSION,
            l_token_emission,
            sizeof(dap_chain_datum_token_emission_t));
    size_t l_datum_emission_size = sizeof(l_datum_emission->header) + l_datum_emission->header.data_size;

    DAP_DELETE(l_token_emission);

    dap_chain_hash_fast_t l_key_hash;
    dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_key_hash);
    char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);

    // Add to mempool emission token
    if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum_emission, l_datum_emission_size
            , dap_config_get_item_str_default(g_config, "mempool", "gdb_group", "datum-pool"))) {
        str_reply_tmp = dap_strdup_printf("datum emission %s is placed in datum pool ", l_key_str);
    else{
        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 };
    dap_chain_hash_fast_t l_datum_token_hash = { 0 };
    // create items
    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(&l_token_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++)
        dap_chain_datum_tx_add_sign_item(&l_tx, l_certs[i]->enc_key);

    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);
    l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
    DAP_DELETE(l_tx);

    // Add to mempool emission token
    if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum_tx, l_datum_tx_size
            , dap_config_get_item_str_default(g_config, "mempool", "gdb_group", "datum-pool"))) {
        set_reply_text(str_reply, "%s\ndatum tx %s is placed in datum pool ", str_reply_tmp, l_key_str);
        dap_chain_utxo_tx_add((dap_chain_datum_tx_t*)l_datum_tx->data);
    else{
        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, const 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)
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    uint64_t l_value = 50;

    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_from, 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;
    l_cond.price = l_value;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    int res = dap_chain_mempool_tx_create_cond(l_key, l_key_cond, addr_from,
            addr_cond,
            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);
    set_reply_text(str_reply, "tx_cond_create res=%d", res);
    if(res == 1)
        return 0;
    return -1;
}

/**
 * com_tx_create command
 *
 * Create transaction
 */
int com_tx_create(int argc, const 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;
    uint64_t value = 0;
    uint64_t value_fee = 0;
    find_option_val(argv, arg_index, argc, "from_wallet_name", &l_from_wallet_name);
    find_option_val(argv, arg_index, argc, "to_addr", &addr_base58_to);
    find_option_val(argv, arg_index, argc, "token", &l_token_ticker);

    if(find_option_val(argv, arg_index, argc, "fee", &addr_base58_fee)) {
        if(find_option_val(argv, arg_index, argc, "value_fee", &str_tmp)) {
            value_fee = strtoull(str_tmp, NULL, 10);
        }
    }
    if(find_option_val(argv, arg_index, argc, "value", &str_tmp)) {
        value = strtoull(str_tmp, NULL, 10);
    if(!l_from_wallet_name) {
        set_reply_text(str_reply, "tx_create requires parameter 'from_wallet_name'");
        return -1;
    }
        set_reply_text(str_reply, "tx_create requires parameter 'to_addr'");
        return -1;
    }
    if(!value) {
        set_reply_text(str_reply, "tx_create requires parameter 'value'");
        return -1;
    }
    if(addr_base58_fee && !value_fee) {
        set_reply_text(str_reply, "tx_create requires parameter 'value_fee' if 'fee' is specified");
        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);
    if(!l_wallet) {
        set_reply_text(str_reply, "wallet %s does not exist", l_from_wallet_name);
/*    //debug
    {
        dap_chain_wallet_t * l_wallet_tesla = dap_chain_wallet_open("w_tesla", 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;
    }*/
    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_str_to_addr(addr_base58_to);
    dap_chain_addr_t *addr_fee = dap_chain_str_to_addr(addr_base58_fee);

    if(!addr_from) {
        set_reply_text(str_reply, "source address is invalid");
        return -1;
    }
    if(!addr_to) {
        set_reply_text(str_reply, "destination address is invalid");
        return -1;
    }
    if(addr_base58_fee && !addr_fee) {
        set_reply_text(str_reply, "fee address is invalid");
        return -1;
    }

    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 = dap_chain_mempool_tx_create(dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to, addr_fee,
            l_token_ticker, value, value_fee);
    dap_string_append_printf(string_ret, "transfer=%s\n", (res == 0) ? "Ok" : (res==-2)? "False, not enough funds for transfer" : "False");
    char *str_ret_tmp = dap_string_free(string_ret, false);
    char *str_ret = strdup(str_ret_tmp);
    set_reply_text(str_reply, str_ret);
    DAP_DELETE(str_ret_tmp);
    DAP_DELETE(addr_to);
    DAP_DELETE(addr_fee);
    dap_chain_wallet_close(l_wallet);
    return res;
/**
 * tx_verify command
 *
 * Verifing transaction
 */
int com_tx_verify(int argc, const char ** argv, char **str_reply)
{
    if(argc > 1) {
        const COMMAND *cmd = find_command(argv[1]);
        if(cmd)
        {
            if(str_reply)
                *str_reply = dap_strdup(cmd->doc);
            return 1;
        }
        if(str_reply)
            set_reply_text(str_reply, "command \"%s\" not recognized", argv[1]);
        set_reply_text(str_reply, "command not defined, enter \"help <cmd name>\"");