From 6a5657cc18e13ce55070185d2dcc70895ad56088 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 29 Mar 2022 19:50:45 +0300
Subject: [PATCH] [+] Base TX creation separated from emission

---
 dap-sdk/crypto/include/dap_enc_base58.h     |   1 -
 dap-sdk/crypto/src/dap_enc_base58.c         |  28 ---
 dap-sdk/crypto/src/dap_hash.c               |  40 +++-
 modules/mempool/dap_chain_mempool.c         |  57 +++++
 modules/mempool/include/dap_chain_mempool.h |   5 +
 modules/net/dap_chain_node_cli.c            |   5 +-
 modules/net/dap_chain_node_cli_cmd.c        | 217 ++++++++------------
 modules/net/dap_chain_node_cli_cmd_tx.c     |   6 +-
 modules/type/blocks/dap_chain_cs_blocks.c   |   4 +-
 9 files changed, 194 insertions(+), 169 deletions(-)

diff --git a/dap-sdk/crypto/include/dap_enc_base58.h b/dap-sdk/crypto/include/dap_enc_base58.h
index 8652d7bfd0..8392fb617e 100755
--- a/dap-sdk/crypto/include/dap_enc_base58.h
+++ b/dap-sdk/crypto/include/dap_enc_base58.h
@@ -47,7 +47,6 @@ char* dap_enc_base58_encode_hash_to_str(dap_chain_hash_fast_t *a_in_hash);
 char* dap_enc_base58_from_hex_str_to_str(const char *a_in_str);
 // convert from "Bura1HFrKsqbdytEXQVrxpbovtvLhR1VbrJs65JBx3gc" to "0xA21F1E865B6740A28E8708798ECF25D2C0AA596DF5EB1FD724186B6AD7FF2199"
 char* dap_enc_base58_to_hex_str_from_str(const char *a_in_str);
-int dap_enc_base58_hex_to_hash(const char * a_hex_str,  dap_chain_hash_fast_t * a_datum_hash);
 
 #ifdef __cplusplus
 }
diff --git a/dap-sdk/crypto/src/dap_enc_base58.c b/dap-sdk/crypto/src/dap_enc_base58.c
index 0614fa39ef..12054863ab 100755
--- a/dap-sdk/crypto/src/dap_enc_base58.c
+++ b/dap-sdk/crypto/src/dap_enc_base58.c
@@ -226,34 +226,6 @@ char* dap_enc_base58_encode_hash_to_str(dap_chain_hash_fast_t *a_in_hash)
     return dap_enc_base58_encode_to_str(a_in_hash->raw, sizeof(dap_chain_hash_fast_t));
 }
 
