Skip to content
Snippets Groups Projects
dap_chain_node_cli_cmd.c 94.3 KiB
Newer Older
    if(!l_certs_str) {
        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-certs'");
    // Load certs
    dap_chain_cert_parse_str_list(l_certs_str, &l_certs, &l_certs_size);
    if(!l_certs_size) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply,
                "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);
    if(!l_addr) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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'");
        return -44;
    } 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);
    // Get mempool group for this chain
    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);
    // Create emission datum
    // then create datum in memory
    dap_chain_datum_token_emission_t * l_token_emission;
    size_t l_token_emission_size = sizeof (l_token_emission->hdr) +
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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,
            l_token_emission,
            l_token_emission_size);
    size_t l_datum_emission_size = sizeof(l_datum_emission->header) + l_datum_emission->header.data_size;

    // Delete token emission
    DAP_DELETE(l_token_emission);
    // 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);

    // Add to mempool emission token
    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);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    else {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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++) {
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
        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);
    // calc datum 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);
    DAP_DELETE(l_tx);
    // Add to mempool tx token
    if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum_tx, l_datum_tx_size
            , l_gdb_group_mempool_base_tx)) {
        dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is placed in datum pool ", str_reply_tmp,
                l_key_str);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    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
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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";
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    uint64_t l_value = 50;
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    //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);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    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);

dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    int res = dap_chain_mempool_tx_create_cond(NULL, l_key, l_key_cond, addr_from,
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            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);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    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
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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_net_name = NULL;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    const char * l_chain_name = NULL;
    const char * l_tx_num_str = NULL;
    size_t l_tx_num =0;
    uint64_t value = 0;
    uint64_t value_fee = 0;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed

    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);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value", &str_tmp)) {
        value = strtoull(str_tmp, NULL, 10);
    if(!l_from_wallet_name) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-from_wallet'");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-to_addr'");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value'");
        return -1;
    }
    if(addr_base58_fee && !value_fee) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value_fee' if '-fee' is specified");
    if(!l_net_name) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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 ;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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);
    if(!l_wallet) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "wallet %s does not exist", l_from_wallet_name);
    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);
    if(!addr_from) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "source address is invalid");
        return -1;
    }
    if(!addr_to) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        dap_chain_node_cli_set_reply_text(str_reply, "destination address is invalid");
        return -1;
    }
    if(addr_base58_fee && !addr_fee) {
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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,
            l_token_ticker, value, value_fee);
Aleksandr Lysikov's avatar
Aleksandr Lysikov committed
    dap_string_append_printf(string_ret, "transfer=%s\n",
            (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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);
    dap_chain_wallet_close(l_wallet);
    return res;
/**
 * tx_verify command
 *
 * Verifing transaction
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
int com_tx_verify(int argc, char ** argv, char **str_reply)
{
    if(argc > 1) {
        if(str_reply)
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
            dap_chain_node_cli_set_reply_text(str_reply, "command \"%s\" not recognized", argv[1]);
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
        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>]
 */
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
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;
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    long l_limit = 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;
    }

    // get logs from list
dmitriy.gerasimov's avatar
dmitriy.gerasimov committed
    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;