-/**
- * @brief dap_enc_base58_hex_to_hash
- * @param a_hex_str
- * @param a_datum_hash
- * @return
- */
-int dap_enc_base58_hex_to_hash(const char * a_hex_str,  dap_chain_hash_fast_t * a_datum_hash)
-{
-    assert(a_datum_hash);
-
-    if (a_hex_str){
-        char* l_datum_base58 = dap_enc_base58_from_hex_str_to_str(a_hex_str);
-        void * l_decoded = DAP_NEW_Z_SIZE(void,strlen(l_datum_base58));
-        size_t l_decoded_size;
-        if (( l_decoded_size = dap_enc_base58_decode(l_datum_base58, l_decoded))!= sizeof (*a_datum_hash) ){
-            memcpy( a_datum_hash, l_decoded, l_decoded_size);
-            return 0;
-        }else{
-            log_it(L_ERROR,"Wrong hash format: can't parse \"%s\", decoded size %zd when expected %zd", a_hex_str, l_decoded_size,
-                                                                                                       sizeof (*a_datum_hash));
-            return -1;
-        }
-
-    }else
-        return -1;
-}
-
-
 // convert from "0xA21F1E865B6740A28E8708798ECF25D2C0AA596DF5EB1FD724186B6AD7FF2199" to "Bura1HFrKsqbdytEXQVrxpbovtvLhR1VbrJs65JBx3gc"
 char* dap_enc_base58_from_hex_str_to_str(const char *a_in_str)
 {
diff --git a/dap-sdk/crypto/src/dap_hash.c b/dap-sdk/crypto/src/dap_hash.c
index 7a62574684..944c0fea81 100755
--- a/dap-sdk/crypto/src/dap_hash.c
+++ b/dap-sdk/crypto/src/dap_hash.c
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include "dap_common.h"
 #include "dap_hash.h"
+#include "dap_enc_base58.h"
 
 #include "KeccakHash.h"
 #include "SimpleFIPS202.h"
@@ -37,17 +38,17 @@
  * @param a_hash
  * @return
  */
-int dap_chain_hash_fast_from_str( const char * a_hash_str, dap_chain_hash_fast_t * a_hash)
+int dap_chain_hash_fast_from_hex_str( const char *a_hex_str, dap_chain_hash_fast_t *a_hash)
 {
     const size_t c_hash_str_size = sizeof(*a_hash) * 2 + 1 /*trailing zero*/+ 2 /* heading 0x */;
-    size_t l_hash_str_len = strlen( a_hash_str);
+    size_t l_hash_str_len = strlen(a_hex_str);
     if ( l_hash_str_len + 1 == c_hash_str_size ){
         for(size_t l_offset = 2; l_offset < l_hash_str_len; l_offset += 2) {
             char l_byte;
-            if(dap_sscanf(a_hash_str + l_offset, "%02hhx", &l_byte) != 1) {
-                if(dap_sscanf(a_hash_str + l_offset, "%02hhx", &l_byte) != 1) {
+            if(dap_sscanf(a_hex_str + l_offset, "%02hhx", &l_byte) != 1) {
+                if(dap_sscanf(a_hex_str + l_offset, "%02hhx", &l_byte) != 1) {
                     log_it(L_ERROR, "dap_chain_str_to_hash_fast parse error: offset=%zu, hash_str_len=%zu, str=\"%2s\"",
-                            l_offset, l_hash_str_len, a_hash_str + l_offset);
+                            l_offset, l_hash_str_len, a_hex_str + l_offset);
                     return -10 * ((int) l_offset); // Wrong char
                 }
             }
@@ -58,3 +59,32 @@ int dap_chain_hash_fast_from_str( const char * a_hash_str, dap_chain_hash_fast_t
         return -1;
 }
 
+
+/**
+ * @brief dap_chain_hash_fast_from_base58_str
+ * @param a_base58_str
+ * @param a_datum_hash
+ * @return
+ */
+int dap_chain_hash_fast_from_base58_str(const char *a_base58_str,  dap_chain_hash_fast_t *a_hash)
+{
+    if (!a_hash)
+        return -1;
+    if (!a_base58_str)
+        return -2;
+    size_t l_hash_len = dap_strlen(a_base58_str);
+    if (l_hash_len > DAP_ENC_BASE58_ENCODE_SIZE(sizeof(dap_hash_fast_t)))
+        return -3;
+    // from base58 to binary
+    byte_t l_out[DAP_ENC_BASE58_DECODE_SIZE(DAP_ENC_BASE58_ENCODE_SIZE(sizeof(dap_hash_fast_t)))];
+    size_t l_out_size = dap_enc_base58_decode(a_in_str, l_out);
+    if (l_out_size != sizeof(dap_hash_fast_t))
+        return -4;
+    memcpy(a_hash, l_out, sizeof(dap_hash_fast_t));
+    return 0;
+}
+
+int dap_chain_hash_fast_from_str( const char *a_hash_str, dap_chain_hash_fast_t *a_hash)
+{
+    return dap_chain_hash_fast_from_hex_str(a_hash_str, a_hash) && dap_chain_hash_fast_from_base58_str(a_hash_str, a_hash);
+}
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index ee705f2552..c392357992 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -587,6 +587,63 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond(dap_chain_net_t * a_net,
     return l_key_hash;
 }
 
+dap_chain_hash_fast_t *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
+                                                        dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value,
+                                                        dap_chain_addr_t *a_addr_to, dap_cert_t *a_certs, size_t a_certs_count)
+{
+    char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool(a_chain);
+    // 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));
+    l_tx->header.ts_created = time(NULL);
+    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(a_emission_chain_id, a_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(a_addr_to, a_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);
+
+    if (a_certs){
+        // Sign all that we have with certs
+        for(size_t i = 0; i < a_certs_count; i++) {
+            if(dap_chain_datum_tx_add_sign_item(&l_tx, a_certs[i]->enc_key) < 0) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "No private key for certificate=%s",
+                        a_certs[i]->name);
+                DAP_DELETE(l_addr);
+                return NULL;
+            }
+        }
+    }
+
+    DAP_DEL_Z(l_tx_token);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(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);
+    DAP_DEL_Z(l_tx);
+    // calc datum hash
+    dap_chain_hash_fast_t *l_datum_tx_hash = DAP_NEW(dap_hash_fast_t);
+    dap_hash_fast(l_datum_tx, l_datum_tx_size, l_datum_tx_hash);
+    char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(l_datum_tx_hash);
+    // Add to mempool tx token
+    bool l_placed = dap_chain_global_db_gr_set(l_tx_hash_str, l_datum_tx,
+                                               l_datum_tx_size, l_gdb_group_mempool_base_tx);
+    DAP_DEL_Z(l_tx_hash_str);
+    DAP_DELETE(l_datum_tx);
+    if (!l_placed) {
+        return NULL;
+    }
+    return l_datum_tx_hash;
+}
+
 uint8_t* dap_datum_mempool_serialize(dap_datum_mempool_t *datum_mempool, size_t *size)
 {
     size_t a_request_size = 2 * sizeof(uint16_t), shift_size = 0;
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index 9cc95a0723..c9db3876ff 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -5,6 +5,7 @@
 #include "dap_chain_net.h"
 #include "dap_chain_ledger.h"
 #include "dap_http.h"
+#include "dap_cert.h"
 /*
  // datum mempool structure
  typedef struct dap_datum_mempool {
@@ -65,3 +66,7 @@ int dap_chain_mempool_tx_create_massive(dap_chain_t * a_chain, dap_enc_key_t *a_
         const dap_chain_addr_t* a_addr_fee,
         const char a_token_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
         uint256_t a_value, uint256_t a_value_fee, size_t a_tx_num);
+
+dap_chain_hash_fast_t *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_emission_hash,
+                                                        dap_chain_id_t a_emission_chain_id, uint256_t a_emission_value,
+                                                        dap_chain_addr_t *a_addr_to, dap_cert_t *a_certs, size_t a_certs_count);
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index c8da12bf8b..943ee15f77 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -1046,7 +1046,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
             );
 
     dap_chain_node_cli_cmd_item_create ("token_emit", com_token_emit, "Token emission",
-            "token_emit -net <net name> -chain_emission <chain for emission> -chain_base_tx <chain for base tx> -addr <addr> -token <token ticker> -certs <cert> -emission_value <val>\n");
+            "token_emit {sign | -token <token ticker> -emission_value <val>} -net <net name> [-chain_emission <chain for emission>] [-chain_base_tx <chain for base tx> -addr <addr>] -certs <cert list>\n");
 
     dap_chain_node_cli_cmd_item_create ("mempool_list", com_mempool_list, "List mempool entries for selected chain network",
             "mempool_list -net <net name>\n");
@@ -1071,7 +1071,8 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
 
     // Transaction commands
     dap_chain_node_cli_cmd_item_create ("tx_create", com_tx_create, "Make transaction",
-            "tx_create -net <net name> -chain <chain name> -from_wallet <name> -to_addr <addr> -token <token ticker> -value <value> [-fee <addr> -value_fee <val>]\n" );
+            "tx_create -net <net name> -chain <chain name> {-from_wallet <name> -token <token ticker> -value <value> -to_addr <addr> | -from_emission <emission_hash>}"
+                                        "[-fee <addr> -value_fee <val>]\n" );
     dap_chain_node_cli_cmd_item_create ("tx_cond_create", com_tx_cond_create, "Make cond transaction",
                                         "tx_cond_create -net <net name> -token <token ticker> -wallet <from wallet> -cert <public cert>"
                                         "-value <value datoshi> -unit <mb | kb | b | sec | day> -srv_uid <numeric uid>\n" );
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 8e4c92971c..5bff985b8f 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1855,30 +1855,30 @@ int com_tx_wallet(int argc, char ** argv, char **str_reply)
             dap_string_append_printf(l_string_ret, "addr: %s\n", (l_addr_str) ? l_addr_str : "-");
             dap_string_append_printf(l_string_ret, "network: %s\n", (l_net_name ) ? l_net_name : "-");
 
-            size_t l_addr_tokens_size = 0;
-            char **l_addr_tokens = NULL;
-            dap_chain_ledger_addr_get_token_ticker_all_fast(l_ledger, l_addr, &l_addr_tokens, &l_addr_tokens_size);
-            if(l_addr_tokens_size > 0)
+            size_t l_l_addr_tokens_size = 0;
+            char **l_l_addr_tokens = NULL;
+            dap_chain_ledger_addr_get_token_ticker_all_fast(l_ledger, l_addr, &l_l_addr_tokens, &l_l_addr_tokens_size);
+            if(l_l_addr_tokens_size > 0)
                 dap_string_append_printf(l_string_ret, "balance:\n");
             else
                 dap_string_append_printf(l_string_ret, "balance: 0");
 
-            for(size_t i = 0; i < l_addr_tokens_size; i++) {
-                if(l_addr_tokens[i]) {
-                    uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, l_addr, l_addr_tokens[i]);
+            for(size_t i = 0; i < l_l_addr_tokens_size; i++) {
+                if(l_l_addr_tokens[i]) {
+                    uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, l_addr, l_l_addr_tokens[i]);
                     char *l_balance_coins = dap_chain_balance_to_coins(l_balance);
                     char *l_balance_datoshi = dap_chain_balance_print(l_balance);
                     dap_string_append_printf(l_string_ret, "\t%s (%s) %s\n", l_balance_coins,
-                            l_balance_datoshi, l_addr_tokens[i]);
-                    if(i < l_addr_tokens_size - 1)
+                            l_balance_datoshi, l_l_addr_tokens[i]);
+                    if(i < l_l_addr_tokens_size - 1)
                         dap_string_append_printf(l_string_ret, "\n");
                     DAP_DELETE(l_balance_coins);
                     DAP_DELETE(l_balance_datoshi);
 
                 }
-                DAP_DELETE(l_addr_tokens[i]);
+                DAP_DELETE(l_l_addr_tokens[i]);
             }
-            DAP_DELETE(l_addr_tokens);
+            DAP_DELETE(l_l_addr_tokens);
             DAP_DELETE(l_addr_str);
             if(l_wallet)
                 dap_chain_wallet_close(l_wallet);
@@ -2986,8 +2986,8 @@ int com_token_decl(int a_argc, char ** a_argv, char ** a_str_reply)
                 }else if ( strcmp( a_argv[l_arg_index],"-tx_receiver_allowed" )==0){
                     const char *a_tx_receiver_allowed_base58 = NULL;
                     dap_chain_node_cli_find_option_val(a_argv, 0, a_argc, "-tx_receiver_allowed", &a_tx_receiver_allowed_base58);
-                    dap_chain_addr_t *addr_to = dap_chain_addr_from_str(a_tx_receiver_allowed_base58);
-                    dap_tsd_t * l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD, addr_to, sizeof(dap_chain_addr_t));
+                    dap_chain_addr_t *l_addr_to = dap_chain_addr_from_str(a_tx_receiver_allowed_base58);
+                    dap_tsd_t * l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD, l_addr_to, sizeof(dap_chain_addr_t));
                     l_tsd_list = dap_list_append( l_tsd_list, l_tsd);
                     //dap_tsd_t * l_tsd = dap_tsd_create_string(DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_RECEIVER_ALLOWED_ADD, a_tx_receiver_allowed_base58);
                     l_tsd_total_size+= dap_tsd_size( l_tsd);
@@ -3408,9 +3408,10 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_emission_hash);
     // Calc token's hash
     dap_hash_fast(l_emission, l_emission_size, &l_token_emission_hash);
-    l_emission_hash_str = dap_chain_hash_fast_to_str_new(&l_emission_hash);
-    l_emission_hash_str_base58 = dap_enc_base58_encode_hash_to_str(&l_emission_hash);
 
+    bool l_hex_format = dap_strcmp(l_hash_out_type, "hex");
+    l_emission_hash_str = l_hex_format ? dap_chain_hash_fast_to_str_new(&l_emission_hash)
+                                       : dap_enc_base58_encode_hash_to_str(&l_emission_hash);
     // Delete token emission
     DAP_DEL_Z(l_emission);
 
@@ -3420,81 +3421,28 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
                                                l_datum_emission_size,
                                                l_gdb_group_mempool_emission);
     str_reply_tmp = dap_strdup_printf("Datum %s with 256bit emission is%s placed in datum pool",
-                                      dap_strcmp(l_hash_out_type, "hex") ? l_emission_hash_str_base58 : l_emission_hash_str,
-                                      l_placed ? "" : " not");
-    DAP_DELETE((char *)l_emission_hash_str);
-    DAP_DEL_Z(l_emission_hash_str_base58);
+                                      l_emission_hash_str, l_placed ? "" : " not");
+    DAP_DEL_Z(l_emission_hash_str);
     if (!l_placed) {
         DAP_DEL_Z(l_datum_emission);
+        DAP_DEL_Z(l_certs);
         return -1;
     }
 
     if(l_chain_base_tx) {
-            char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool(l_chain_base_tx);
-        // 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));
-        l_tx->header.ts_created = time(NULL);
-        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_chain_emission->id, &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);
-
-        if (l_certs){
-            // 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(a_str_reply, "No private key for certificate=%s",
-                            l_certs[i]->name);
-                    DAP_DELETE(l_addr);
-                    return -3;
-                }
-            }
-        }
-
-        if (l_certs)
-            DAP_DEL_Z(l_certs);
-
-        DAP_DEL_Z(l_tx_token);
-        DAP_DEL_Z(l_in);
-        DAP_DEL_Z(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);
-
-        // 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);
-        char * l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_datum_tx_hash);
-        char * l_tx_hash_str_base58 = dap_enc_base58_encode_hash_to_str(&l_datum_tx_hash);
-        DAP_DEL_Z(l_tx);
-
-        // Add to mempool tx token
-        bool l_placed = dap_chain_global_db_gr_set(dap_strdup(l_tx_hash_str), l_datum_tx,
-                                                   l_datum_tx_size, l_gdb_group_mempool_base_tx);
-        dap_chain_node_cli_set_reply_text(a_str_reply, "%s\nDatum %s with 256bit TX is%s placed in datum pool ",
-                                          str_reply_tmp,
-                                          dap_strcmp(l_hash_out_type, "hex") ? l_tx_hash_str_base58 : l_tx_hash_str,
-                                          l_placed ? "" : " not");
-        DAP_DEL_Z(l_tx_hash_str);
+        dap_chain_hash_fast_t *l_datum_tx_hash = dap_chain_mempool_base_tx_create(l_chain_base_tx, &l_emission_hash,
+                                                                l_chain_emission->id, l_emission_value,
+                                                                l_addr, l_certs, l_certs_size);
+        char *l_tx_hash_str = l_hex_format ? dap_chain_hash_fast_to_str_new(l_datum_tx_hash)
+                                           : dap_enc_base58_encode_hash_to_str(l_datum_tx_hash);
+        = dap_enc_base58_encode_hash_to_str(l_datum_tx_hash);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "%s\nDatum %s with 256bit TX is%s placed in datum pool",
+                                          str_reply_tmp, l_tx_hash_str, l_placed ? "" : " not");
         DAP_DEL_Z(l_tx_hash_str_base58);
         DAP_DELETE(str_reply_tmp);
-        DAP_DELETE(l_addr);
-        if (!l_placed) {
-            DAP_DELETE(l_datum_tx);
-            return -2;
-        }
     }
-
+    DAP_DELETE(l_addr);
+    DAP_DEL_Z(l_certs);
     return 0;
 }
 
@@ -3880,11 +3828,14 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     const char * l_net_name = NULL;
     const char * l_chain_name = NULL;
     const char * l_tx_num_str = NULL;
+    const char *l_emission_hash_str = NULL;
+    dap_chain_hash_fast_t l_emission_hash = {};
     size_t l_tx_num = 0;
 
     uint256_t l_value = {};
     uint256_t l_value_fee = {};
     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, "-from_emission", &l_emission_hash_str);
     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);
@@ -3902,39 +3853,43 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value", &str_tmp)) {
         l_value = dap_chain_balance_scan(str_tmp);
     }
-    if(!l_from_wallet_name) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-from_wallet'");
+    if(!l_from_wallet_name && !l_emission_hash_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires one of parameters '-from_wallet' or '-from_emission'");
         return -1;
     }
     if(!addr_base58_to) {
         dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-to_addr'");
-        return -1;
+        return -2;
     }
-    if(IS_ZERO_256(l_value)) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value'");
-        return -1;
+    if (l_emission_hash_str) {
+        if (dap_chain_hash_fast_from_str(l_emission_hash_str, &l_emission_hash)) {
+            dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-emission_hash' "
+                                                         "to be valid string containing hash in hex or base58 format");
+            return -3;
+        }
+    } else {
+        if(IS_ZERO_256(l_value)) {
+            dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value' to be valid uint256 value");
+            return -4;
+        }
     }
     if(addr_base58_fee && IS_ZERO_256(l_value_fee)) {
         dap_chain_node_cli_set_reply_text(str_reply,
-                "tx_create requires parameter '-value_fee' if '-fee' is specified");
-        return -1;
+                "tx_create requires parameter '-value_fee' to be valid uint256 value if '-fee' is specified");
+        return -5;
     }
 
     if(!l_net_name) {
         dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
-        return -1;
+        return -6;
     }
     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_net == NULL || (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;
+        return -7;
     }
 
-    /*    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) {
         l_chain = dap_chain_net_get_chain_by_chain_type(l_net, CHAIN_TYPE_TX);
@@ -3942,7 +3897,32 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     if(!l_chain) {
         dap_chain_node_cli_set_reply_text(str_reply, "not found chain name '%s', try use parameter '-chain'",
                 l_chain_name);
-        return -1;
+        return -8;
+    }
+
+    dap_chain_addr_t *l_addr_to = dap_chain_addr_from_str(addr_base58_to);
+    if(!l_addr_to) {
+        dap_chain_node_cli_set_reply_text(str_reply, "destination address is invalid");
+        return -11;
+    }
+
+    dap_string_t *string_ret = dap_string_new(NULL);
+    int res = 0;
+    if (l_emission_hash_str) {
+        dap_hash_fast_t *l_tx_hash = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_addr_to);
+        if (l_tx_hash){
+            char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+            dap_chain_hash_fast_to_str(l_tx_hash,l_tx_hash_str,sizeof (l_tx_hash_str)-1);
+            dap_string_append_printf(string_ret, "transfer=Ok\ntx_hash=%s\n",l_tx_hash_str);
+            DAP_DELETE(l_tx_hash);
+        }else{
+            dap_string_append_printf(string_ret, "transfer=False\n");
+            res = -15;
+        }
+        dap_chain_node_cli_set_reply_text(str_reply, string_ret->str);
+        dap_string_free(string_ret, false);
+        DAP_DELETE(l_addr_to);
+        return res;
     }
 
     const char *c_wallets_path = dap_chain_wallet_get_path(g_config);
@@ -3950,49 +3930,36 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
 
     if(!l_wallet) {
         dap_chain_node_cli_set_reply_text(str_reply, "wallet %s does not exist", l_from_wallet_name);
-        return -1;
+        return -9;
     }
     const dap_chain_addr_t *addr_from = (const dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet, l_net->pub.id);
-    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) {
         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;
+        return -10;
     }
     if(addr_base58_fee && !addr_fee) {
         dap_chain_node_cli_set_reply_text(str_reply, "fee address is invalid");
-        return -1;
+        return -12;
     }
-
-    //
     // Check, if network ID is same as ID in destination wallet address. If not - operation is cancelled.
-    //
-
-    if (addr_to->net_id.uint64 != l_net->pub.id.uint64)
-    {
+    if (l_addr_to->net_id.uint64 != l_net->pub.id.uint64) {
         dap_chain_node_cli_set_reply_text(str_reply, "destination wallet network ID=0x%llx and network ID=0x%llx is not equal. Please, change network name or wallet address", 
-                                            addr_to->net_id.uint64, l_net->pub.id.uint64);
-        return -1;
+                                            l_addr_to->net_id.uint64, l_net->pub.id.uint64);
+        return -13;
     }
 
-    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 = 0;
     if(l_tx_num){
         res = dap_chain_mempool_tx_create_massive(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from,
-                               addr_to, addr_fee,
+                               l_addr_to, addr_fee,
                                l_token_ticker, l_value, l_value_fee, l_tx_num);
 
         dap_string_append_printf(string_ret, "transfer=%s\n",
                 (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
     }else{
-        dap_hash_fast_t * l_tx_hash = dap_chain_mempool_tx_create(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, addr_to,
+        dap_hash_fast_t * l_tx_hash = dap_chain_mempool_tx_create(l_chain, dap_chain_wallet_get_key(l_wallet, 0), addr_from, l_addr_to,
                 addr_fee,
                 l_token_ticker, l_value, l_value_fee);
         if (l_tx_hash){
@@ -4002,7 +3969,7 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
             DAP_DELETE(l_tx_hash);
         }else{
             dap_string_append_printf(string_ret, "transfer=False\n");
-            res = -1;
+            res = -14;
         }
 
     }
@@ -4010,7 +3977,7 @@ int com_tx_create(int argc, char ** argv, char **str_reply)
     dap_chain_node_cli_set_reply_text(str_reply, string_ret->str);
     dap_string_free(string_ret, false);
 
-    DAP_DELETE(addr_to);
+    DAP_DELETE(l_addr_to);
     DAP_DELETE(addr_fee);
     dap_chain_wallet_close(l_wallet);
     return res;
@@ -4047,13 +4014,9 @@ int com_tx_verify(int a_argc, char **a_argv, char **a_str_reply)
         *a_str_reply = NULL;
     }
     dap_hash_fast_t l_tx_hash;
-    char *l_hex_str_from58 = NULL;
-    if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash) < 0) {
-        l_hex_str_from58 = dap_enc_base58_to_hex_str_from_str(l_tx_hash_str);
-        if (!l_hex_str_from58) {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid tx hash format, need hex or base58");
-            return -3;
-        }
+    if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash)) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid tx hash format, need hex or base58");
+        return -3;
     }
     size_t l_tx_size = 0;
     char *l_gdb_group = dap_chain_net_get_gdb_group_mempool(l_chain);
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index e0b93b3f27..880710d272 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -1316,8 +1316,7 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
         //const char *l_chain_group = dap_chain_gdb_get_group(l_chain);
         dap_chain_hash_fast_t l_tx_hash;
         if(l_tx_hash_str) {
-            if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash) &&
-                    dap_enc_base58_hex_to_hash(l_tx_hash_str, &l_tx_hash)) {
+            if (dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash)) {
                 l_tx_hash_str = NULL;
                 dap_chain_node_cli_set_reply_text(a_str_reply, "tx hash not recognized");
                 return -1;
@@ -1458,8 +1457,7 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
             return -2;
         }
         dap_chain_hash_fast_t *l_tx_hash = DAP_NEW(dap_chain_hash_fast_t);
-        if (dap_chain_hash_fast_from_str(l_tx_hash_str, l_tx_hash) &&
-                dap_enc_base58_hex_to_hash(l_tx_hash_str, l_tx_hash)) {
+        if (dap_chain_hash_fast_from_str(l_tx_hash_str, l_tx_hash)) {
             dap_chain_node_cli_set_reply_text(a_str_reply, "Can't get hash_fast from %s", l_tx_hash_str);
             return -4;
         }
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 106ee3bee2..1d03a0911f 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -277,7 +277,7 @@ static int s_cli_parse_cmd_hash(char ** a_argv, int a_arg_index, int a_argc, cha
     const char *l_datum_hash_str = NULL;
     dap_chain_node_cli_find_option_val(a_argv, a_arg_index, a_argc, a_param, &l_datum_hash_str);
 
-    return dap_enc_base58_hex_to_hash(l_datum_hash_str, a_datum_hash);
+    return dap_chain_hash_fast_from_str(l_datum_hash_str, a_datum_hash);
 }
 
 /**
@@ -455,7 +455,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
             dap_chain_block_t  * l_block;
             size_t l_block_size = 0;
             dap_chain_hash_fast_t l_block_hash={0};
-            dap_enc_base58_hex_to_hash( l_subcmd_str_arg, &l_block_hash); // Convert argument to hash
+            dap_chain_hash_fast_from_str( l_subcmd_str_arg, &l_block_hash); // Convert argument to hash
             l_block = (dap_chain_block_t*) dap_chain_get_atom_by_hash( l_chain, &l_block_hash, &l_block_size);
             if ( l_block){
                 dap_chain_block_cache_t *l_block_cache = dap_chain_block_cs_cache_get_by_hash(l_blocks, &l_block_hash);
-- 
GitLab