diff --git a/dap_chain_net.c b/dap_chain_net.c
index 76d13df66961e6233e53aa899c231e1afdc1626e..488d08ffa609d910cd1c06d21a42144d0a731f37 100644
--- a/dap_chain_net.c
+++ b/dap_chain_net.c
@@ -1,6 +1,7 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
  * Kelvin Project https://github.com/kelvinblockchain
  * Copyright  (c) 2017-2018
@@ -33,12 +34,22 @@
 #include "dap_string.h"
 #include "dap_strfuncs.h"
 #include "dap_config.h"
-#include "dap_chain_utxo.h"
+#include "dap_hash.h"
 #include "dap_chain_net.h"
 #include "dap_chain_node_client.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
 
+#include "dap_chain_global_db.h"
+#include "dap_chain_global_db_remote.h"
+
+#include "dap_stream_ch_chain_net_pkt.h"
+#include "dap_stream_ch_chain_net.h"
+#include "dap_stream_ch_chain.h"
+#include "dap_stream_ch_chain_pkt.h"
+#include "dap_stream_ch.h"
+#include "dap_stream_ch_pkt.h"
+
 #include "dap_module.h"
 
 #define _XOPEN_SOURCE 700
@@ -57,18 +68,25 @@ typedef struct dap_chain_net_pvt{
     pthread_cond_t state_proc_cond;
     pthread_mutex_t state_mutex;
     dap_chain_node_role_t node_role;
-    uint8_t padding[4];
+    uint8_t padding2[4];
+
+    dap_chain_node_addr_t * node_addr;
+    dap_chain_node_info_t * node_info; // Current node's info
+
+    dap_chain_node_client_t * links;
+    size_t links_count;
 
-    dap_chain_node_client_t * links_by_node_addr;
-    dap_chain_node_client_t * clients_by_ipv4;
-    dap_chain_node_client_t * clients_by_ipv6;
-    size_t clients_count;
+    dap_chain_node_addr_t *links_addrs;
+    size_t links_addrs_count;
 
+    size_t addr_request_attempts;
+    bool load_mode;
     char ** seed_aliases;
     uint16_t seed_aliases_count;
-    uint8_t padding2[6];
+    uint8_t padding3[6];
 
     dap_chain_net_state_t state;
+    dap_chain_net_state_t state_prev;
     dap_chain_net_state_t state_target;
 } dap_chain_net_pvt_t;
 
@@ -88,11 +106,13 @@ static dap_chain_net_item_t * s_net_items_ids = NULL;
 
 static const char * c_net_states[]={
     [NET_STATE_OFFLINE] = "NET_STATE_OFFLINE",
+    [NET_STATE_LINKS_PREPARE ] = "NET_STATE_LINKS_PREPARE",
     [NET_STATE_LINKS_CONNECTING] = "NET_STATE_LINKS_CONNECTING",
     [NET_STATE_LINKS_ESTABLISHED]= "NET_STATE_LINKS_ESTABLISHED",
     [NET_STATE_SYNC_GDB]= "NET_STATE_SYNC_GDB",
     [NET_STATE_SYNC_CHAINS]= "NET_STATE_SYNC_CHAINS",
-    [NET_STATE_SYNC_ALL]= "NET_STATE_STAND_BY"
+    [NET_STATE_ADDR_REQUEST]= "NET_STATE_ADDR_REQUEST",
+    [NET_STATE_ONLINE]= "NET_STATE_ONLINE"
 };
 
 static dap_chain_net_t * s_net_new(const char * a_id, const char * a_name , const char * a_node_role);
@@ -101,7 +121,9 @@ static int s_net_states_proc(dap_chain_net_t * l_net);
 static void * s_net_proc_thread ( void * a_net);
 static void s_net_proc_thread_start( dap_chain_net_t * a_net );
 static void s_net_proc_kill( dap_chain_net_t * a_net );
-
+static void s_gbd_history_callback_notify (void * a_arg,const char a_op_code, const char * a_prefix, const char * a_group,
+                                                     const char * a_key, const void * a_value,
+                                                     const size_t a_value_len);
 static int s_cli_net(int argc, const char ** argv, char **str_reply);
 
 static bool s_seed_mode = false;
@@ -132,6 +154,28 @@ int dap_chain_net_state_go_to(dap_chain_net_t * a_net, dap_chain_net_state_t a_n
     return 0;
 }
 
+/**
+ * @brief s_gbd_history_callback_notify
+ * @param a_op_code
+ * @param a_prefix
+ * @param a_group
+ * @param a_key
+ * @param a_value
+ * @param a_value_len
+ */
+static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, const char * a_prefix, const char * a_group,
+                                                     const char * a_key, const void * a_value,
+                                                     const size_t a_value_len)
+{
+    (void) a_op_code;
+
+    if (a_arg) {
+        dap_chain_net_t * l_net = (dap_chain_net_t *) a_arg;
+        if (!PVT (l_net)->load_mode )
+            dap_chain_net_sync_all(l_net);
+    }
+}
+
 
 /**
  * @brief s_net_states_proc
@@ -140,55 +184,297 @@ int dap_chain_net_state_go_to(dap_chain_net_t * a_net, dap_chain_net_state_t a_n
 static int s_net_states_proc(dap_chain_net_t * l_net)
 {
     int ret=0;
+lb_proc_state:
+    pthread_mutex_lock(&PVT(l_net)->state_mutex );
     switch ( PVT(l_net)->state ){
         case NET_STATE_OFFLINE:{
+            log_it(L_NOTICE,"%s.state: NET_STATE_OFFLINE",l_net->pub.name);
+            dap_chain_node_client_t * l_node_client = NULL, *l_node_client_tmp = NULL;
+            HASH_ITER(hh,PVT(l_net)->links,l_node_client,l_node_client_tmp){
+                HASH_DEL(PVT(l_net)->links, l_node_client);
+                dap_chain_node_client_close(l_node_client);
+            }
+            PVT(l_net)->links_addrs_count = 0;
+            if ( PVT(l_net)->links_addrs )
+                DAP_DELETE(PVT(l_net)->links_addrs);
+            PVT(l_net)->links_addrs = NULL;
+
             if ( PVT(l_net)->state_target != NET_STATE_OFFLINE ){
-                // Check if there are root nodes in list
-                switch ( PVT(l_net)->node_role.enums){
-                    case NODE_ROLE_ROOT_MASTER:
-                    case NODE_ROLE_ROOT:{
-                    }break;
-                    case NODE_ROLE_ARCHIVE:
-                    case NODE_ROLE_CELL_MASTER:
-                    case NODE_ROLE_MASTER:
-                    case NODE_ROLE_FULL:
-                    case NODE_ROLE_LIGHT:
-                    default:{};
-                };
+                PVT(l_net)->state = NET_STATE_LINKS_PREPARE;
+                pthread_mutex_unlock(&PVT(l_net)->state_mutex );
+                goto lb_proc_state;
             }
-        }break;
-        case NET_STATE_LINKS_PINGING:{
-            switch ( PVT(l_net)->node_role.enums){
+        } break;
+        case NET_STATE_LINKS_PREPARE:{
+            log_it(L_NOTICE,"%s.state: NET_STATE_LINKS_PREPARE",l_net->pub.name);
+            switch (PVT(l_net)->node_role.enums) {
+                case NODE_ROLE_ROOT:
                 case NODE_ROLE_ROOT_MASTER:
-                case NODE_ROLE_ROOT:{
-                }break;
                 case NODE_ROLE_ARCHIVE:
-                case NODE_ROLE_CELL_MASTER:
-                case NODE_ROLE_MASTER:
+                case NODE_ROLE_CELL_MASTER:{
+                    // This roles load predefined links from global_db
+                    if ( PVT(l_net)->node_info ) {
+                        if (PVT(l_net)->links_addrs )
+                            DAP_DELETE(PVT(l_net)->links_addrs);
+                        PVT(l_net)->links_addrs_count = PVT(l_net)->node_info->hdr.links_number;
+                        PVT(l_net)->links_addrs = DAP_NEW_Z_SIZE( dap_chain_node_addr_t,
+                                                                  PVT(l_net)->links_addrs_count);
+                        for (size_t i =0 ; i < PVT(l_net)->node_info->hdr.links_number; i++ ){
+                            PVT(l_net)->links_addrs[i].uint64 = PVT(l_net)->node_info->links[i].uint64;
+                        }
+                    }else {
+                        log_it(L_WARNING,"No nodeinfo in global_db to prepare links for connecting");
+                    }
+                } break;
                 case NODE_ROLE_FULL:
-                case NODE_ROLE_LIGHT:
+                case NODE_ROLE_MASTER:
+                case NODE_ROLE_LIGHT:{
+                    // If we haven't any assigned shard - connect to root-0
+                    if ( l_net->pub.cell_id.uint64 == 0 ){
+                        PVT(l_net)->links_addrs_count=1;
+                        PVT(l_net)->links_addrs = DAP_NEW_Z_SIZE(dap_chain_node_addr_t,
+                                                                 PVT(l_net)->links_addrs_count);
+                        dap_chain_node_addr_t * l_node_addr = dap_chain_node_alias_find(l_net, PVT(l_net)->seed_aliases[0] );
+                        PVT(l_net)->links_addrs[0].uint64 = l_node_addr->uint64;
+                    }else {
+                        // TODO read cell's nodelist and populate array with it
+                    }
+                } break;
+            }
+            if ( PVT(l_net)->state_target != NET_STATE_LINKS_PREPARE ){
+                if ( PVT(l_net)->links_addrs_count>0 ) { // If links are present
+                    PVT(l_net)->state = NET_STATE_LINKS_CONNECTING;
+                    log_it(L_DEBUG,"Prepared %u links, start to establish them", PVT(l_net)->links_addrs_count );
+                } else {
+                    log_it(L_WARNING,"No links for connecting, return back to OFFLINE state");
+                    PVT(l_net)->state = NET_STATE_OFFLINE;
+                }
+            }else {
+                log_it(L_WARNING,"Target state is NET_STATE_LINKS_PREPARE? Realy?");
+                PVT(l_net)->state = NET_STATE_OFFLINE;
+            }
+        } pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+        case NET_STATE_LINKS_CONNECTING:{
+            log_it(L_NOTICE,"%s.state: NET_STATE_LINKS_CONNECTING",l_net->pub.name);
+            size_t l_links_established = 0;
+            for (size_t i =0 ; i < PVT(l_net)->links_addrs_count ; i++ ){
+                log_it(L_INFO,"Establishing connection with " NODE_ADDR_FP_STR,
+                       NODE_ADDR_FP_ARGS_S( PVT(l_net)->links_addrs[i]) );
+                dap_chain_node_info_t *l_link_node_info = dap_chain_node_info_read(l_net, &PVT(l_net)->links_addrs[i] );
+                if ( l_link_node_info ) {
+                    dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(l_link_node_info );
+                    if(!l_node_client) {
+                        DAP_DELETE(l_link_node_info);
+                        ret = -1;
+                        break;
+                    }
+                    // wait connected
+                    int timeout_ms = 15000; //15 sec = 15000 ms
+                    int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
+                    if (res == 0 ){
+                        log_it(L_NOTICE, "Connected link %u",i);
+                        l_links_established++;
+                        HASH_ADD(hh,PVT(l_net)->links, remote_node_addr,sizeof(l_node_client->remote_node_addr), l_node_client);
+                    }else {
+                        log_it(L_NOTICE, "Cant establish link %u",i);
+                        dap_chain_node_client_close(l_node_client);
+                    }
+                }
+            }
+            if (l_links_established >0 ){
+                log_it(L_NOTICE, "Established %u links",l_links_established);
+                PVT(l_net)->state = NET_STATE_LINKS_ESTABLISHED;
+            }else {
+                log_it(L_NOTICE, "Can't establish links, go to offline");
+                PVT(l_net)->state = NET_STATE_OFFLINE ;
+                PVT(l_net)->state_target = NET_STATE_OFFLINE ;
+            }
+        } pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+        case NET_STATE_LINKS_ESTABLISHED:{
+            log_it(L_NOTICE,"%s.state: NET_STATE_LINKS_ESTABLISHED",l_net->pub.name);
+            switch (PVT(l_net)->state_target) {
+                case NET_STATE_ONLINE:{ // Online
+                    switch ( PVT(l_net)->node_role.enums ){
+                        case NODE_ROLE_ROOT_MASTER:
+                        case NODE_ROLE_ROOT:{
+                            dap_chain_node_client_t * l_node_client = NULL, *l_node_client_tmp = NULL;
+
+                            // Send everybody your address when linked
+                            HASH_ITER(hh,PVT(l_net)->links,l_node_client,l_node_client_tmp){
+                                dap_stream_ch_chain_net_pkt_write(dap_client_get_stream_ch(
+                                                  l_node_client->client, dap_stream_ch_chain_net_get_id()),
+                                                   DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR, l_net->pub.id,
+                                                   dap_chain_net_get_cur_addr(l_net),
+                                                   sizeof (dap_chain_node_addr_t) );
+                            }
+                        }break;
+                        case NODE_ROLE_CELL_MASTER:
+                        case NODE_ROLE_MASTER:{
+                            PVT(l_net)->state = NET_STATE_ADDR_REQUEST;
+                        } break;
+                       default: PVT( l_net)->state = NET_STATE_SYNC_GDB;
+                    }
+                }pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+                case NET_STATE_SYNC_GDB: // we need only to sync gdb
+                    PVT(l_net)->state = NET_STATE_SYNC_GDB ;
+                    if ( PVT(l_net)->addr_request_attempts >=10 && PVT(l_net)->state == NET_STATE_ADDR_REQUEST){
+                        PVT(l_net)->addr_request_attempts = 0;
+                        switch( PVT(l_net)->state_target){
+                            case NET_STATE_ONLINE:
+                            case NET_STATE_SYNC_GDB:
+                                PVT(l_net)->state = NET_STATE_SYNC_GDB;
+                            pthread_mutex_unlock(&PVT(l_net)->state_mutex );
+                            goto lb_proc_state;
+                            case NET_STATE_SYNC_CHAINS:
+                                PVT(l_net)->state = NET_STATE_SYNC_CHAINS;
+                            pthread_mutex_unlock(&PVT(l_net)->state_mutex );
+                            goto lb_proc_state;
+                            default: {
+                                PVT(l_net)->state = NET_STATE_OFFLINE;
+                                PVT(l_net)->state_target = NET_STATE_OFFLINE;
+                            }
+                        }
+                    }
+                pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+                case NET_STATE_SYNC_CHAINS:
+                    PVT(l_net)->state = (PVT(l_net)->node_info && PVT(l_net)->node_info->hdr.address.uint64)?
+                                NET_STATE_SYNC_CHAINS : NET_STATE_ADDR_REQUEST;
+                pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+                case NET_STATE_ADDR_REQUEST :
+                    PVT(l_net)->state = NET_STATE_ADDR_REQUEST;
+                pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
                 default:{}
-            };
-
+            }
         }break;
-        case NET_STATE_LINKS_CONNECTING:{
+        case NET_STATE_ADDR_REQUEST:{
+            dap_chain_node_client_t * l_node_client = NULL, *l_node_client_tmp = NULL;
+            HASH_ITER(hh,PVT(l_net)->links,l_node_client,l_node_client_tmp){
+                uint8_t l_ch_id = dap_stream_ch_chain_net_get_id(); // Channel id for chain net request
+                size_t res = dap_stream_ch_chain_net_pkt_write(dap_client_get_stream_ch(l_node_client->client,
+                      l_ch_id), DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_REQUEST, l_net->pub.id,
+                                                            NULL, 0 );
+                if(res == 0) {
+                    log_it(L_WARNING,"Can't send NODE_ADDR_REQUEST packet");
+                    HASH_DEL(PVT(l_net)->links,l_node_client);
+                    dap_chain_node_client_close(l_node_client);
+                    continue; // try with another link
+                }
 
-            log_it(L_DEBUG,"Connected %u/% links", PVT(l_net)->clients_count );
-            ret = 1;
-        }break;
-        case NET_STATE_LINKS_ESTABLISHED:{
+                // wait for finishing of request
+                int timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
+                // TODO add progress info to console
+                PVT(l_net)->addr_request_attempts++;
+                int l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_NODE_ADDR_LEASED, timeout_ms);
+                switch (l_res) {
+                    case 0:
+                        log_it(L_WARNING,"Timeout with addr leasing");
+                    continue; // try with another link
+                    case 1:
+                        log_it(L_INFO, "Node address leased");
+                        PVT(l_net)->state = NET_STATE_SYNC_GDB;
+                    pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+                    default:
+                        if ( l_node_client->last_error[0] ){
+                            log_it(L_INFO, "Node address request error %d: \"%s\"",l_res, l_node_client->last_error );
+                            l_node_client->last_error[0]='\0';
+                        }
+                        log_it(L_INFO, "Node address request error %d",l_res);
+                    continue;
+                }
 
+                log_it(L_WARNING,"Haven't received address from any links, return back to LINKS_ESTABLISHED");
+                PVT(l_net)->state = NET_STATE_LINKS_ESTABLISHED;
+                pthread_mutex_unlock(&PVT(l_net)->state_mutex );goto lb_proc_state; // One address assigned its enought for now
+            }
         }break;
         case NET_STATE_SYNC_GDB:{
+            // send request
+            dap_chain_node_client_t * l_node_client = NULL, *l_node_client_tmp = NULL;
+            HASH_ITER(hh,PVT(l_net)->links,l_node_client,l_node_client_tmp){
+                dap_stream_ch_chain_sync_request_t l_sync_gdb = {{0}};
+                // Get last timestamp in log
+                l_sync_gdb.ts_start = (uint64_t) dap_db_log_get_last_timestamp_remote(l_node_client->remote_node_addr.uint64);
+                l_sync_gdb.ts_end = (uint64_t) time(NULL);
+
+                log_it(L_DEBUG,"Prepared request to gdb sync from %llu to %llu",l_sync_gdb.ts_start,l_sync_gdb.ts_end);
+                size_t l_res =  dap_stream_ch_chain_pkt_write( dap_client_get_stream_ch(l_node_client->client,
+                                                                                   dap_stream_ch_chain_get_id() ) ,
+                           DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB, l_net->pub.id, (dap_chain_id_t){{0}} ,
+                                                          l_net->pub.cell_id, &l_sync_gdb, sizeof (l_sync_gdb) );
+                if(l_res == 0) {
+                    log_it(L_WARNING,"Can't send GDB sync request");
+                    HASH_DEL(PVT(l_net)->links,l_node_client);
+                    dap_chain_node_client_close(l_node_client);
+                    continue;
+                }
+
+                // wait for finishing of request
+                int timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
+                // TODO add progress info to console
+                int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+                switch (res) {
+                    case 0:
+                        log_it(L_WARNING,"Timeout with link sync");
+                    break;
+                    case 1:
+                        log_it(L_INFO, "Node sync completed");
+                    break;
+                    default:
+                        log_it(L_INFO, "Node sync error %d",res);
+                }
+            }
+            if ( PVT(l_net)->state_target == NET_STATE_ONLINE ){
+                PVT(l_net)->state = NET_STATE_SYNC_CHAINS;
+            }else {
+                PVT(l_net)->state = NET_STATE_ONLINE;
+            }
+        }    pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
 
-        }break;
         case NET_STATE_SYNC_CHAINS:{
+            dap_chain_node_client_t * l_node_client = NULL, *l_node_client_tmp = NULL;
+            uint8_t l_ch_id = dap_stream_ch_chain_get_id(); // Channel id for global_db sync
+            HASH_ITER(hh,PVT(l_net)->links,l_node_client,l_node_client_tmp){
+                        dap_chain_t * l_chain = NULL;
+                DL_FOREACH(l_net->pub.chains, l_chain ){
+                    size_t l_lasts_size = 0;
+                    dap_chain_atom_ptr_t * l_lasts;
+                    dap_chain_atom_iter_t * l_atom_iter = l_chain->callback_atom_iter_create(l_chain);
+                    l_lasts = l_chain->callback_atom_iter_get_lasts(l_atom_iter,&l_lasts_size);
+                    if ( l_lasts ) {
+                        dap_stream_ch_chain_sync_request_t l_request = {{0}};
+                        dap_hash_fast(l_lasts[0],l_chain->callback_atom_get_size(l_lasts[0]),&l_request.hash_from );
+                        dap_chain_node_client_send_ch_pkt(l_node_client,l_ch_id,
+                                                      DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
+                                                      &l_request,sizeof (l_request) );
+                        // wait for finishing of request
+                        int timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
+                        // TODO add progress info to console
+                        int l_res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+                        switch (l_res) {
+                            case 0:
+                                log_it(L_WARNING,"Timeout with link sync");
+                            break;
+                            case 1:
+                                log_it(L_INFO, "Node sync completed");
+                            break;
+                            default:
+                                log_it(L_INFO, "Node sync error %d",l_res);
+                        }
 
-        }break;
-        case NET_STATE_SYNC_ALL:{
+                        DAP_DELETE( l_lasts );
+                    }
+                    DAP_DELETE( l_atom_iter );
+                }
 
+            }
+            PVT(l_net)->state = NET_STATE_ONLINE;
+        }pthread_mutex_unlock(&PVT(l_net)->state_mutex ); goto lb_proc_state;
+
+        case NET_STATE_ONLINE:{
+            log_it(L_NOTICE,"State online");
         } break;
     }
+    pthread_mutex_unlock(&PVT(l_net)->state_mutex );
     return ret;
 }
 
@@ -207,7 +493,7 @@ static void * s_net_proc_thread ( void * a_net)
         pthread_mutex_lock( &PVT(l_net)->state_mutex );
         pthread_cond_wait(&PVT(l_net)->state_proc_cond,&PVT(l_net)->state_mutex);
         pthread_mutex_unlock( &PVT(l_net)->state_mutex );
-        log_it( L_DEBUG, "Waked up net proc thread");
+        log_it( L_DEBUG, "Waked up net proHASH_COUNT( c thread");
 
     }
     return NULL;
@@ -314,12 +600,20 @@ void dap_chain_net_delete( dap_chain_net_t * a_net )
 int dap_chain_net_init()
 {
     dap_chain_node_cli_cmd_item_create ("net", s_cli_net, "Network commands",
+        "net -net <chain net name> go < online | offline >\n"
+            "\tFind and establish links and stay online\n"
+        "net -net <chain net name> get status\n"
+            "\tLook at current status\n"
         "net -net <chain net name> sync < all | gdb | chains >\n"
             "\tSyncronyze gdb, chains or everything\n\n"
         "net -net <chain net name> link < list | add | del | info | establish >\n"
             "\tList,add,del, dump or establish links\n\n"
                                         );
     s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
+    dap_chain_global_db_add_history_group_prefix("global");
+
+    dap_chain_global_db_add_history_callback_notify("global", s_gbd_history_callback_notify, NULL );
+
     return  0;
 }
 
@@ -338,10 +632,37 @@ static int s_cli_net(int argc, const char ** argv, char **a_str_reply)
     if ( l_net ){
         const char * l_sync_str = NULL;
         const char * l_links_str = NULL;
+        const char * l_go_str = NULL;
+        const char * l_get_str = NULL;
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "sync", &l_sync_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "link", &l_links_str);
+        dap_chain_node_cli_find_option_val(argv, arg_index, argc, "go", &l_go_str);
+        dap_chain_node_cli_find_option_val(argv, arg_index, argc, "get", &l_get_str);
+
+        if ( l_go_str){
+            if ( strcmp(l_go_str,"online") == 0 ) {
+                dap_chain_net_state_go_to(l_net, NET_STATE_ONLINE);
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network \"%s\" go from state %s to %s",
+                                                    l_net->pub.name,c_net_states[PVT(l_net)->state],
+                                                    c_net_states[PVT(l_net)->state_target]);
+            } else if ( strcmp(l_go_str,"offline") == 0 ) {
+                dap_chain_net_state_go_to(l_net, NET_STATE_OFFLINE);
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network \"%s\" go from state %s to %s",
+                                                    l_net->pub.name,c_net_states[PVT(l_net)->state],
+                                                    c_net_states[PVT(l_net)->state_target]);
+
+            }
 
-        if ( l_links_str ){
+        } else if ( l_get_str){
+            if ( strcmp(l_get_str,"status") == 0 ) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network \"%s\" has state %s (target state %s), active links %u from %u",
+                                                    l_net->pub.name,c_net_states[PVT(l_net)->state],
+                                                    c_net_states[PVT(l_net)->state_target], HASH_COUNT( PVT(l_net)->links),
+                                                    PVT(l_net)->links_addrs_count
+                                                  );
+                ret = 0;
+            }
+        } else if ( l_links_str ){
             if ( strcmp(l_links_str,"list") == 0 ) {
 
             } else if ( strcmp(l_links_str,"add") == 0 ) {
@@ -413,30 +734,144 @@ int dap_chain_net_load(const char * a_net_name)
             log_it(L_ERROR,"Can't create l_net");
             return -1;
         }
+        PVT(l_net)->load_mode = true;
         l_net->pub.gdb_groups_prefix = dap_strdup (
                     dap_config_get_item_str_default(l_cfg , "general" , "gdb_groups_prefix","" ) );
+        dap_chain_global_db_add_history_group_prefix( l_net->pub.gdb_groups_prefix);
+        dap_chain_global_db_add_history_callback_notify(l_net->pub.gdb_groups_prefix, s_gbd_history_callback_notify, l_net );
+
+        l_net->pub.gdb_nodes = dap_strdup_printf("%s.nodes",l_net->pub.gdb_groups_prefix);
+        l_net->pub.gdb_nodes_aliases = dap_strdup_printf("%s.nodes.aliases",l_net->pub.gdb_groups_prefix);
 
 
-        // UTXO model
-        uint16_t l_utxo_flags = 0;
+
+        // Add network to the list
+        dap_chain_net_item_t * l_net_item = DAP_NEW_Z( dap_chain_net_item_t);
+        dap_chain_net_item_t * l_net_item2 = DAP_NEW_Z( dap_chain_net_item_t);
+        snprintf(l_net_item->name,sizeof (l_net_item->name),"%s"
+                     ,dap_config_get_item_str(l_cfg , "general" , "name" ));
+        l_net_item->chain_net = l_net;
+        l_net_item->net_id.uint64 = l_net->pub.id.uint64;
+        HASH_ADD_STR(s_net_items,name,l_net_item);
+
+        memcpy( l_net_item2,l_net_item,sizeof (*l_net_item));
+        HASH_ADD(hh,s_net_items_ids,net_id,sizeof ( l_net_item2->net_id),l_net_item2);
+
+        // LEDGER model
+        uint16_t l_ledger_flags = 0;
         switch ( PVT( l_net )->node_role.enums ) {
             case NODE_ROLE_ROOT_MASTER:
             case NODE_ROLE_ROOT:
             case NODE_ROLE_ARCHIVE:
-                l_utxo_flags |= DAP_CHAIN_UTXO_CHECK_TOKEN_EMISSION;
+                l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION;
             case NODE_ROLE_MASTER:
-                l_utxo_flags |= DAP_CHAIN_UTXO_CHECK_CELLS_DS;
+                l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_CELLS_DS;
             case NODE_ROLE_CELL_MASTER:
-                l_utxo_flags |= DAP_CHAIN_UTXO_CHECK_TOKEN_EMISSION;
+                l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION;
             case NODE_ROLE_FULL:
             case NODE_ROLE_LIGHT:
-                l_utxo_flags |= DAP_CHAIN_UTXO_CHECK_LOCAL_DS;
+                l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_LOCAL_DS;
         }
-        dap_chain_utxo_init(l_utxo_flags);
+        // init LEDGER model
+        l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags);
 
         // Check if seed nodes are present in local db alias
         PVT(l_net)->seed_aliases = dap_config_get_array_str( l_cfg , "general" ,"seed_nodes_aliases"
                                                              ,&PVT(l_net)->seed_aliases_count);
+        uint16_t l_seed_nodes_addrs_len =0;
+        char ** l_seed_nodes_addrs = dap_config_get_array_str( l_cfg , "general" ,"seed_nodes_addrs"
+                                                             ,&l_seed_nodes_addrs_len);
+
+        uint16_t l_seed_nodes_ipv4_len =0;
+        char ** l_seed_nodes_ipv4 = dap_config_get_array_str( l_cfg , "general" ,"seed_nodes_ipv4"
+                                                             ,&l_seed_nodes_ipv4_len);
+
+        const char * l_node_ipv4_str = dap_config_get_item_str(l_cfg , "general" ,"node-ipv4");
+        const char * l_node_addr_str = dap_config_get_item_str(l_cfg , "general" ,"node-addr");
+        const char * l_node_alias_str = dap_config_get_item_str(l_cfg , "general" , "node-alias");
+
+        log_it (L_DEBUG, "Read %u aliases, %u address and %u ipv4 addresses, check them",
+                PVT(l_net)->seed_aliases_count,l_seed_nodes_addrs_len, l_seed_nodes_ipv4_len );
+        for ( size_t i = 0; i < PVT(l_net)->seed_aliases_count &&
+                            i < l_seed_nodes_addrs_len &&
+                            i < l_seed_nodes_ipv4_len
+                                                                    ; i++ ){
+            dap_chain_node_addr_t * l_seed_node_addr;
+            l_seed_node_addr = dap_chain_node_alias_find(l_net, PVT(l_net)->seed_aliases[i] );
+            if (l_seed_node_addr == NULL){
+                log_it(L_NOTICE, "Not found alias %s in database, prefill it",PVT(l_net)->seed_aliases[i]);
+                dap_chain_node_info_t * l_node_info = DAP_NEW_Z(dap_chain_node_info_t);
+                l_seed_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
+                snprintf( l_node_info->hdr.alias,sizeof ( l_node_info->hdr.alias),"%s",PVT(l_net)->seed_aliases[i]);
+                if (sscanf(l_seed_nodes_addrs[i],NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS(l_seed_node_addr) ) != 4 ){
+                    log_it(L_ERROR,"Wrong address format,  should be like 0123::4567::890AB::CDEF");
+                    DAP_DELETE(l_seed_node_addr);
+                    DAP_DELETE(l_node_info);
+                    l_seed_node_addr = NULL;
+                    continue;
+                }
+                if( l_seed_node_addr ){
+                    inet_pton( AF_INET, l_seed_nodes_ipv4[i],&l_node_info->hdr.ext_addr_v4);
+                    l_node_info->hdr.address.uint64 = l_seed_node_addr->uint64;
+                    int l_ret;
+                    if ( (l_ret = dap_chain_node_info_save(l_net, l_node_info)) ==0 ){
+                        if (dap_chain_node_alias_register(l_net,PVT(l_net)->seed_aliases[i],l_seed_node_addr))
+                            log_it(L_NOTICE,"Seed node "NODE_ADDR_FP_STR" added to the curent list",NODE_ADDR_FP_ARGS(l_seed_node_addr) );
+                        else {
+                            log_it(L_WARNING,"Cant register alias %s for address "NODE_ADDR_FP_STR,NODE_ADDR_FP_ARGS(l_seed_node_addr));
+                        }
+                    }else{
+                        log_it(L_WARNING,"Cant save node info for address "NODE_ADDR_FP_STR" return code %d",
+                               NODE_ADDR_FP_ARGS(l_seed_node_addr), l_ret);
+                    }
+                    DAP_DELETE( l_seed_node_addr);
+                }else
+                    log_it(L_WARNING,"No address for seed node, can't populate global_db with it");
+                DAP_DELETE( l_node_info);
+            }else
+                log_it(L_DEBUG,"Seed alias %s is present",PVT(l_net)->seed_aliases[i]);
+
+         }
+         DAP_DELETE( l_seed_nodes_ipv4);
+         DAP_DELETE(l_seed_nodes_addrs);
+
+        if ( l_node_alias_str ){
+            dap_chain_node_addr_t * l_node_addr;
+            if ( l_node_addr_str == NULL)
+                l_node_addr = dap_chain_node_alias_find(l_net, l_node_alias_str);
+            else{
+                l_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
+                if ( sscanf(l_node_addr_str, "0x%016llx",&l_node_addr->uint64 ) != 1 ){
+                    sscanf(l_node_addr_str,"0x%016llX",&l_node_addr->uint64);
+                }
+                if( l_node_addr->uint64 == 0 ){
+                    log_it(L_ERROR,"Can't parse node address");
+                    DAP_DELETE(l_node_addr);
+                    l_node_addr = NULL;
+                }
+                PVT(l_net)->node_addr = l_node_addr;
+                //}
+            }
+            if ( l_node_addr ) {
+                char *l_addr_hash_str = dap_chain_node_addr_to_hash_str(l_node_addr);
+                if(!l_addr_hash_str){
+                    log_it(L_ERROR,"Can't get hash string for node address!");
+                } else {
+                    PVT(l_net)->node_info = dap_chain_node_info_read (l_net, l_node_addr);
+                    if ( PVT(l_net)->node_info ) {
+                        log_it(L_NOTICE,"GDB Info: node_addr: " NODE_ADDR_FP_STR"  links: %u cell_id: 0x%0l16X ",
+                               NODE_ADDR_FP_ARGS(l_node_addr),
+                               PVT(l_net)->node_info->hdr.links_number,
+                               PVT(l_net)->node_info->hdr.cell_id.uint64);
+                    }else {
+                        log_it(L_WARNING, "Not present node_info in database for our own address " NODE_ADDR_FP_STR,
+                               NODE_ADDR_FP_ARGS(l_node_addr) );
+                    }
+                }
+            }
+
+
+         }
 
         // Init chains
         size_t l_chains_path_size =strlen(dap_config_path())+1+strlen(l_net->pub.name)+1+strlen("network")+1;
@@ -459,7 +894,7 @@ int dap_chain_net_load(const char * a_net_name)
                         //dap_config_open(l_chains_path);
 
                         // Create chain object
-                        dap_chain_t * l_chain = dap_chain_load_from_cfg(l_net->pub.name, l_net->pub.id, l_chains_path);
+                        dap_chain_t * l_chain = dap_chain_load_from_cfg(l_net->pub.ledger, l_net->pub.name, l_net->pub.id, l_chains_path);
                         if(l_chain){
                             DL_APPEND( l_net->pub.chains, l_chain);
                             if(l_chain->callback_created)
@@ -472,6 +907,8 @@ int dap_chain_net_load(const char * a_net_name)
             }
         } else {
             log_it(L_ERROR,"Can't any chains for network %s",l_net->pub.name);
+            PVT(l_net)->load_mode = false;
+
             return -2;
         }
 
@@ -490,7 +927,7 @@ int dap_chain_net_load(const char * a_net_name)
                 if (l_chain )
                    l_chain->is_datum_pool_proc = true;
 
-                PVT(l_net)->state_target = NET_STATE_SYNC_ALL;
+                PVT(l_net)->state_target = NET_STATE_ONLINE;
                 log_it(L_INFO,"Root node role established");
             } break;
             case NODE_ROLE_CELL_MASTER:
@@ -499,12 +936,12 @@ int dap_chain_net_load(const char * a_net_name)
                 dap_chain_id_t l_chain_id = { .raw = {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x01} };
                 dap_chain_t * l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id );
                 l_chain->is_datum_pool_proc = true;
-                PVT(l_net)->state_target = NET_STATE_SYNC_ALL;
+                PVT(l_net)->state_target = NET_STATE_ONLINE;
                 log_it(L_INFO,"Master node role established");
             } break;
             case NODE_ROLE_FULL:{
                 log_it(L_INFO,"Full node role established");
-                PVT(l_net)->state_target = NET_STATE_SYNC_ALL;
+                PVT(l_net)->state_target = NET_STATE_ONLINE;
             } break;
             case NODE_ROLE_LIGHT:
             default:
@@ -515,17 +952,7 @@ int dap_chain_net_load(const char * a_net_name)
         if (s_seed_mode) { // If we seed we do everything manual. First think - prefil list of node_addrs and its aliases
             PVT(l_net)->state_target = NET_STATE_OFFLINE;
         }
-        // Add network to the list
-        dap_chain_net_item_t * l_net_item = DAP_NEW_Z( dap_chain_net_item_t);
-        dap_chain_net_item_t * l_net_item2 = DAP_NEW_Z( dap_chain_net_item_t);
-        snprintf(l_net_item->name,sizeof (l_net_item->name),"%s"
-                     ,dap_config_get_item_str(l_cfg , "general" , "name" ));
-        l_net_item->chain_net = l_net;
-        l_net_item->net_id.uint64 = l_net->pub.id.uint64;
-        HASH_ADD_STR(s_net_items,name,l_net_item);
-
-        memcpy( l_net_item2,l_net_item,sizeof (*l_net_item));
-        HASH_ADD(hh,s_net_items_ids,net_id,sizeof ( l_net_item2->net_id),l_net_item2);
+        PVT(l_net)->load_mode = false;
 
         // Start the proc thread
         s_net_proc_thread_start(l_net);
@@ -549,13 +976,27 @@ void dap_chain_net_deinit()
 dap_chain_net_t * dap_chain_net_by_name( const char * a_name)
 {
     dap_chain_net_item_t * l_net_item = NULL;
-    HASH_FIND_STR(s_net_items,a_name,l_net_item );
+    if(a_name)
+        HASH_FIND_STR(s_net_items,a_name,l_net_item );
     if ( l_net_item )
         return l_net_item->chain_net;
     else
         return NULL;
 }
 
+/**
+ * @brief dap_chain_ledger_by_net_name
+ * @param a_net_name
+ * @return
+ */
+dap_ledger_t * dap_chain_ledger_by_net_name( const char * a_net_name)
+{
+    dap_chain_net_t *l_net = dap_chain_net_by_name(a_net_name);
+    if(l_net)
+        return l_net->pub.ledger;
+    return NULL;
+}
+
 /**
  * @brief dap_chain_net_by_id
  * @param a_id
@@ -603,7 +1044,20 @@ dap_chain_t * dap_chain_net_get_chain_by_name( dap_chain_net_t * l_net, const ch
    return NULL;
 }
 
+/**
+ * @brief dap_chain_net_get_cur_addr
+ * @param l_net
+ * @return
+ */
+dap_chain_node_addr_t * dap_chain_net_get_cur_addr( dap_chain_net_t * l_net)
+{
+    return  PVT(l_net)->node_info? &PVT(l_net)->node_info->hdr.address: PVT(l_net)->node_addr;
+}
 
+/**
+ * @brief dap_chain_net_proc_datapool
+ * @param a_net
+ */
 void dap_chain_net_proc_datapool (dap_chain_net_t * a_net)
 {
 
diff --git a/dap_chain_net.h b/dap_chain_net.h
index e738dd252771315d0a12191692c94491a45d3c6a..4cf307089b2afd038bb081aad0b14f7ba9e031a1 100644
--- a/dap_chain_net.h
+++ b/dap_chain_net.h
@@ -1,6 +1,7 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
  * Kelvin Project https://github.com/kelvinblockchain
  * Copyright  (c) 2017-2019
@@ -28,19 +29,22 @@
 #include <stdint.h>
 #include <string.h>
 #include "dap_chain_common.h"
+#include "dap_chain_node.h"
 #include "dap_chain.h"
+#include "dap_chain_ledger.h"
 
 
 #define DAP_CHAIN_NET_NAME_MAX 32
 
 typedef  enum dap_chain_net_state{
     NET_STATE_OFFLINE = 0,
-    NET_STATE_LINKS_PINGING,
+    NET_STATE_LINKS_PREPARE,
     NET_STATE_LINKS_CONNECTING,
     NET_STATE_LINKS_ESTABLISHED,
+    NET_STATE_ADDR_REQUEST, // Waiting for address assign
     NET_STATE_SYNC_GDB,
     NET_STATE_SYNC_CHAINS,
-    NET_STATE_SYNC_ALL,
+    NET_STATE_ONLINE,
 } dap_chain_net_state_t;
 
 
@@ -50,7 +54,11 @@ typedef struct dap_chain_net{
         dap_chain_cell_id_t cell_id; // Cell where the node is connected to. {{0}} if not celled(sharder) blockchain
         char * name;
         char * gdb_groups_prefix;
+        char * gdb_nodes_aliases;
+        char * gdb_nodes;
+
         dap_chain_t * chains; // double-linked list of chains
+        dap_ledger_t  *ledger;
     } pub;
     uint8_t pvt[];
 } dap_chain_net_t;
@@ -63,12 +71,12 @@ int dap_chain_net_load(const char * a_net_name);
 
 int dap_chain_net_state_go_to(dap_chain_net_t * a_net, dap_chain_net_state_t a_new_state);
 
-inline static int dap_chain_net_start(dap_chain_net_t * a_net){ return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_ALL); }
+inline static int dap_chain_net_start(dap_chain_net_t * a_net){ return dap_chain_net_state_go_to(a_net,NET_STATE_ONLINE); }
 inline static int dap_chain_net_stop(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_OFFLINE); }
 inline static int dap_chain_net_links_establish(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_LINKS_ESTABLISHED); }
 inline static int dap_chain_net_sync_chains(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
 inline static int dap_chain_net_sync_gdb(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_GDB); }
-inline static int dap_chain_net_sync_all(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_ALL); }
+inline static int dap_chain_net_sync_all(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_ONLINE); }
 
 void dap_chain_net_delete( dap_chain_net_t * a_net);
 void dap_chain_net_proc_datapool (dap_chain_net_t * a_net);
@@ -76,11 +84,15 @@ void dap_chain_net_proc_datapool (dap_chain_net_t * a_net);
 dap_chain_net_t * dap_chain_net_by_name( const char * a_name);
 dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id);
 dap_chain_net_id_t dap_chain_net_id_by_name( const char * a_name);
+dap_ledger_t * dap_chain_ledger_by_net_name( const char * a_net_name);
 
 dap_chain_t * dap_chain_net_get_chain_by_name( dap_chain_net_t * l_net, const char * a_name);
 
+dap_chain_node_addr_t * dap_chain_net_get_cur_addr( dap_chain_net_t * l_net);
+
 void dap_chain_net_links_connect(dap_chain_net_t * a_net);
 
+
 /**
  * @brief dap_chain_net_get_gdb_group_mempool
  * @param l_chain
@@ -95,7 +107,7 @@ static inline char * dap_chain_net_get_gdb_group_mempool(dap_chain_t * l_chain)
         size_t l_ret_size =  strlen( l_net->pub.gdb_groups_prefix ) + 1 +
                 strlen( l_chain->name)+1+strlen(c_mempool_group_str)+1;
         l_ret = DAP_NEW_Z_SIZE(char, l_ret_size);
-        snprintf( l_ret,l_ret_size,"%s.%s.%s",l_net->pub.gdb_groups_prefix,l_chain->name,c_mempool_group_str);
+        snprintf( l_ret,l_ret_size,"%s.chain-%s.%s",l_net->pub.gdb_groups_prefix,l_chain->name,c_mempool_group_str);
     }
     return l_ret;
 }
diff --git a/dap_chain_node.c b/dap_chain_node.c
index 980ce0bd52e15a45e7d15e6641ac1e7dddfbff85..8358cc143bbf9255a9a8f9b4a9410ff8ffb54d4b 100644
--- a/dap_chain_node.c
+++ b/dap_chain_node.c
@@ -34,7 +34,7 @@
 /**
  * Generate node address by shard id
  */
-dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_cell_id_t *shard_id)
+dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_net_t * a_net,dap_chain_cell_id_t *shard_id)
 {
     if(!shard_id)
         return NULL;
@@ -51,9 +51,9 @@ dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_cell_id_t *shard_id)
 }
 
 /**
- * Check the validity of the node address by shard id
+ * Check the validity of the node address by cell id
  */
-bool dap_chain_node_check_addr(dap_chain_node_addr_t *addr, dap_chain_cell_id_t *shard_id)
+bool dap_chain_node_check_addr(dap_chain_net_t * a_net,dap_chain_node_addr_t *addr, dap_chain_cell_id_t *shard_id)
 {
     bool ret = false;
     if(!addr || !shard_id)
@@ -65,14 +65,15 @@ bool dap_chain_node_check_addr(dap_chain_node_addr_t *addr, dap_chain_cell_id_t
 /**
  * Register alias in base
  */
-bool dap_chain_node_alias_register(const char *alias, dap_chain_node_addr_t *addr)
+bool dap_chain_node_alias_register(dap_chain_net_t * a_net,const char *alias, dap_chain_node_addr_t *addr)
 {
     const char *a_key = alias;
 //    char a_value[2 * sizeof(dap_chain_node_addr_t) + 1];
 //    if(bin2hex(a_value, (const unsigned char *) addr, sizeof(dap_chain_node_addr_t)) == -1)
 //        return false;
 //    a_value[2 * sizeof(dap_chain_node_addr_t)] = '\0';
-    bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t*) addr, sizeof(dap_chain_node_addr_t), GROUP_ALIAS);
+    bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t*) addr, sizeof(dap_chain_node_addr_t)
+                                          , a_net->pub.gdb_nodes_aliases);
     return res;
 }
 
@@ -81,21 +82,21 @@ bool dap_chain_node_alias_register(const char *alias, dap_chain_node_addr_t *add
  * @param alias
  * @return
  */
-dap_chain_node_addr_t * dap_chain_node_alias_find(const char *a_alias)
+dap_chain_node_addr_t * dap_chain_node_alias_find(dap_chain_net_t * a_net,const char *a_alias)
 {
     size_t l_addr_size =0;
     dap_chain_node_addr_t * l_addr = (dap_chain_node_addr_t *)
-            dap_chain_global_db_gr_get(a_alias, &l_addr_size, GROUP_ALIAS);
+            dap_chain_global_db_gr_get(a_alias, &l_addr_size, a_net->pub.gdb_nodes_aliases);
     return  l_addr;
 }
 
 /**
  * Delete alias from base
  */
-bool dap_chain_node_alias_delete(const char *alias)
+bool dap_chain_node_alias_delete(dap_chain_net_t * a_net,const char *a_alias)
 {
-    const char *a_key = alias;
-    bool res = dap_chain_global_db_gr_del(a_key, GROUP_ALIAS);
+    const char *a_key = a_alias;
+    bool res = dap_chain_global_db_gr_del(a_key, a_net->pub.gdb_nodes_aliases);
     return res;
 }
 
@@ -114,8 +115,68 @@ size_t dap_chain_node_info_get_size(dap_chain_node_info_t *node_info)
     return (sizeof(dap_chain_node_info_t) + node_info->hdr.links_number * sizeof(dap_chain_node_addr_t));
 }
 
+/**
+ * @brief dap_chain_node_info_save
+ * @param node_info
+ * @return
+ */
+int dap_chain_node_info_save(dap_chain_net_t * a_net, dap_chain_node_info_t *node_info)
+{
+    if(!node_info || !node_info->hdr.address.uint64){
+        log_it(L_ERROR,"Can't save node info: %s", node_info? "null address":"null object" );
+        return  -1;
+    }
+    char *l_key = dap_chain_node_addr_to_hash_str(&node_info->hdr.address);
 
+    if(!l_key){
+        log_it(L_ERROR,"Can't produce key to save node info ");
+        return -2;
+    }
+    //char *a_value = dap_chain_node_info_serialize(node_info, NULL);
+    size_t node_info_size = dap_chain_node_info_get_size(node_info);
+    bool res = dap_chain_global_db_gr_set(l_key, (const uint8_t *) node_info, node_info_size, a_net->pub.gdb_nodes);
+    DAP_DELETE(l_key);
+    //DAP_DELETE(a_value);
+    return res?0:-3;
+}
 
+/**
+ * Read node from base
+ */
+dap_chain_node_info_t* dap_chain_node_info_read( dap_chain_net_t * a_net,dap_chain_node_addr_t *l_address)
+{
+    char *l_key = dap_chain_node_addr_to_hash_str(l_address);
+    if(!l_key) {
+        log_it(L_WARNING,"Can't calculate hash of addr");
+        return NULL;
+    }
+    size_t node_info_size = 0;
+    dap_chain_node_info_t *l_node_info;
+    // read node
+    l_node_info = (dap_chain_node_info_t *) dap_chain_global_db_gr_get(l_key, &node_info_size, a_net->pub.gdb_nodes);
+
+    if(!l_node_info) {
+        log_it(L_ERROR, "node with key %s (addr " NODE_ADDR_FP_STR ") not found in base",l_key, NODE_ADDR_FP_ARGS(l_address));
+        DAP_DELETE(l_key);
+        return NULL;
+    }
+
+    size_t node_info_size_must_be = dap_chain_node_info_get_size(l_node_info);
+    if(node_info_size_must_be != node_info_size) {
+        log_it(L_ERROR, "Node has bad size in base=%u (must be %u)", node_info_size, node_info_size_must_be);
+        DAP_DELETE(l_node_info);
+        DAP_DELETE(l_key);
+        return NULL;
+    }
+
+//    dap_chain_node_info_t *node_info = dap_chain_node_info_deserialize(str, (str) ? strlen(str) : 0);
+//    if(!node_info) {
+//        set_reply_text(str_reply, "node has invalid format in base");
+//    }
+//    DAP_DELETE(str);
+    DAP_DELETE(l_key);
+    return l_node_info;
+}
 
 
 /**
diff --git a/dap_chain_node.h b/dap_chain_node.h
index 62b3f3a44a8aae24815849f3e6fb1323ef187393..347aef94b646e580e2508419eefe56dc17d2aa09 100644
--- a/dap_chain_node.h
+++ b/dap_chain_node.h
@@ -30,16 +30,9 @@
 
 #include "dap_common.h"
 #include "dap_chain_common.h"
+#include "dap_chain_global_db.h"
 
-/**
-  * @struct Node address
-  *
-  */
-typedef union dap_chain_node_addr{
-    uint64_t uint64;
-    uint8_t raw[sizeof(uint64_t)];  // Access to selected octects
-} DAP_ALIGN_PACKED dap_chain_node_addr_t;
-
+typedef struct dap_chain_net dap_chain_net_t;
 /**
   *  Node Declaration request
   *
@@ -113,15 +106,24 @@ size_t dap_chain_node_info_get_size(dap_chain_node_info_t *node_info);
 /**
  * Generate node addr by shard id
  */
-dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_cell_id_t *shard_id);
+dap_chain_node_addr_t* dap_chain_node_gen_addr(dap_chain_net_t * l_net,dap_chain_cell_id_t *a_cell_id);
 
 /**
  * Check the validity of the node address by shard id
  */
-bool dap_chain_node_check_addr(dap_chain_node_addr_t *addr, dap_chain_cell_id_t *shard_id);
+bool dap_chain_node_check_addr(dap_chain_net_t * l_net,dap_chain_node_addr_t *addr, dap_chain_cell_id_t *a_cell_id);
 
-dap_chain_node_addr_t * dap_chain_node_alias_find(const char *alias);
-bool dap_chain_node_alias_register(const char *alias, dap_chain_node_addr_t *addr);
-bool dap_chain_node_alias_delete(const char *alias);
+dap_chain_node_addr_t * dap_chain_node_alias_find(dap_chain_net_t * l_net,const char *alias);
+bool dap_chain_node_alias_register(dap_chain_net_t * l_net,const char *alias, dap_chain_node_addr_t *addr);
+bool dap_chain_node_alias_delete(dap_chain_net_t * l_net,const char *alias);
+
+int dap_chain_node_info_save(dap_chain_net_t * l_net,dap_chain_node_info_t *node_info);
+dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_net_t * l_net, dap_chain_node_addr_t *address);
+
+inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *address)
+{
+    char *a_key = dap_chain_global_db_hash((const uint8_t*) address, sizeof(dap_chain_node_addr_t));
+    return a_key;
+}
 
 
diff --git a/dap_chain_node_cli.c b/dap_chain_node_cli.c
index 4913852c03a7f9f15a013a65904addba881f2d94..902ad6f5f6e64fdec6bf5673e7a716d3327ef7cc 100644
--- a/dap_chain_node_cli.c
+++ b/dap_chain_node_cli.c
@@ -1,7 +1,11 @@
 /*
  * Authors:
- * Dmitriy A. Gearasimov <naeper@demlabs.net>
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2019
+ * All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
 
@@ -300,9 +304,11 @@ static void* thread_one_client_func(void *args)
                 }
                 char *reply_body = dap_strdup_printf("ret_code: %d\r\n%s\r\n", res, (str_reply) ? str_reply : "");
                 // return the result of the command function
-                char *reply_str = dap_strdup_printf("HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s",
+                char *reply_str = dap_strdup_printf("HTTP/1.1 200 OK\r\n"
+                                                    "Content-Length: %d\r\n\r\n"
+                                                    "%s",
                         strlen(reply_body), reply_body);
-                int ret = send(newsockfd, reply_str, strlen(reply_str) + 1, 1000);
+                int ret = send(newsockfd, reply_str, strlen(reply_str) ,0);
                 DAP_DELETE(str_reply);
                 DAP_DELETE(reply_str);
                 DAP_DELETE(reply_body);
@@ -356,7 +362,7 @@ void dap_chain_node_cli_set_reply_text(char **str_reply, const char *str, ...)
 {
     if(str_reply) {
         if(*str_reply) {
-            assert(!*str_reply);
+            assert(! *str_reply );
             DAP_DELETE(*str_reply);
             *str_reply = NULL;
         }
@@ -457,15 +463,13 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
            "global_db node add  -net <net name> -addr {<node address> | -alias <node alias>} -cell <cell id>  {-ipv4 <ipv4 external address> | -ipv6 <ipv6 external address>}\n\n"
                     "global_db node del  -net <net name> -addr <node address> | -alias <node alias>\n\n"
                     "global_db node link {add|del}  -net <net name> {-addr <node address> | -alias <node alias>} -link <node address>\n\n"
-                    "global_db node dump  -net <net name>\n\n"
-                    "global_db node dump  -net <net name> -addr <node address> | -alias <node alias>\n\n"
-                    "global_db node get -net <net name>\n\n"
-                    "global_db node set -net <net name> -addr <node address> | -alias <node alias>\n\n"
-          "global_db node remote_set -addr <node address> | -alias <node alias>\n");
+                        );
     dap_chain_node_cli_cmd_item_create ("node", com_node, "Work with node",
             "node alias {<node address> | -alias <node alias>}\n\n"
                     "node connect {<node address> | -alias <node alias>}\n\n"
-                    "node handshake {<node address> | -alias <node alias>}\n");
+                    "node handshake {<node address> | -alias <node alias>}\n"
+                    "node dump -net <net name> [ -addr <node address> | -alias <node alias>]\n\n"
+                                        );
     dap_chain_node_cli_cmd_item_create ("ping", com_ping, "Send ICMP ECHO_REQUEST to network hosts",
             "ping [-c <count>] host\n");
     dap_chain_node_cli_cmd_item_create ("traceroute", com_traceroute, "Print the hops and time of packets trace to network host",
@@ -481,7 +485,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                                         "\tObtain help for <command> or get the total list of the commands\n"
                                         );
     dap_chain_node_cli_cmd_item_create("wallet", com_tx_wallet, "Wallet operations",
-            "wallet [new -w <wallet_name> | list | info -addr <addr> -w <wallet_name>]\n");
+            "wallet [new -w <wallet_name> | list | info -addr <addr> -w <wallet_name> -net <net_name>]\n");
 
     // Token commands
     dap_chain_node_cli_cmd_item_create ("token_decl", com_token_decl, "Token declaration",
@@ -497,7 +501,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 -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");
 
     dap_chain_node_cli_cmd_item_create ("mempool_list", com_mempool_list, "List mempool entries for selected chain network and chain id",
             "mempool_list -net <net name> -chain <chain name>\n");
@@ -511,7 +515,7 @@ 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 from_wallet_name <name> to_addr <addr> token <token> value <val> [fee <addr> value_fee <val>]\n" );
+            "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" );
     dap_chain_node_cli_cmd_item_create ("tx_cond_create", com_tx_cond_create, "Make cond transaction",
             "tx_cond_create todo\n" );
     dap_chain_node_cli_cmd_item_create ("tx_verify", com_tx_verify, "Verifing transaction",
diff --git a/dap_chain_node_cli.h b/dap_chain_node_cli.h
index f7fd19f4c633070086cbd0d74b870835e2fcc0fc..f41b637254e1a356306010738f4e3f4df4e07ceb 100644
--- a/dap_chain_node_cli.h
+++ b/dap_chain_node_cli.h
@@ -1,23 +1,28 @@
 /*
  * Authors:
- * Dmitriy A. Gearasimov <naeper@demlabs.net>
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2019
+ * All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
+ DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+ DAP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
 #pragma once
 
 #include "dap_common.h"
diff --git a/dap_chain_node_cli_cmd.c b/dap_chain_node_cli_cmd.c
index 97d0935e7fc346ab9ababded622f9665a5e27bc5..daec8d9922538243fc79f74b93ca53ab8e5dfe4e 100644
--- a/dap_chain_node_cli_cmd.c
+++ b/dap_chain_node_cli_cmd.c
@@ -1,9 +1,10 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
  * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * Copyright  (c) 2019
  * All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
@@ -37,6 +38,10 @@
 #include <dirent.h>
 
 #include "iputils/iputils.h"
+
+#include "uthash.h"
+#include "utlist.h"
+
 #include "dap_string.h"
 #include "dap_hash.h"
 #include "dap_chain_common.h"
@@ -54,12 +59,15 @@
 
 #include "dap_chain_datum.h"
 #include "dap_chain_datum_tx_items.h"
-#include "dap_chain_utxo.h"
+#include "dap_chain_ledger.h"
 #include "dap_chain_mempool.h"
 #include "dap_chain_global_db.h"
 #include "dap_chain_global_db_remote.h"
 
 #include "dap_stream_ch_chain_net.h"
+#include "dap_stream_ch_chain.h"
+#include "dap_stream_ch_chain_pkt.h"
+#include "dap_stream_ch_chain_net_pkt.h"
 
 #define LOG_TAG "chain_node_cli_cmd"
 
@@ -68,14 +76,14 @@
  *
  * return addr, NULL if not found
  */
-dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias(const char *a_alias)
+dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias( dap_chain_net_t * a_net, const char *a_alias)
 {
     dap_chain_node_addr_t *l_addr = NULL;
     if(!a_alias)
         return NULL;
     const char *a_key = a_alias;
     size_t l_addr_size = 0;
-    l_addr = (dap_chain_node_addr_t*) (void*) dap_chain_global_db_gr_get(a_key, &l_addr_size, GROUP_ALIAS);
+    l_addr = (dap_chain_node_addr_t*) (void*) dap_chain_global_db_gr_get(a_key, &l_addr_size, a_net->pub.gdb_nodes_aliases);
     if(l_addr_size != sizeof(dap_chain_node_addr_t)) {
 //        l_addr = DAP_NEW_Z(dap_chain_node_addr_t);
 //        if(hex2bin((char*) l_addr, (const unsigned char *) addr_str, sizeof(dap_chain_node_addr_t) * 2) == -1) {
@@ -92,14 +100,14 @@ dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias(const char *a_alias)
  *
  * return list of addr, NULL if not found
  */
-static dap_list_t* get_aliases_by_name(dap_chain_node_addr_t *a_addr)
+static dap_list_t* get_aliases_by_name(dap_chain_net_t * l_net, dap_chain_node_addr_t *a_addr)
 {
     if(!a_addr)
         return NULL;
     dap_list_t *list_aliases = NULL;
     size_t data_size = 0;
     // read all aliases
-    dap_global_db_obj_t **objs = dap_chain_global_db_gr_load(GROUP_ALIAS, &data_size);
+    dap_global_db_obj_t **objs = dap_chain_global_db_gr_load(l_net->pub.gdb_nodes_aliases, &data_size);
     if(!objs || !data_size)
         return NULL;
     for(size_t i = 0; i < data_size; i++) {
@@ -126,50 +134,44 @@ static dap_list_t* get_aliases_by_name(dap_chain_node_addr_t *a_addr)
     return list_aliases;
 }
 
-static dap_chain_node_addr_t* com_global_db_get_addr(dap_chain_node_info_t *node_info,
-        dap_chain_node_addr_t *addr, const char *alias_str)
+static dap_chain_node_addr_t* node_info_get_addr(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info,
+        dap_chain_node_addr_t *a_addr, const char *a_alias_str)
 {
-    dap_chain_node_addr_t *address = NULL;
-    if(alias_str && !addr->uint64) {
-        address = dap_chain_node_addr_get_by_alias(alias_str);
+    dap_chain_node_addr_t *l_address = NULL;
+    if(a_alias_str && !a_addr->uint64) {
+        l_address = dap_chain_node_addr_get_by_alias(a_net, a_alias_str);
     }
-    if(addr->uint64) {
-        address = DAP_NEW(dap_chain_node_addr_t);
-        address->uint64 = addr->uint64;
+    if(a_addr->uint64) {
+        l_address = DAP_NEW(dap_chain_node_addr_t);
+        l_address->uint64 = a_addr->uint64;
     }
-    return address;
-}
-
-char* com_global_db_get_key_for_addr(dap_chain_node_addr_t *address)
-{
-    char *a_key = dap_chain_global_db_hash((const uint8_t*) address, sizeof(dap_chain_node_addr_t));
-    return a_key;
+    return l_address;
 }
 
 /**
  * Read node from base
  */
-static dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_node_addr_t *address, char **str_reply)
+static dap_chain_node_info_t* node_info_read_and_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_address, char **a_str_reply)
 {
-    char *l_key = com_global_db_get_key_for_addr(address);
+    char *l_key = dap_chain_node_addr_to_hash_str(a_address);
     if(!l_key)
     {
-        dap_chain_node_cli_set_reply_text(str_reply, "can't calculate hash of addr");
+        dap_chain_node_cli_set_reply_text(a_str_reply, "can't calculate hash of addr");
         return NULL;
     }
     size_t node_info_size = 0;
     dap_chain_node_info_t *node_info;
     // read node
-    node_info = (dap_chain_node_info_t *) dap_chain_global_db_gr_get(l_key, &node_info_size, GROUP_NODE);
+    node_info = (dap_chain_node_info_t *) dap_chain_global_db_gr_get(l_key, &node_info_size, a_net->pub.gdb_nodes);
 
     if(!node_info) {
-        dap_chain_node_cli_set_reply_text(str_reply, "node not found in base");
+        dap_chain_node_cli_set_reply_text(a_str_reply, "node not found in base");
         DAP_DELETE(l_key);
         return NULL;
     }
     size_t node_info_size_must_be = dap_chain_node_info_get_size(node_info);
     if(node_info_size_must_be != node_info_size) {
-        dap_chain_node_cli_set_reply_text(str_reply, "node has bad size in base=%u (must be %u)", node_info_size,
+        dap_chain_node_cli_set_reply_text(a_str_reply, "node has bad size in base=%u (must be %u)", node_info_size,
                 node_info_size_must_be);
         DAP_DELETE(node_info);
         DAP_DELETE(l_key);
@@ -188,13 +190,13 @@ static dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_node_addr_t *ad
 /**
  * Save node to base
  */
-static bool dap_chain_node_info_save(dap_chain_node_info_t *node_info, char **str_reply)
+static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *node_info, char **str_reply)
 {
     if(!node_info || !node_info->hdr.address.uint64) {
         dap_chain_node_cli_set_reply_text(str_reply, "node addr not found");
         return false;
     }
-    char *a_key = com_global_db_get_key_for_addr(&node_info->hdr.address);
+    char *a_key = dap_chain_node_addr_to_hash_str(&node_info->hdr.address);
     if(!a_key)
     {
         dap_chain_node_cli_set_reply_text(str_reply, "can't calculate hash for addr");
@@ -202,59 +204,55 @@ static bool dap_chain_node_info_save(dap_chain_node_info_t *node_info, char **st
     }
     //char *a_value = dap_chain_node_info_serialize(node_info, NULL);
     size_t node_info_size = dap_chain_node_info_get_size(node_info);
-    bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t *) node_info, node_info_size, GROUP_NODE);
+    bool res = dap_chain_global_db_gr_set(a_key, (const uint8_t *) node_info, node_info_size,a_net->pub.gdb_nodes);
     DAP_DELETE(a_key);
     //DAP_DELETE(a_value);
     return res;
 }
+
 /**
  * Handler of command 'global_db node add'
  *
  * str_reply[out] for reply
  * return 0 Ok, -1 error
  */
-static int com_global_db_add(dap_chain_node_info_t *node_info, const char *alias_str,
-        const char *cell_str, const char *ipv4_str, const char *ipv6_str, char **str_reply)
+static int node_info_add_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *a_alias_str,
+        const char *a_cell_str, const char *a_ipv4_str, const char *a_ipv6_str, char **a_str_reply)
 {
 
-    if(!node_info->hdr.address.uint64) {
-        dap_chain_node_cli_set_reply_text(str_reply, "not found -addr parameter");
+    if(!a_node_info->hdr.address.uint64) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "not found -addr parameter");
         return -1;
     }
-    if(!cell_str) {
-        dap_chain_node_cli_set_reply_text(str_reply, "not found -cell parameter");
+    if(!a_cell_str) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "not found -cell parameter");
         return -1;
     }
-    if(!ipv4_str && !ipv6_str) {
-        dap_chain_node_cli_set_reply_text(str_reply, "not found -ipv4 or -ipv6 parameter");
-        return -1;
-    }
-    else {
-        if(ipv4_str)
-            inet_pton(AF_INET, ipv4_str, &(node_info->hdr.ext_addr_v4));
-        if(ipv6_str)
-            inet_pton(AF_INET6, ipv6_str, &(node_info->hdr.ext_addr_v6));
-    }
+    if(a_ipv4_str)
+        inet_pton(AF_INET, a_ipv4_str, &(a_node_info->hdr.ext_addr_v4));
+    if(a_ipv6_str)
+        inet_pton(AF_INET6, a_ipv6_str, &(a_node_info->hdr.ext_addr_v6));
+
     // check match addr to cell or no
     /*dap_chain_node_addr_t *addr = dap_chain_node_gen_addr(&node_info->hdr.cell_id);
      if(!dap_chain_node_check_addr(&node_info->hdr.address, &node_info->hdr.cell_id)) {
      set_reply_text(str_reply, "cell does not match addr");
      return -1;
      }*/
-    if(alias_str) {
+    if(a_alias_str) {
         // add alias
-        if(!dap_chain_node_alias_register(alias_str, &node_info->hdr.address)) {
-            log_it(L_WARNING, "can't save alias %s", alias_str);
-            dap_chain_node_cli_set_reply_text(str_reply, "alias '%s' can't be mapped to addr=0x%lld",
-                    alias_str, node_info->hdr.address.uint64);
+        if(!dap_chain_node_alias_register( a_net, a_alias_str, &a_node_info->hdr.address)) {
+            log_it(L_WARNING, "can't save alias %s", a_alias_str);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "alias '%s' can't be mapped to addr=0x%lld",
+                    a_alias_str, a_node_info->hdr.address.uint64);
             return -1;
         }
     }
 
     // write to base
-    bool res = dap_chain_node_info_save(node_info, str_reply);
+    bool res = node_info_save_and_reply(a_net,a_node_info, a_str_reply);
     if(res)
-        dap_chain_node_cli_set_reply_text(str_reply, "node added");
+        dap_chain_node_cli_set_reply_text(a_str_reply, "node added");
     else
         return -1;
     if(res)
@@ -268,39 +266,39 @@ static int com_global_db_add(dap_chain_node_info_t *node_info, const char *alias
  * str_reply[out] for reply
  * return 0 Ok, -1 error
  */
-static int com_global_db_del(dap_chain_node_info_t *node_info, const char *alias_str, char **str_reply)
+static int node_info_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *alias_str, char **str_reply)
 {
-    if(!node_info->hdr.address.uint64 && !alias_str) {
+    if(!a_node_info->hdr.address.uint64 && !alias_str) {
         dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
         return -1;
     }
     // check, current node have this addr or no
     uint64_t l_cur_addr = dap_db_get_cur_node_addr();
-    if(l_cur_addr && l_cur_addr == node_info->hdr.address.uint64) {
+    if(l_cur_addr && l_cur_addr == a_node_info->hdr.address.uint64) {
         dap_chain_node_cli_set_reply_text(str_reply, "current node cannot be deleted");
         return -1;
     }
 
     // find addr by alias or addr_str
-    dap_chain_node_addr_t *address = com_global_db_get_addr(node_info, &node_info->hdr.address, alias_str);
+    dap_chain_node_addr_t *address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, alias_str);
     if(!address) {
         dap_chain_node_cli_set_reply_text(str_reply, "alias not found");
         return -1;
     }
-    char *a_key = com_global_db_get_key_for_addr(address);
+    char *a_key = dap_chain_node_addr_to_hash_str(address);
     if(a_key)
     {
         // delete node
-        bool res = dap_chain_global_db_gr_del(a_key, GROUP_NODE);
+        bool res = dap_chain_global_db_gr_del(a_key, a_net->pub.gdb_nodes);
         if(res) {
             // delete all aliases for node address
             {
-                dap_list_t *list_aliases = get_aliases_by_name(address);
+                dap_list_t *list_aliases = get_aliases_by_name(a_net, address);
                 dap_list_t *list = list_aliases;
                 while(list)
                 {
                     const char *alias = (const char *) list->data;
-                    dap_chain_node_alias_delete(alias);
+                    dap_chain_node_alias_delete(a_net, alias);
                     list = dap_list_next(list);
                 }
                 dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
@@ -328,31 +326,33 @@ static int com_global_db_del(dap_chain_node_info_t *node_info, const char *alias
  * str_reply[out] for reply
  * return 0 Ok, -1 error
  */
-static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd, const char *alias_str,
-        dap_chain_node_addr_t *link, char **str_reply)
+static int link_add_or_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *cmd, const char *a_alias_str,
+        dap_chain_node_addr_t *link, char **a_str_reply)
 {
-    if(!node_info->hdr.address.uint64 && !alias_str) {
-        dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
+    if(!a_node_info->hdr.address.uint64 && !a_alias_str) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
         return -1;
     }
     if(!link->uint64) {
-        dap_chain_node_cli_set_reply_text(str_reply, "link not found");
+        dap_chain_node_cli_set_reply_text(a_str_reply, "link not found");
         return -1;
     }
     // TODO check the presence of link in the node base
     if(0) {
-        dap_chain_node_cli_set_reply_text(str_reply, "node 0x%llx not found in base", link->uint64);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "node 0x%016llx not found in base", link->uint64);
         return -1;
     }
 
     // find addr by alias or addr_str
-    dap_chain_node_addr_t *address = com_global_db_get_addr(node_info, &node_info->hdr.address, alias_str);
-    if(!address) {
-        dap_chain_node_cli_set_reply_text(str_reply, "alias not found");
+    dap_chain_node_addr_t *l_address = node_info_get_addr(a_net, a_node_info, &a_node_info->hdr.address, a_alias_str);
+    if(!l_address) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
         return -1;
     }
-    dap_chain_node_info_t *node_info_read = dap_chain_node_info_read(address, str_reply);
-    if(!node_info_read)
+
+    dap_chain_node_info_t * l_node_info_read = node_info_read_and_reply(a_net, l_address, a_str_reply);
+    size_t l_node_info_read_size = dap_chain_node_info_get_size(l_node_info_read);
+    if(!l_node_info_read)
         return -1;
 
     int cmd_int = 0;
@@ -363,10 +363,10 @@ static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd,
 
     // find link in node_info_read
     int index_link = -1;
-    for(size_t i = 0; i < node_info_read->hdr.links_number; i++) {
-        if(node_info_read->links[i].uint64 == link->uint64) {
+    for(size_t i = 0; i < l_node_info_read->hdr.links_number; i++) {
+        if(l_node_info_read->links[i].uint64 == link->uint64) {
             // link already present
-            index_link = i;
+            index_link = (int) i;
             break;
         }
     }
@@ -374,8 +374,9 @@ static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd,
     // add link
     if(cmd_int == 1) {
         if(index_link == -1) {
-            memcpy(&(node_info_read->links[node_info_read->hdr.links_number]), link, sizeof(dap_chain_node_addr_t));
-            node_info_read->hdr.links_number++;
+            l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size += sizeof(*link));
+            memcpy(&(l_node_info_read->links[l_node_info_read->hdr.links_number]), link, sizeof(dap_chain_node_addr_t));
+            l_node_info_read->hdr.links_number++;
             res_successful = true;
         }
     }
@@ -383,22 +384,23 @@ static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd,
     else if(cmd_int == 2) {
         // move link list to one item prev
         if(index_link >= 0) {
-            for(unsigned int j = (unsigned int) index_link; j < (node_info_read->hdr.links_number - 1); j++) {
-                memcpy(&(node_info_read->links[j]), &(node_info_read->links[j + 1]), sizeof(dap_chain_node_addr_t));
+            for(unsigned int j = (unsigned int) index_link; j < (l_node_info_read->hdr.links_number - 1); j++) {
+                memcpy(&(l_node_info_read->links[j]), &(l_node_info_read->links[j + 1]), sizeof(dap_chain_node_addr_t));
             }
-            node_info_read->hdr.links_number--;
+            l_node_info_read->hdr.links_number--;
             res_successful = true;
+            l_node_info_read = DAP_REALLOC(l_node_info_read, l_node_info_read_size -= sizeof(*link));
         }
     }
     // save edited node_info
     if(res_successful) {
-        bool res = dap_chain_node_info_save(node_info_read, str_reply);
+        bool res = node_info_save_and_reply(a_net, l_node_info_read, a_str_reply);
         if(res) {
             res_successful = true;
             if(cmd_int == 1)
-                dap_chain_node_cli_set_reply_text(str_reply, "link added");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link added");
             if(cmd_int == 2)
-                dap_chain_node_cli_set_reply_text(str_reply, "link deleted");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link deleted");
         }
         else {
             res_successful = false;
@@ -407,20 +409,20 @@ static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd,
     else {
         if(cmd_int == 1) {
             if(index_link >= 0)
-                dap_chain_node_cli_set_reply_text(str_reply, "link not added because it is already present");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link not added because it is already present");
             else
-                dap_chain_node_cli_set_reply_text(str_reply, "link not added");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link not added");
         }
         if(cmd_int == 2) {
             if(index_link == -1)
-                dap_chain_node_cli_set_reply_text(str_reply, "link not deleted because not found");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted because not found");
             else
-                dap_chain_node_cli_set_reply_text(str_reply, "link not deleted");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "link not deleted");
         }
     }
 
-    DAP_DELETE(address);
-    DAP_DELETE(node_info_read);
+    DAP_DELETE(l_address);
+    DAP_DELETE(l_node_info_read);
     if(res_successful)
         return 0;
     return -1;
@@ -432,608 +434,470 @@ static int com_global_db_link(dap_chain_node_info_t *node_info, const char *cmd,
  * str_reply[out] for reply
  * return 0 Ok, -1 error
  */
-static int com_global_db_dump(dap_chain_node_info_t *a_node_info, const char *alias_str, char **str_reply)
+static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t * a_addr, const char *a_alias, char **a_str_reply)
 {
-    size_t l_nodes_count = 1;
-    //bool show_all_addr = false;
-    dap_global_db_obj_t **l_objs = NULL;
-    if(!a_node_info->hdr.address.uint64 && !alias_str) {
-        //set_reply_text(str_reply, "addr not found");
-        //return -1;
-        //show_all_addr = true;
-        // read all nodes
-        dap_chain_node_info_t *node_info;
+    int l_ret = 0;
+    dap_string_t *l_string_reply = dap_string_new("Node dump:\n");
+
+    if( (a_addr && a_addr->uint64 ) || a_alias) {
+        dap_chain_node_addr_t *l_addr;
+        if (a_addr && a_addr->uint64){
+            l_addr = DAP_NEW(dap_chain_node_addr_t);
+            l_addr->uint64 = a_addr->uint64;
+        } else if (a_alias) {
+            l_addr = dap_chain_node_alias_find(a_net,a_alias);
+        }
+        if ( l_addr ) {
+        }
+    }else { // Dump list
+        dap_global_db_obj_t **l_objs = NULL;
+        size_t l_nodes_count = 0;
+        dap_chain_node_info_t *l_node_info;
         // read all node
-        l_objs = dap_chain_global_db_gr_load(GROUP_NODE, &l_nodes_count);
-        /*for(size_t i = 0; i < l_nodes_count; i++) {
-         dap_global_db_obj_t *l_obj = l_objs[i];
-         dap_chain_node_info_t *node_info = (dap_chain_node_info_t *) l_obj->value;
-         node_info->
+        l_objs = dap_chain_global_db_gr_load( a_net->pub.gdb_nodes, &l_nodes_count);
 
-         }*/
         if(!l_nodes_count || !l_objs) {
-            dap_chain_node_cli_set_reply_text(str_reply, "nodes not found");
-            return -1;
-        }
-    }
-    size_t i;
-    dap_string_t *l_string_reply = dap_string_new(NULL);
-    for(i = 0; i < l_nodes_count; i++) {
-        dap_chain_node_info_t *node_info = (!l_objs) ? a_node_info : (dap_chain_node_info_t *) l_objs[i]->value;
-        // find addr by alias or addr_str
-        dap_chain_node_addr_t *address = com_global_db_get_addr(node_info, &node_info->hdr.address, alias_str);
-        if(!address) {
-            dap_chain_node_cli_set_reply_text(str_reply, "alias not found");
-            break;
-        }
-        // read node
-        dap_chain_node_info_t *node_info_read = dap_chain_node_info_read(address, str_reply);
-        if(!node_info_read) {
-            DAP_DELETE(address);
-            break;
-        }
+            dap_string_append_printf(l_string_reply, "No records\n");
+            l_ret = -1;
+        }else {
+            dap_string_append_printf(l_string_reply,"Got %u records:\n",l_nodes_count);
+            for(size_t i = 0; i < l_nodes_count; i++) {
+                dap_chain_node_info_t *node_info =  (dap_chain_node_info_t *) l_objs[i]->value;
+                // find addr by alias or addr_str
+                dap_chain_node_addr_t *address = node_info_get_addr(a_net, node_info, &node_info->hdr.address, a_alias);
+                if(!address) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
+                    break;
+                }
+                // read node
+                dap_chain_node_info_t *node_info_read = node_info_read_and_reply( a_net, address, a_str_reply);
+                if(!node_info_read) {
+                    DAP_DELETE(address);
+                    break;
+                }
 
-        int hostlen = 128;
-        char host4[hostlen];
-        char host6[hostlen];
-        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info_read->hdr.ext_addr_v4 };
-        const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, hostlen);
+                const int hostlen = 128;
+                char *host4 = (char*) alloca(hostlen);
+                char *host6 = (char*) alloca(hostlen);
+                struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info_read->hdr.ext_addr_v4 };
+                const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, hostlen);
 
-        struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info_read->hdr.ext_addr_v6 };
-        const char* str_ip6 = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host6, hostlen);
+                struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info_read->hdr.ext_addr_v6 };
+                const char* str_ip6 = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host6, hostlen);
 
-        // get aliases in form of string
-        dap_string_t *aliases_string = dap_string_new(NULL);
-        dap_list_t *list_aliases = get_aliases_by_name(address);
-        if(list_aliases)
-        {
-            dap_list_t *list = list_aliases;
-            while(list)
-            {
-                const char *alias = (const char *) list->data;
-                dap_string_append_printf(aliases_string, "\nalias %s", alias);
-                list = dap_list_next(list);
-            }
-            dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
-        }
-        else
-            dap_string_append(aliases_string, "\nno aliases");
+                // get aliases in form of string
+                dap_string_t *aliases_string = dap_string_new(NULL);
+                dap_list_t *list_aliases = get_aliases_by_name(a_net,address);
+                if(list_aliases)
+                {
+                    dap_list_t *list = list_aliases;
+                    while(list)
+                    {
+                        const char *alias = (const char *) list->data;
+                        dap_string_append_printf(aliases_string, "\nalias %s", alias);
+                        list = dap_list_next(list);
+                    }
+                    dap_list_free_full(list_aliases, (dap_callback_destroyed_t) free);
+                }
+                else
+                    dap_string_append(aliases_string, "\nno aliases");
+
+                // get links in form of string
+                dap_string_t *links_string = dap_string_new(NULL);
+                for(unsigned int i = 0; i < node_info_read->hdr.links_number; i++) {
+                    dap_chain_node_addr_t link_addr = node_info_read->links[i];
+                    dap_string_append_printf(links_string, "\nlink%02d address : " NODE_ADDR_FP_STR, i,
+                                             NODE_ADDR_FP_ARGS_S(link_addr) );
+                }
 
-        // get links in form of string
-        dap_string_t *links_string = dap_string_new(NULL);
-        for(int i = 0; i < node_info_read->hdr.links_number; i++) {
-            dap_chain_node_addr_t link_addr = node_info_read->links[i];
-            dap_string_append_printf(links_string, "\nlink%02d address : 0x%llx", i, link_addr.uint64);
+                if(i)
+                    dap_string_append_printf(l_string_reply, "\n");
+                // set short reply with node param
+                if(l_objs)
+                    dap_string_append_printf(l_string_reply,
+                            "node address "NODE_ADDR_FP_STR"\tcell 0x%016llx\tipv4 %s\tnumber of links %u",
+                            node_info_read->hdr.address.uint64,str_ip4, node_info_read->hdr.cell_id.uint64,
+                             node_info_read->hdr.links_number);
+                else
+                    // set full reply with node param
+                    dap_string_append_printf(l_string_reply,
+                            "node address " NODE_ADDR_FP_STR "\ncell 0x%016llx%s\nipv4 %s\nipv6 %s\nlinks %u%s",
+                            NODE_ADDR_FP_ARGS_S(node_info_read->hdr.address) , str_ip4, str_ip6,
+                     node_info_read->hdr.cell_id.uint64, aliases_string->str,
+                            node_info_read->hdr.links_number, links_string->str);
+                dap_string_free(aliases_string, true);
+                dap_string_free(links_string, true);
+
+                DAP_DELETE(address);
+                DAP_DELETE(node_info_read);
+            }
         }
-
-        if(i)
-            dap_string_append_printf(l_string_reply, "\n");
-        // set short reply with node param
-        if(l_objs)
-            dap_string_append_printf(l_string_reply,
-                    "node address 0x%llx\tcell 0x%llx\tipv4 %s\tnumber of links %d",
-                    node_info_read->hdr.address, node_info_read->hdr.cell_id,
-                    str_ip4, node_info_read->hdr.links_number);
-        else
-            // set full reply with node param
-            dap_string_append_printf(l_string_reply,
-                    "node address 0x%llx\ncell 0x%llx%s\nipv4 %s\nipv6 %s\nlinks %d%s",
-                    node_info_read->hdr.address, node_info_read->hdr.cell_id, aliases_string->str,
-                    str_ip4, str_ip6,
-                    node_info_read->hdr.links_number, links_string->str);
-        dap_string_free(aliases_string, true);
-        dap_string_free(links_string, true);
-
-        DAP_DELETE(address);
-        DAP_DELETE(node_info_read);
-    }
-    if(i == l_nodes_count) {
-        // set full reply with node param
-        dap_chain_node_cli_set_reply_text(str_reply, l_string_reply->str);
     }
+    dap_chain_node_cli_set_reply_text(a_str_reply, l_string_reply->str);
     dap_string_free(l_string_reply, true);
-    if(i < l_nodes_count)
-        return -1;
-    else
-        return 0;
-}
-
-/**
- * Handler of command 'global_db node get'
- *
- * str_reply[out] for reply
- * return 0 Ok, -1 error
- */
-static int com_global_db_get(char **a_str_reply)
-{
-    // get cur node addr
-    uint64_t l_addr = dap_db_get_cur_node_addr();
-    if(l_addr) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "address for current node is 0x%llu", l_addr);
-        return 0;
-    }
-    dap_chain_node_cli_set_reply_text(a_str_reply, "address for node has not been set.");
-    return -1;
-}
-
-/**
- * Handler of command 'global_db node set'
- *
- * str_reply[out] for reply
- * return 0 Ok, -1 error
- */
-static int com_global_db_set(dap_chain_node_info_t *a_node_info, const char *a_alias_str, char **a_str_reply)
-{
-    if(!a_node_info->hdr.address.uint64 && !a_alias_str) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
-        return -1;
-    }
-    // find addr by alias or addr_str
-    dap_chain_node_addr_t *l_address = com_global_db_get_addr(a_node_info, &a_node_info->hdr.address, a_alias_str);
-    if(!l_address) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
-        return -1;
-    }
-    // read node
-    dap_chain_node_info_t *l_node_info_read = dap_chain_node_info_read(l_address, a_str_reply);
-    if(!l_node_info_read) {
-        DAP_DELETE(l_address);
-        return -1;
-    }
-    // set cur node addr
-    if(dap_db_set_cur_node_addr(l_node_info_read->hdr.address.uint64)) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "new address for node has been set");
-        return 0;
-    }
-    dap_chain_node_cli_set_reply_text(a_str_reply, "new address for node has not been set");
-    return -1;
+    return l_ret;
 }
 
-/**
- * Handler of command 'global_db node remote_set'
- *
- * str_reply[out] for reply
- * return 0 Ok, -1 error
- */
-static int com_global_db_set_remote(dap_chain_node_info_t *a_node_info, const char *a_alias_str, char **a_str_reply)
-{
-    if(!a_node_info->hdr.address.uint64 && !a_alias_str) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
-        return -1;
-    }
-    // find addr by alias or addr_str
-    dap_chain_node_addr_t *l_address = com_global_db_get_addr(a_node_info, &a_node_info->hdr.address, a_alias_str);
-    if(!l_address) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "alias not found");
-        return -1;
-    }
-    // read node
-    dap_chain_node_info_t *l_node_info_read = dap_chain_node_info_read(l_address, a_str_reply);
-    if(!l_node_info_read) {
-        DAP_DELETE(l_address);
-        return -1;
-    }
-
-    // get cur node addr
-    uint64_t l_cur_node_addr = dap_db_get_cur_node_addr(); //0x12345
-    if(!l_cur_node_addr) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "current node has no address");
-        return -1;
-    }
-    dap_chain_node_info_t *l_node_info = dap_chain_node_info_read(l_address, a_str_reply);
-    if(!l_node_info) {
-        return -1;
-    }
-    // start connect
-    dap_chain_node_client_t *client = dap_chain_node_client_connect(l_node_info);
-    if(!client) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
-        DAP_DELETE(l_node_info);
-        return -1;
-    }
-    // wait connected
-    int timeout_ms = 15000; //15 sec = 15000 ms
-    int res = chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
-    if(res != 1) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node");
-        // clean client struct
-        dap_chain_node_client_close(client);
-        DAP_DELETE(l_node_info);
-        return -1;
-    }
-
-    // send request
-    res = dap_chain_node_client_send_chain_net_request(client, dap_stream_ch_chain_net_get_id(),
-    STREAM_CH_CHAIN_NET_PKT_TYPE_SET_NODE_ADDR, (char*) &l_node_info->hdr.address.uint64, sizeof(uint64_t)); //, NULL);
-    if(res != 1) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "no request sent");
-        // clean client struct
-        dap_chain_node_client_close(client);
-        DAP_DELETE(l_node_info);
-        return -1;
-    }
-
-    // wait for finishing of request
-    timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
-    res = chain_node_client_wait(client, NODE_CLIENT_STATE_GET_NODE_ADDR, timeout_ms);
-    DAP_DELETE(l_node_info);
-    dap_client_disconnect(client->client);
-    dap_chain_node_client_close(client);
-    switch (res) {
-    case 0:
-        dap_chain_node_cli_set_reply_text(a_str_reply, "timeout");
-        return -1;
-    case 1: {
-        uint64_t addr = 0;
-        if(client->recv_data_len == sizeof(uint64_t))
-            memcpy(&addr, client->recv_data, sizeof(uint64_t));
-        if(client->recv_data_len > 0)
-            DAP_DELETE(client->recv_data);
-        client->recv_data = NULL;
-        dap_chain_node_cli_set_reply_text(a_str_reply, "new address for remote node has been set 0x%x", addr);
-    }
-        return 0;
-    default:
-        dap_chain_node_cli_set_reply_text(a_str_reply, "error");
-        return -1;
-    }
-
-    dap_chain_node_cli_set_reply_text(a_str_reply, "not implement");
-    return -1;
-}
 
 /**
  * global_db command
  *
  * return 0 OK, -1 Err
  */
-int com_global_db(int argc, const char ** argv, char **str_reply)
+int com_global_db(int a_argc, const char ** a_argv, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_ADD, CMD_DEL, CMD_LINK, CMD_DUMP, CMD_GET, CMD_SET, CMD_REMOTE_SET
-    };
+        CMD_NONE, CMD_ADD, CMD_DEL, CMD_LINK    };
     //printf("com_global_db\n");
     int arg_index = 1;
     // find 'node' as first parameter only
-    arg_index = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "node", NULL);
-    if(!arg_index || argc < 3) {
-        dap_chain_node_cli_set_reply_text(str_reply, "parameters are not valid");
+    arg_index = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "node", NULL);
+    if(!arg_index || a_argc < 3) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "parameters are not valid");
         return -1;
     }
+    dap_chain_net_t * l_net = NULL;
+
+    if(dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, a_argc, a_argv, a_str_reply, NULL, &l_net) < 0)
+        return -11;
+
     int arg_index_n = ++arg_index;
     // find command (add, delete, etc) as second parameter only
     int cmd_num = CMD_NONE;
-    if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "add", NULL))
+    if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
             != 0) {
         cmd_num = CMD_ADD;
     }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "del", NULL))
+    else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del",
+    NULL))
             != 0) {
         cmd_num = CMD_DEL;
     }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "link", NULL))
+    else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "link",
+    NULL))
             != 0) {
         cmd_num = CMD_LINK;
     }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "dump", NULL))
-            != 0) {
-        cmd_num = CMD_DUMP;
-    }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "get", NULL))
-            != 0) {
-        cmd_num = CMD_GET;
-    }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "set", NULL))
-            != 0) {
-        cmd_num = CMD_SET;
-    }
-    else if((arg_index_n = dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "remote_set",
-    NULL)) != 0) {
-        cmd_num = CMD_REMOTE_SET;
-    }
+
     if(cmd_num == CMD_NONE) {
-        dap_chain_node_cli_set_reply_text(str_reply, "command %s not recognized", argv[1]);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
         return -1;
     }
     //arg_index = arg_index_n; // no need, they are already equal must be
     assert(arg_index == arg_index_n);
     arg_index++;
-    const char *addr_str = NULL, *alias_str = NULL, *cell_str = NULL, *link_str = NULL;
-    const char *ipv4_str = NULL, *ipv6_str = NULL;
+    const char *l_addr_str = NULL, *alias_str = NULL, *l_cell_str = NULL, *l_link_str = NULL;
+    const char *a_ipv4_str = NULL, *a_ipv6_str = NULL;
     // find addr, alias
-    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, "-alias", &alias_str);
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-cell", &cell_str);
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-ipv4", &ipv4_str);
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-ipv6", &ipv6_str);
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-link", &link_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-cell", &l_cell_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv4", &a_ipv4_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ipv6", &a_ipv6_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-link", &l_link_str);
 
     // struct to write to the global db
-    dap_chain_node_info_t node_info;
-    dap_chain_node_addr_t link;
-    memset(&node_info, 0, sizeof(dap_chain_node_info_t));
-    memset(&link, 0, sizeof(dap_chain_node_addr_t));
-    if(addr_str) {
-        dap_digit_from_string(addr_str, node_info.hdr.address.raw, sizeof(node_info.hdr.address.raw));
+    dap_chain_node_addr_t l_link = { 0 };
+    dap_chain_node_info_t *l_node_info;
+    size_t l_node_info_size = sizeof(l_node_info->hdr) + sizeof(l_link);
+    l_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, l_node_info_size);
+
+    if(l_addr_str) {
+        dap_digit_from_string(l_addr_str, l_node_info->hdr.address.raw, sizeof(l_node_info->hdr.address.raw));
     }
-    if(cell_str) {
-        dap_digit_from_string(cell_str, node_info.hdr.cell_id.raw, sizeof(node_info.hdr.cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
+    if(l_cell_str) {
+        dap_digit_from_string(l_cell_str, l_node_info->hdr.cell_id.raw, sizeof(l_node_info->hdr.cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
     }
-    if(link_str) {
-        dap_digit_from_string(link_str, link.raw, sizeof(link.raw));
+    if(l_link_str) {
+        dap_digit_from_string(l_link_str, l_link.raw, sizeof(l_link.raw));
     }
 
     switch (cmd_num)
     {
     // add new node to global_db
     case CMD_ADD:
-        if(!arg_index || argc < 8) {
-            dap_chain_node_cli_set_reply_text(str_reply, "invalid parameters");
+        if(!arg_index || a_argc < 8) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameters");
             return -1;
         }
         // handler of command 'global_db node add'
-        return com_global_db_add(&node_info, alias_str, cell_str, ipv4_str, ipv6_str, str_reply);
+        return node_info_add_with_reply(l_net,l_node_info, alias_str, l_cell_str, a_ipv4_str, a_ipv6_str, a_str_reply);
         //break;
 
     case CMD_DEL:
         // handler of command 'global_db node del'
-        return com_global_db_del(&node_info, alias_str, str_reply);
-        break;
+        return node_info_del_with_reply(l_net,l_node_info, alias_str, a_str_reply);
     case CMD_LINK:
-        if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "add", NULL))
+        if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "add", NULL))
             // handler of command 'global_db node link add -addr <node address> -link <node address>'
-            return com_global_db_link(&node_info, "add", alias_str, &link, str_reply);
-        else if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "del", NULL))
+            return link_add_or_del_with_reply(l_net, l_node_info, "add", alias_str, &l_link, a_str_reply);
+        else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "del", NULL))
             // handler of command 'global_db node link del -addr <node address> -link <node address>'
-            return com_global_db_link(&node_info, "del", alias_str, &link, str_reply);
+            return link_add_or_del_with_reply(l_net, l_node_info, "del", alias_str, &l_link, a_str_reply);
         else {
-            dap_chain_node_cli_set_reply_text(str_reply, "command not recognize, supported format:\n"
+            dap_chain_node_cli_set_reply_text(a_str_reply, "command not recognize, supported format:\n"
                     "global_db node link <add|del] [-addr <node address>  | -alias <node alias>] -link <node address>");
+            DAP_DELETE(l_node_info);
             return -1;
         }
-        break;
-    case CMD_DUMP:
-        // handler of command 'global_db node dump'
-        return com_global_db_dump(&node_info, alias_str, str_reply);
-        break;
-    case CMD_GET:
-        // handler of command 'global_db node get'
-        return com_global_db_get(str_reply);
-        break;
-    case CMD_SET:
-        // handler of command 'global_db node set'
-        return com_global_db_set(&node_info, alias_str, str_reply);
-        break;
-    case CMD_REMOTE_SET:
-        // handler of command 'global_db node remote_set'
-        return com_global_db_set_remote(&node_info, alias_str, str_reply);
-        break;
 
     default:
-        dap_chain_node_cli_set_reply_text(str_reply, "command %s not recognized", argv[1]);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
         return -1;
     }
-    return -1;
 }
 
 /**
  * Node command
  */
-int com_node(int argc, const char ** argv, char **str_reply)
+int com_node(int a_argc, const char ** a_argv, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT
+        CMD_NONE, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT , CMD_DUMP
     };
     int arg_index = 1;
     int cmd_num = CMD_NONE;
     const char *cmd_str = NULL;
 // find  add parameter ('alias' or 'handshake')
-    if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "handshake", NULL)) {
+    if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "handshake", NULL)) {
         cmd_num = CMD_HANDSHAKE;
     }
-    else if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "connect", NULL)) {
+    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "connect", NULL)) {
         cmd_num = CMD_CONNECT;
     }
-    else if(dap_chain_node_cli_find_option_val(argv, arg_index, min(argc, arg_index + 1), "alias", NULL)) {
+    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "alias", NULL)) {
         cmd_num = CMD_ALIAS;
     }
+    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "dump", NULL)) {
+        cmd_num = CMD_DUMP;
+    }
     arg_index++;
     if(cmd_num == CMD_NONE) {
-        dap_chain_node_cli_set_reply_text(str_reply, "command %s not recognized", argv[1]);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "command %s not recognized", a_argv[1]);
         return -1;
     }
-    dap_chain_node_addr_t address;
-    memset(&address, 0, sizeof(dap_chain_node_addr_t));
-    const char *addr_str = NULL, *alias_str = NULL;
+    dap_chain_node_addr_t l_node_addr={0};
+    const char *l_addr_str = NULL, *alias_str = NULL;
     const char * l_net_str = NULL;
 // find addr, alias
-    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, "-alias", &alias_str);
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-net", &l_net_str);
 
-    dap_digit_from_string(addr_str, address.raw, sizeof(address.raw));
+    if (l_addr_str)
+        if ( dap_chain_node_addr_from_str(&l_node_addr,l_addr_str) != 0 )
+            dap_digit_from_string(l_addr_str, l_node_addr.raw, sizeof(l_node_addr.raw));
 
-    if( l_net_str == NULL){
-        dap_chain_node_cli_set_reply_text(str_reply, "No -net <net name> option in command %s", argv[1]);
+    if(l_net_str == NULL) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "No -net <net name> option in command %s", a_argv[1]);
         return -11;
     }
 
     dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_str);
 
-    if( l_net == NULL){
-        dap_chain_node_cli_set_reply_text(str_reply, "%s: Can't find such network %s", argv[1], l_net_str);
+    if(l_net == NULL) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "%s: Can't find such network %s", a_argv[1], l_net_str);
         return -12;
     }
 
     switch (cmd_num)
-        {
-        // add alias
-        case CMD_ALIAS:
-            if(alias_str) {
-                if(addr_str) {
-                    // add alias
-                    if(!dap_chain_node_alias_register(alias_str, &address))
-                        log_it(L_WARNING, "can't save alias %s", alias_str);
-                    else {
-                        dap_chain_node_cli_set_reply_text(str_reply, "alias mapped successfully");
-                    }
-                }
+    {
+    case CMD_DUMP:{
+        // handler of command 'global_db node dump'
+
+        return node_info_dump_with_reply(l_net, &l_node_addr , alias_str, a_str_reply);
+    }
+    // add alias
+    case CMD_ALIAS:
+        if(alias_str) {
+            if(l_addr_str) {
+                // add alias
+                if(!dap_chain_node_alias_register(l_net, alias_str, &l_node_addr))
+                    log_it(L_WARNING, "can't save alias %s", alias_str);
                 else {
-                    dap_chain_node_cli_set_reply_text(str_reply, "alias can't be mapped because -addr is not found");
-                    return -1;
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "alias mapped successfully");
                 }
             }
             else {
-                dap_chain_node_cli_set_reply_text(str_reply, "alias can't be mapped because -alias is not found");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -addr is not found");
                 return -1;
             }
+        }
+        else {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "alias can't be mapped because -alias is not found");
+            return -1;
+        }
 
-            break;
-            // make connect
-        case CMD_CONNECT: {
-            // get address from alias if addr not defined
-            if(alias_str && !address.uint64) {
-                dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(alias_str);
-                if(address_tmp) {
-                    memcpy(&address, address_tmp, sizeof(address_tmp));
-                    DAP_DELETE(address_tmp);
-                }
-                else {
-                    dap_chain_node_cli_set_reply_text(str_reply, "no address found by alias");
-                    return -1;
-                }
+        break;
+        // make connect
+    case CMD_CONNECT: {
+        // get address from alias if addr not defined
+        if(alias_str && !l_node_addr.uint64) {
+            dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net, alias_str);
+            if(address_tmp) {
+                memcpy(&l_node_addr, address_tmp, sizeof(*address_tmp));
+                DAP_DELETE(address_tmp);
             }
-            if(!address.uint64) {
-                dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
+            else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
                 return -1;
             }
+        }
+        if(!l_node_addr.uint64) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
+            return -1;
+        }
 
-            // get cur node addr
-            uint64_t l_cur_node_addr = dap_db_get_cur_node_addr(); //0x12345
-            if(!l_cur_node_addr) {
-                dap_chain_node_cli_set_reply_text(str_reply, "node has no address");
-                return -1;
-            }
 
-            dap_chain_node_info_t *node_info = dap_chain_node_info_read(&address, str_reply);
-            if(!node_info) {
-                return -1;
-            }
-            // start connect
-            dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
-            if(!client) {
-                dap_chain_node_cli_set_reply_text(str_reply, "can't connect");
-                DAP_DELETE(node_info);
-                return -1;
-            }
-            // wait connected
-            int timeout_ms = 15000; //15 sec = 15000 ms
-            int res = chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
-            if(res != 1) {
-                dap_chain_node_cli_set_reply_text(str_reply, "no response from node");
-                // clean client struct
-                dap_chain_node_client_close(client);
-                DAP_DELETE(node_info);
-                return -1;
-            }
+        dap_chain_node_info_t *l_remote_node_info = node_info_read_and_reply(l_net, &l_node_addr, a_str_reply);
+        if(!l_remote_node_info) {
+            return -1;
+        }
+        // start connect
+        dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(l_remote_node_info);
+        if(!l_node_client) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
+            DAP_DELETE(l_remote_node_info);
+            return -1;
+        }
+        // wait connected
+        int timeout_ms = 15000; //15 sec = 15000 ms
+        int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
+        if(res ) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node: code %d",res);
+            // clean client struct
+            dap_chain_node_client_close(l_node_client);
+            DAP_DELETE(l_remote_node_info);
+            return -1;
+        }
+        log_it(L_NOTICE, "Stream connection established, now lets sync all");
+        dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
+        dap_stream_ch_t * l_ch_chain = dap_client_get_stream_ch(l_node_client->client, dap_stream_ch_chain_get_id());
+        // fill begin time
+        l_sync_request.ts_start = (uint64_t) dap_db_log_get_last_timestamp_remote(
+                l_remote_node_info->hdr.address.uint64);
+        // fill end time = 0 - no time limit
+        //l_sync_request.ts_end = (time_t) time(NULL);
+        // fill current node address
+        l_sync_request.node_addr.uint64 =
+                dap_chain_net_get_cur_addr(l_net) ? dap_chain_net_get_cur_addr(l_net)->uint64 :
+                                                    dap_db_get_cur_node_addr();
+        dap_chain_id_t l_chain_id_null = { { 0 } };
+        dap_chain_cell_id_t l_chain_cell_id_null = { { 0 } };
+        log_it(L_INFO, "Requested GLOBAL_DB syncronizatoin, %llu:%llu period", l_sync_request.ts_start,
+                l_sync_request.ts_end);
+        if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB,
+                l_net->pub.id, l_chain_id_null, l_chain_cell_id_null, &l_sync_request,
+                sizeof(l_sync_request))) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
+            // clean client struct
+            dap_chain_node_client_close(l_node_client);
+            DAP_DELETE(l_remote_node_info);
+            return -1;
+        }
+        dap_stream_ch_set_ready_to_write(l_ch_chain, true);
+        // wait for finishing of request
+        timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
+        // TODO add progress info to console
+        res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
+        if ( res <0 ){
+            dap_chain_node_client_close(l_node_client);
+            DAP_DELETE(l_remote_node_info);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Error: can't connect to node "NODE_ADDR_FP_STR,
+                                              NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
+
+            return -2;
 
+        }
+        // Requesting chains
+        dap_chain_t *l_chain = NULL;
+        DL_FOREACH(l_net->pub.chains, l_chain)
+        {
             // send request
-            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) {
-                dap_chain_node_cli_set_reply_text(str_reply, "no request sent");
+            dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
+            if(0 == dap_stream_ch_chain_pkt_write(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS,
+                    l_net->pub.id, l_chain->id, l_remote_node_info->hdr.cell_id, &l_sync_request,
+                    sizeof(l_sync_request))) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Error: Cant send sync chains request");
                 // clean client struct
-                dap_chain_node_client_close(client);
-                DAP_DELETE(node_info);
-                return -1;
+                dap_chain_node_client_close(l_node_client);
+                DAP_DELETE(l_remote_node_info);
+                return -3;
             }
+            log_it(L_NOTICE, "Requested syncronization for chain \"%s\"", l_chain->name);
+            dap_stream_ch_set_ready_to_write(l_ch_chain, true);
 
             // wait for finishing of request
             timeout_ms = 120000; // 2 min = 120 sec = 120 000 ms
             // TODO add progress info to console
-            res = 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:
-                dap_chain_node_cli_set_reply_text(str_reply, "timeout");
-                return -1;
-            case 1:
-                dap_chain_node_cli_set_reply_text(str_reply, "nodes sync completed");
-                return 0;
-            default:
-                dap_chain_node_cli_set_reply_text(str_reply, "error");
-                return -1;
-            }
-
+            res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
         }
-            break;
-            // 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 = dap_chain_node_addr_get_by_alias(alias_str);
-                if(address_tmp) {
-                    memcpy(&address, address_tmp, sizeof(address_tmp));
-                    DAP_DELETE(address_tmp);
-                }
-                else {
-                    dap_chain_node_cli_set_reply_text(str_reply, "no address found by alias");
-                    return -1;
-                }
-            }
-            if(!address.uint64) {
-                dap_chain_node_cli_set_reply_text(str_reply, "addr not found");
-                return -1;
-            }
+        log_it(L_INFO, "Chains and gdb are synced");
+        DAP_DELETE(l_remote_node_info);
+        dap_client_disconnect(l_node_client->client);
+        l_node_client->client = NULL;
+        dap_chain_node_client_close(l_node_client);
+        dap_chain_node_cli_set_reply_text(a_str_reply, "Node sync completed: Chains and gdb are synced");
+        return 0;
 
-            dap_chain_node_info_t *node_info = dap_chain_node_info_read(&address, str_reply);
-            if(!node_info)
-                return -1;
-            int timeout_ms = 10000; //10 sec = 10000 ms
-            // start handshake
-            dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
-            if(!client) {
-                dap_chain_node_cli_set_reply_text(str_reply, "can't connect");
-                DAP_DELETE(node_info);
-                return -1;
+    }
+        // make handshake
+    case CMD_HANDSHAKE: {
+        // get address from alias if addr not defined
+        if(alias_str && !l_node_addr.uint64) {
+            dap_chain_node_addr_t *address_tmp = dap_chain_node_addr_get_by_alias(l_net,alias_str);
+            if(address_tmp) {
+                memcpy(&l_node_addr, address_tmp, sizeof(address_tmp));
+                DAP_DELETE(address_tmp);
             }
-            // wait handshake
-            int res = chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
-            if(res != 1) {
-                dap_chain_node_cli_set_reply_text(str_reply, "no response from node");
-                // clean client struct
-                dap_chain_node_client_close(client);
-                DAP_DELETE(node_info);
-                return -1;
+            else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "no address found by alias");
+                return -4;
             }
+        }
+        if(!l_node_addr.uint64) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
+            return -5;
+        }
+
+        dap_chain_node_info_t *node_info = node_info_read_and_reply(l_net,&l_node_addr, a_str_reply);
+        if(!node_info)
+            return -6;
+        int timeout_ms = 10000; //10 sec = 10000 ms
+        // start handshake
+        dap_chain_node_client_t *client = dap_chain_node_client_connect(node_info);
+        if(!client) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
+            DAP_DELETE(node_info);
+            return -7;
+        }
+        // wait handshake
+        int res = dap_chain_node_client_wait(client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
+        if(res != 1) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node");
+            // clean client struct
+            dap_chain_node_client_close(client);
             DAP_DELETE(node_info);
+            return -8;
+        }
+        DAP_DELETE(node_info);
 
-            //Add new established connection in the list
-            int ret = dap_chain_node_client_list_add(&address, client);
-            switch (ret)
-            {
-            case -1:
-                dap_chain_node_client_close(client);
-                dap_chain_node_cli_set_reply_text(str_reply, "connection established, but not saved");
-                return -1;
-            case -2:
-                dap_chain_node_client_close(client);
-                dap_chain_node_cli_set_reply_text(str_reply, "connection already present");
-                return -1;
-            }
-            dap_chain_node_cli_set_reply_text(str_reply, "connection established");
-        } break;
+        //Add new established connection in the list
+        int ret = dap_chain_node_client_list_add(&l_node_addr, client);
+        switch (ret)
+        {
+        case -1:
+            dap_chain_node_client_close(client);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "connection established, but not saved");
+            return -9;
+        case -2:
+            dap_chain_node_client_close(client);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "connection already present");
+            return -10;
+        }
+        dap_chain_node_cli_set_reply_text(a_str_reply, "connection established");
+    }
+        break;
     }
     return 0;
 }
@@ -1305,16 +1169,17 @@ int com_tx_wallet(int argc, const char ** argv, char **str_reply)
     arg_index++;
     if(cmd_num == CMD_NONE) {
         dap_chain_node_cli_set_reply_text(str_reply,
-                "format of command: wallet [new -w <wallet_name> | list | info -addr <addr> -w <wallet_name>]");
+                "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;
+    const char *addr_str = NULL, *wallet_name = NULL, *l_net_name = NULL;
     // find wallet addr
     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) {
@@ -1344,12 +1209,12 @@ int com_tx_wallet(int argc, const char ** argv, char **str_reply)
         // wallet list
     case CMD_WALLET_LIST: {
         DIR * l_dir = opendir(c_wallets_path);
-        if( l_dir ) {
+        if(l_dir) {
             struct dirent * l_dir_entry;
-            while((l_dir_entry=readdir(l_dir))!=NULL){
+            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 ) ) {
+                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) {
@@ -1380,6 +1245,18 @@ int com_tx_wallet(int argc, const char ** argv, char **str_reply)
         if(!l_addr && addr_str)
             l_addr = dap_chain_str_to_addr(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)
@@ -1388,15 +1265,17 @@ int com_tx_wallet(int argc, const char ** argv, char **str_reply)
 
             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);
+            dap_chain_ledger_addr_get_token_ticker_all(l_ledger, 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]);
+                    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, "          %Lf %s\n", l_balance_coins, l_addr_tokens[i]);
+
                 }
                 DAP_DELETE(l_addr_tokens[i]);
             }
@@ -1432,43 +1311,44 @@ int com_tx_wallet(int argc, const char ** argv, char **str_reply)
  * @param l_net
  * @return
  */
-int dap_chain_node_cli_cmd_values_parse_net_chain(int *a_arg_index,int argc, const char ** argv, char ** a_str_reply,
-                             dap_chain_t ** a_chain, dap_chain_net_t ** a_net)
+int dap_chain_node_cli_cmd_values_parse_net_chain(int *a_arg_index, int argc, const char ** argv, char ** a_str_reply,
+        dap_chain_t ** a_chain, dap_chain_net_t ** a_net)
 {
     const char * l_chain_str = NULL;
     const char * l_net_str = NULL;
 
     // Net name
-    if ( a_net )
+    if(a_net)
         dap_chain_node_cli_find_option_val(argv, *a_arg_index, argc, "-net", &l_net_str);
     else
-       return -100;
+        return -100;
 
     // Select network
     if(!l_net_str) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "%s requires parameter 'net'",argv[0]);
+        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);
+    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 ){
+    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);
+            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 -103;
             }
         }
     }
-    return  0;
+    return 0;
 
 }
 
@@ -1487,7 +1367,7 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
     // Chain name
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "datum", &l_datum_hash_str);
 
-    if ( 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;
@@ -1495,11 +1375,11 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
 
         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 )
+        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);
+        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");
@@ -1509,16 +1389,16 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
 
         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);
+        log_it(L_DEBUG, "Requested to sign token declaration %s in gdb://%s with certs %s",
+                l_gdb_group_mempool, l_datum_hash_str, l_certs_str);
 
         dap_chain_datum_t * l_datum = NULL;
         size_t l_datum_size = 0;
-        if( (l_datum = (dap_chain_datum_t*) dap_chain_global_db_gr_get(
-                    l_datum_hash_str ,&l_datum_size,l_gdb_group_mempool )) != NULL ) {
+        if((l_datum = (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 ){
+            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);
@@ -1526,81 +1406,85 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
                 // 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++ ) {
+                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);
+                    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);
+                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");
+                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 );
+                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 );
+                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);
+                        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);
+                        DAP_DELETE(l_sign);
                         l_offset += l_sign_size;
-                        if (l_offset > l_signs_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);
+                    dap_hash_fast(l_datum, l_datum_size, &l_key_hash);
                     char * l_key_str = dap_chain_hash_fast_to_str_new(&l_key_hash);
 
                     // Add datum to mempool with datum_token hash as a key
-                    if(dap_chain_global_db_gr_set(l_key_str, (uint8_t *) l_datum, l_datum_size,l_gdb_group_mempool )) {
+                    if(dap_chain_global_db_gr_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);
+                        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;
+                            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_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);
@@ -1608,9 +1492,10 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
                         }
 
                     }
-                    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);
+                    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);
@@ -1618,25 +1503,28 @@ int com_token_decl_sign(int argc, const char ** argv, char ** a_str_reply)
                     }
 
                 } else {
-                    dap_chain_node_cli_set_reply_text(a_str_reply, "Error! Not enought place for new signature (%u is left when we need %u signatures)",
-                                                       l_datum_token->header.signs_total - l_signs_count, l_certs_count );
+                    dap_chain_node_cli_set_reply_text(a_str_reply,
+                            "Error! 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");
+                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);
+        } 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 {
+    } 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
@@ -1650,36 +1538,36 @@ int com_mempool_list(int argc, const char ** argv, char ** a_str_reply)
     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(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 ){
+    if(l_chain && l_net) {
         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;
+        dap_global_db_obj_t ** l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
+        dap_string_append_printf(l_str_tmp, "%s.%s: Found %u records :\n", l_net->pub.name, l_chain->name, l_objs_size);
+        for(size_t i = 0; i < l_objs_size; i++) {
+            dap_chain_datum_t * l_datum = (dap_chain_datum_t*) l_objs[i]->value;
             char buf[50];
             time_t l_ts_create = (time_t) l_datum->header.ts_create;
-            dap_string_append_printf(l_str_tmp,"%s: type_id=%s  data_size=%u ts_create=%s",
-                                     l_objs[i]->key, c_datum_type_str[l_datum->header.type_id],
-                                        l_datum->header.data_size,ctime_r( &l_ts_create,buf ) );
+            dap_string_append_printf(l_str_tmp, "%s: type_id=%s  data_size=%u ts_create=%s",
+                    l_objs[i]->key, c_datum_type_str[l_datum->header.type_id],
+                    l_datum->header.data_size, ctime_r(&l_ts_create, buf));
         }
 
         // Clean up
         dap_chain_node_cli_set_reply_text(a_str_reply, l_str_tmp->str);
         dap_chain_global_db_objs_delete(l_objs);
-        dap_string_free(l_str_tmp,false);
+        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");
+        return 0;
+    } else {
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Error! Need both -net <network name> and -chain <chain name> params\n");
         return -2;
     }
 }
@@ -1697,29 +1585,31 @@ int com_mempool_delete(int argc, const char ** argv, char ** a_str_reply)
     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(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");
         return -1;
     }
 
-    if ( l_chain && l_net ){
+    if(l_chain && l_net) {
         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 ){
+        if(l_datum_hash_str) {
             char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
-            if ( dap_chain_global_db_gr_del(l_datum_hash_str,l_gdb_group_mempool) ) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Datum %s deleted",l_datum_hash_str);
-                return  0;
-            }else {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Error! Can't find datum %s",l_datum_hash_str);
-                return  -4;
+            if(dap_chain_global_db_gr_del(l_datum_hash_str, l_gdb_group_mempool)) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Datum %s deleted", l_datum_hash_str);
+                return 0;
+            } else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
+                return -4;
             }
-        }else {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option",argv[0]);
+        } else {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", argv[0]);
             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");
+    } else {
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Error! Need both -net <network name> and -chain <chain name> params\n");
         return -2;
     }
 }
@@ -1737,46 +1627,44 @@ int com_mempool_proc(int argc, const char ** argv, char ** a_str_reply)
     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)
+    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_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);
-
+    if(l_objs_size) {
+        dap_string_append_printf(l_str_tmp, "%s.%s: Found %u records :\n", l_net->pub.name, l_chain->name);
 
         size_t l_datums_size = l_objs_size;
-        dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*,sizeof(dap_chain_datum_t*)*l_datums_size);
-        for ( size_t i = 0; i< l_objs_size; i++){
-            dap_chain_datum_t * l_datum = (dap_chain_datum_t* ) l_objs[i]->value;
+        dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*, sizeof(dap_chain_datum_t*) * l_datums_size);
+        for(size_t i = 0; i < l_objs_size; i++) {
+            dap_chain_datum_t * l_datum = (dap_chain_datum_t*) l_objs[i]->value;
             l_datums[i] = l_datum;
             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 );
+            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);
         }
-        size_t l_objs_processed = l_chain->callback_datums_pool_proc(l_chain,l_datums,l_datums_size);
+        size_t l_objs_processed = l_chain->callback_datums_pool_proc(l_chain, l_datums, l_datums_size);
         // Delete processed objects
-        for ( size_t i = 0; i< l_objs_processed; i++){
-            dap_chain_global_db_gr_del(l_objs[i]->key,l_gdb_group_mempool);
-            dap_string_append_printf(l_str_tmp,"New event created, removed datum 0x%s from mempool \n",l_objs[i]->key);
+        for(size_t i = 0; i < l_objs_processed; i++) {
+            dap_chain_global_db_gr_del(l_objs[i]->key, l_gdb_group_mempool);
+            dap_string_append_printf(l_str_tmp, "New event created, removed datum 0x%s from mempool \n",
+                    l_objs[i]->key);
         }
         dap_chain_global_db_objs_delete(l_objs);
 
         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);
+        dap_string_free(l_str_tmp, false);
+    } else {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "%s.^s: No records in mempool", l_net->pub.name, l_chain->name);
     }
     return 0;
 }
 
-
-
 /**
  * @brief com_token_decl
  * @param argc
@@ -1800,7 +1688,6 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     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;
@@ -1809,18 +1696,15 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     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)
+    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);
 
@@ -1833,10 +1717,11 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     if(!l_total_supply_str) {
         dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'total_supply'");
         return -11;
-    }else {
+    } 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");
+        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;
         }
     }
@@ -1845,10 +1730,11 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     if(!l_signs_emission_str) {
         dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'signs_emission'");
         return -3;
-    }else {
+    } 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");
+        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;
         }
     }
@@ -1857,22 +1743,21 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     if(!l_signs_total_str) {
         dap_chain_node_cli_set_reply_text(str_reply, "token_create requires parameter 'signs_total'");
         return -31;
-    }else {
+    } 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");
+        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'");
@@ -1880,7 +1765,7 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     }
 
     // Load certs lists
-    size_t l_signs_size = dap_chain_cert_parse_str_list(l_certs_str,&l_certs, &l_certs_size);
+    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");
@@ -1888,14 +1773,13 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     }
 
     // If we have more certs than we need signs - use only first part of the list
-    if (l_certs_size > l_signs_total )
+    if(l_certs_size > l_signs_total)
         l_certs_size = l_signs_total;
 
     // Create new datum token
-    dap_chain_datum_token_t * l_datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t,sizeof(l_datum_token->header) +
-                                                             l_signs_size);
+    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
-    snprintf(l_datum_token->header.ticker,sizeof(l_datum_token->header.ticker),"%s",l_ticker);
+    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;
@@ -1903,35 +1787,39 @@ int com_token_decl(int argc, const char ** argv, char ** str_reply)
     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);
+    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);
-        memcpy(l_datum_token->signs+l_signs_offset,l_sign,l_sign_size);
+        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);
+        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,
-                                                         sizeof (l_datum_token->header)+ l_signs_size);
+    dap_chain_datum_t * l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_DECL, l_datum_token,
+            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);
+    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);
+    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;
+        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);
+    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);
@@ -1972,43 +1860,42 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
     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);
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-certs", &l_certs_str);
 
     // Wallet address that recieves the emission
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "addr", &l_addr_str);
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-addr", &l_addr_str);
 
     // Token ticker
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "token", &l_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)) {
+    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'");
+        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'");
+        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-addr'");
         return -2;
     }
 
     if(!l_ticker) {
-        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter 'token'");
+        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-token'");
         return -3;
     }
 
     if(!l_certs_str) {
-        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter 'certs'");
+        dap_chain_node_cli_set_reply_text(str_reply, "token_emit requires parameter '-certs'");
         return -4;
     }
 
     // Load certs
-    dap_chain_cert_parse_str_list(l_certs_str,&l_certs,&l_certs_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(str_reply,
@@ -2016,7 +1903,6 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
         return -5;
     }
 
-
     dap_chain_addr_t * l_addr = dap_chain_str_to_addr(l_addr_str);
 
     if(!l_addr) {
@@ -2024,28 +1910,33 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
         return -4;
     }
 
+    // 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");
+    } 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");
             return -43;
         }
     }
 
-
-    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);
+    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'");
+        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);
+    } 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);
             return -45;
         }
     }
@@ -2054,9 +1945,11 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
     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);
+    } 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);
             return -47;
         }
     }
@@ -2065,24 +1958,41 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
     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;
-    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);
+    size_t l_token_emission_size = sizeof (l_token_emission->hdr) +
+            sizeof (l_token_emission->data.type_auth.signs_count);
+
+    l_token_emission = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, l_token_emission_size);
+    strncpy(l_token_emission->hdr.ticker, l_ticker, sizeof(l_token_emission->hdr.ticker));
+    l_token_emission->hdr.value = l_emission_value;
+
+    // Then add signs
+    size_t l_offset=0;
+    for (size_t i =0; i < l_certs_size; i++ ){
+        dap_chain_sign_t * l_sign = dap_chain_cert_sign(l_certs[i],&l_token_emission->hdr, sizeof(l_token_emission->hdr),0 );
+        size_t l_sign_size = dap_chain_sign_get_size(l_sign);
+        l_token_emission_size += l_sign_size;
+        l_token_emission= DAP_REALLOC(l_token_emission, l_token_emission_size);
+        memcpy(l_token_emission->data.type_auth.signs+l_offset,l_sign,l_sign_size);
+        l_offset+= l_sign_size;
+        DAP_DELETE(l_sign);
+    }
+
+    // Produce datum
     dap_chain_datum_t * l_datum_emission = dap_chain_datum_create(DAP_CHAIN_DATUM_TOKEN_EMISSION,
             l_token_emission,
-            sizeof(dap_chain_datum_token_emission_t));
+            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);
 
-    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);
+    // 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
@@ -2098,9 +2008,8 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
     // 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_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);
 
@@ -2132,16 +2041,16 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
     // 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_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_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);
-        dap_chain_utxo_tx_add((dap_chain_datum_tx_t*) l_datum_tx->data);
+        dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is placed in datum pool ", str_reply_tmp,
+                l_key_str);
     }
     else {
         dap_chain_node_cli_set_reply_text(str_reply, "%s\ndatum tx %s is not placed in datum pool ", str_reply_tmp,
@@ -2161,11 +2070,13 @@ int com_token_emit(int argc, const char ** argv, char ** str_reply)
  */
 int com_tx_cond_create(int argc, const char ** argv, char **str_reply)
 {
+    (void) argc;
     // 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";
     uint64_t l_value = 50;
     //debug
     {
@@ -2185,9 +2096,11 @@ int com_tx_cond_create(int argc, const char ** argv, char **str_reply)
     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");
-    int res = dap_chain_mempool_tx_create_cond(l_key, l_key_cond, addr_from,
+//    dap_chain_net_srv_abstract_set(&l_cond, SERV_CLASS_PERMANENT, SERV_ID_VPN, l_value, SERV_UNIT_MB,
+//            "test vpn service");
+    dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name((const char *) c_net_name);
+
+    int res = dap_chain_mempool_tx_create_cond(NULL, l_key, l_key_cond, addr_from,
             addr_cond,
             NULL, l_token_ticker, l_value, 0, (const void*) &l_cond, sizeof(dap_chain_net_srv_abstract_t));
 
@@ -2213,34 +2126,60 @@ int com_tx_create(int argc, const char ** argv, char **str_reply)
     const char *str_tmp = NULL;
     const char * l_from_wallet_name = NULL;
     const char * l_token_ticker = NULL;
+    const char * l_net_name = NULL;
+    const char * l_chain_name = NULL;
+
     uint64_t value = 0;
     uint64_t value_fee = 0;
-    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "from_wallet_name", &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);
-
-    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)) {
+    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);
+
+    if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-fee", &addr_base58_fee)) {
+        if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value_fee", &str_tmp)) {
             value_fee = strtoull(str_tmp, NULL, 10);
         }
     }
-    if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "value", &str_tmp)) {
+    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) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter 'from_wallet_name'");
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-from_wallet'");
         return -1;
     }
     if(!addr_base58_to) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter 'to_addr'");
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-to_addr'");
         return -1;
     }
     if(!value) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter 'value'");
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value'");
         return -1;
     }
     if(addr_base58_fee && !value_fee) {
-        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter 'value_fee' if 'fee' is specified");
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-value_fee' if '-fee' is specified");
+        return -1;
+    }
+
+    if(!l_net_name) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_create requires parameter '-net'");
+        return -1;
+    }
+    dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name);
+    dap_ledger_t *l_ledger = l_net->pub.ledger ;
+    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;
     }
 
@@ -2272,7 +2211,7 @@ int com_tx_create(int argc, const char ** argv, char **str_reply)
     //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,
+    int res = 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);
     dap_string_append_printf(string_ret, "transfer=%s\n",
             (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for transfer" : "False");
@@ -2316,7 +2255,7 @@ int com_print_log(int argc, const char ** argv, char **str_reply)
     const char * l_str_ts_after = NULL;
     const char * l_str_limit = NULL;
     int64_t l_ts_after = 0;
-    int32_t l_limit = 0;
+    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);
 
@@ -2333,7 +2272,7 @@ int com_print_log(int argc, const char ** argv, char **str_reply)
     }
 
     // get logs from list
-    char *l_str_ret = log_get_item(l_ts_after, l_limit);
+    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;
diff --git a/dap_chain_node_cli_cmd.h b/dap_chain_node_cli_cmd.h
index 9abb45703ead296d4864ecfd79cf3f55a61cc2e9..6066504b2027af2751fff27d585d92041d8e00e7 100644
--- a/dap_chain_node_cli_cmd.h
+++ b/dap_chain_node_cli_cmd.h
@@ -1,26 +1,27 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * Alexander Lysikov <alexander.lysikov@demlabs.net>
  * DeM Labs Inc.   https://demlabs.net
  * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * Copyright  (c) 2019
  * All rights reserved.
 
  This file is part of DAP (Deus Applications Prototypes) the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
+ DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
 
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
+ DAP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
 
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
+ You should have received a copy of the GNU General Public License
+ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
 #pragma once
 
@@ -34,7 +35,7 @@
  *
  * return addr, NULL if not found
  */
-dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias(const char *alias);
+dap_chain_node_addr_t* dap_chain_node_addr_get_by_alias(dap_chain_net_t * a_net, const char *alias);
 
 
 int dap_chain_node_cli_cmd_values_parse_net_chain(int *a_arg_index,int argc, const char ** argv, char ** a_str_reply,
@@ -121,3 +122,4 @@ int com_print_log(int argc, const char ** argv, char **str_reply);
 int com_mempool_delete(int argc, const char ** argv, char ** a_str_reply);
 int com_mempool_list(int argc, const char ** argv, char ** a_str_reply);
 int com_mempool_proc(int argc, const char ** argv, char ** a_str_reply);
+
diff --git a/dap_chain_node_client.c b/dap_chain_node_client.c
index b3171682fb21cafdb603178e6527326b58477914..b1ac1f26f86812444f2d7c9bb8fa928b11b3bc34 100644
--- a/dap_chain_node_client.c
+++ b/dap_chain_node_client.c
@@ -34,6 +34,8 @@
 #include "dap_http_client_simple.h"
 #include "dap_client_pvt.h"
 #include "dap_stream_ch_pkt.h"
+#include "dap_stream_ch_chain.h"
+#include "dap_stream_ch_chain_pkt.h"
 #include "dap_stream_ch_chain_net.h"
 #include "dap_stream_ch_chain_net_pkt.h"
 #include "dap_stream_pkt.h"
@@ -46,11 +48,20 @@
 #define SYSTEM_CONFIGS_DIR SYSTEM_PREFIX"/etc"
 
 static int listen_port_tcp = 8079;
+static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg);
+static void s_ch_chain_callback_notify_packet_out(dap_stream_ch_chain_t*, uint8_t a_pkt_type,
+                                                      dap_stream_ch_chain_pkt_t *a_pkt, size_t a_pkt_data_size,
+                                                      void * a_arg);
+static void s_ch_chain_callback_notify_packet_in(dap_stream_ch_chain_t* a_ch_chain, uint8_t a_pkt_type,
+                                                      dap_stream_ch_chain_pkt_t *a_pkt, size_t a_pkt_data_size,
+                                                      void * a_arg);
 
+/**
+ * @brief dap_chain_node_client_init
+ * @return
+ */
 int dap_chain_node_client_init(void)
 {
-    int res = dap_client_init();
-    res = dap_http_client_simple_init();
     dap_config_t *g_config;
     // read listen_port_tcp from settings
     dap_config_init(SYSTEM_CONFIGS_DIR);
@@ -63,36 +74,191 @@ int dap_chain_node_client_init(void)
     }
     if(g_config)
         dap_config_close(g_config);
-    return res;
+    return 0;
 }
 
+/**
+ * @brief dap_chain_node_client_deinit
+ */
 void dap_chain_node_client_deinit()
 {
     dap_http_client_simple_deinit();
     dap_client_deinit();
 }
 
-// callback for dap_client_new() in chain_node_client_connect()
+/**
+ * @brief stage_status_callback
+ * @param a_client
+ * @param a_arg
+ */
 static void stage_status_callback(dap_client_t *a_client, void *a_arg)
 {
+    (void) a_client;
+    (void) a_arg;
+
     //printf("* stage_status_callback client=%x data=%x\n", a_client, a_arg);
 }
-// callback for dap_client_new() in chain_node_client_connect()
-static void stage_status_error_callback(dap_client_t *a_client, void *a_arg)
+
+/**
+ * @brief s_stage_status_error_callback
+ * @param a_client
+ * @param a_arg
+ */
+static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
 {
+    (void) a_arg;
+    dap_chain_node_client_t *l_node_client = a_client->_inheritor;
+    if ( DAP_CHAIN_NODE_CLIENT(a_client)->keep_connection &&
+         ( ( dap_client_get_stage(a_client) != STAGE_STREAM_STREAMING )||
+           ( dap_client_get_stage_status(a_client) == STAGE_STATUS_ERROR  ) ) ){
+        log_it(L_NOTICE,"Some errors happends, current state is %s but we need to return back to STAGE_STREAM_STREAMING",
+                 dap_client_get_stage_str(a_client) ) ;
+
+        pthread_mutex_unlock(&l_node_client->wait_mutex);
+        log_it(L_DEBUG,"Wakeup all who waits");
+        l_node_client->state = NODE_CLIENT_STATE_ERROR;
+        pthread_cond_signal(&l_node_client->wait_cond);
+
+        //dap_client_go_stage( a_client , STAGE_STREAM_STREAMING, s_stage_end_callback );
+    }
     //printf("* tage_status_error_callback client=%x data=%x\n", a_client, a_arg);
 }
 
-// callback for the end of connection in dap_chain_node_client_connect()->dap_client_go_stage()
-static void a_stage_end_callback(dap_client_t *a_client, void *a_arg)
+/**
+ * @brief a_stage_end_callback
+ * @param a_client
+ * @param a_arg
+ */
+static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
+{
+    dap_chain_node_client_t *l_node_client = a_client->_inheritor;
+    assert(l_node_client);
+    if(l_node_client) {
+        log_it(L_NOTICE,"Stream connection with node " NODE_ADDR_FP_STR " established",
+               NODE_ADDR_FP_ARGS_S( l_node_client->remote_node_addr) );
+        pthread_mutex_lock(&l_node_client->wait_mutex);
+        l_node_client->state = NODE_CLIENT_STATE_CONNECTED;
+
+        dap_stream_ch_t * l_ch = dap_client_get_stream_ch( a_client , dap_stream_ch_chain_get_id() );
+        if (l_ch){
+            dap_stream_ch_chain_t * l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+            l_ch_chain->callback_notify_packet_out = s_ch_chain_callback_notify_packet_out;
+            l_ch_chain->callback_notify_packet_in = s_ch_chain_callback_notify_packet_in;
+            l_ch_chain->callback_notify_arg = l_node_client;
+        }else {
+            log_it(L_WARNING,"No ch_chain channel, can't init notify callback for pkt type CH_CHAIN");
+        }
+
+        pthread_mutex_unlock(&l_node_client->wait_mutex);
+        if ( l_node_client->callback_connected )
+            l_node_client->callback_connected(l_node_client,a_arg);
+        l_node_client->keep_connection = true;
+        log_it(L_DEBUG,"Wakeup all who waits");
+        pthread_cond_signal(&l_node_client->wait_cond);
+    }
+}
+
+/**
+ * @brief s_ch_chain_callback_notify_packet
+ * @param a_pkt_type
+ * @param a_pkt
+ * @param a_pkt_data_size
+ * @param a_arg
+ */
+static void s_ch_chain_callback_notify_packet_in(dap_stream_ch_chain_t* a_ch_chain, uint8_t a_pkt_type,
+                                                      dap_stream_ch_chain_pkt_t *a_pkt, size_t a_pkt_data_size,
+                                                      void * a_arg)
+{
+    dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t *) a_arg;
+    switch (a_pkt_type) {
+        case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR:
+            pthread_mutex_lock(&l_node_client->wait_mutex);
+            l_node_client->state = NODE_CLIENT_STATE_ERROR ;
+            snprintf(l_node_client->last_error,sizeof (l_node_client->last_error),
+                     "%s", (char*) a_pkt->data );
+            log_it(L_WARNING,"Received packet DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR with error \"%s\"",
+                   l_node_client->last_error);
+            pthread_mutex_unlock(&l_node_client->wait_mutex);
+            pthread_cond_signal(&l_node_client->wait_cond);
+
+        case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_NODE_ADDR_LEASE:
+            pthread_mutex_lock(&l_node_client->wait_mutex);
+            l_node_client->state = NODE_CLIENT_STATE_NODE_ADDR_LEASED;
+            pthread_mutex_unlock(&l_node_client->wait_mutex);
+            pthread_cond_signal(&l_node_client->wait_cond);
+        break;
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL:
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB:
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS:{
+            dap_stream_ch_chain_sync_request_t * l_request = NULL;
+            if ( a_pkt_data_size == sizeof ( *l_request))
+                l_request = (dap_stream_ch_chain_sync_request_t* ) a_pkt->data;
+
+            if ( l_request ){
+                if ( l_request->ts_start < (uint64_t) dap_db_log_get_last_timestamp() ){
+                    log_it(L_INFO, "Remote is synced but we have updates for it");
+                    // Get log diff
+                    a_ch_chain->request_last_ts = dap_db_log_get_last_timestamp();
+                    dap_list_t *l_list = dap_db_log_get_list((time_t) l_request->ts_start);
+
+                    if ( l_list ) {
+                        // Add it to outgoing list
+                        l_list->prev = a_ch_chain->request_global_db_trs;
+                        a_ch_chain->request_global_db_trs = l_list;
+                        a_ch_chain->request_net_id.uint64 = a_pkt->hdr.net_id.uint64;
+                        a_ch_chain->request_cell_id.uint64 = a_pkt->hdr.cell_id.uint64;
+                        a_ch_chain->request_chain_id.uint64 = a_pkt->hdr.chain_id.uint64;
+                        a_ch_chain->state = CHAIN_STATE_SYNC_GLOBAL_DB ;
+
+                        log_it(L_INFO, "Sync for remote tr_count=%d",dap_list_length(l_list));
+                        dap_stream_ch_set_ready_to_write(a_ch_chain->ch, true);
+                    }
+                }else {
+                    log_it(L_INFO, "Remote node has lastes ts for us");
+                    pthread_mutex_lock(&l_node_client->wait_mutex);
+                    l_node_client->state = NODE_CLIENT_STATE_SYNCED;
+                    pthread_mutex_unlock(&l_node_client->wait_mutex);
+                    pthread_cond_signal(&l_node_client->wait_cond);
+                }
+            }else {
+                log_it(L_INFO, "Sync notify without request to sync back, stay in SYNCED state");
+                pthread_mutex_lock(&l_node_client->wait_mutex);
+                l_node_client->state = NODE_CLIENT_STATE_SYNCED;
+                pthread_mutex_unlock(&l_node_client->wait_mutex);
+                pthread_cond_signal(&l_node_client->wait_cond);
+            }
+
+        }
+        default:{}
+    }
+}
+
+/**
+ * @brief s_ch_chain_callback_notify_packet_in
+ * @param a_ch_chain
+ * @param a_pkt_type
+ * @param a_pkt
+ * @param a_pkt_data_size
+ * @param a_arg
+ */
+static void s_ch_chain_callback_notify_packet_out(dap_stream_ch_chain_t* a_ch_chain, uint8_t a_pkt_type,
+                                                      dap_stream_ch_chain_pkt_t *a_pkt, size_t a_pkt_data_size,
+                                                      void * a_arg)
 {
-    dap_chain_node_client_t *client = a_client->_inheritor;
-    assert(client);
-    if(client) {
-        pthread_mutex_lock(&client->wait_mutex);
-        client->state = NODE_CLIENT_STATE_CONNECTED;
-        pthread_cond_signal(&client->wait_cond);
-        pthread_mutex_unlock(&client->wait_mutex);
+    (void) a_pkt;
+    (void) a_pkt_data_size;
+    (void) a_ch_chain;
+    dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t *) a_arg;
+    switch (a_pkt_type) {
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL:
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB:
+        case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_CHAINS:{
+            pthread_mutex_lock(&l_node_client->wait_mutex);
+            l_node_client->state = NODE_CLIENT_STATE_SYNCED;
+            pthread_mutex_unlock(&l_node_client->wait_mutex);
+            pthread_cond_signal(&l_node_client->wait_cond);
+        }break;
+        default:{}
     }
 }
 
@@ -101,31 +267,35 @@ static void a_stage_end_callback(dap_client_t *a_client, void *a_arg)
  *
  * return a connection handle, or NULL, if an error
  */
-dap_chain_node_client_t* dap_chain_node_client_connect(dap_chain_node_info_t *node_info)
+dap_chain_node_client_t* dap_chain_node_client_connect(dap_chain_node_info_t *a_node_info)
 {
-    if(!node_info)
+    if(!a_node_info){
+        log_it(L_ERROR,"Can't connect to the node: null object node_info");
         return NULL;
+    }
     dap_chain_node_client_t *l_node_client = DAP_NEW_Z(dap_chain_node_client_t);
-    l_node_client->state = NODE_CLIENT_STATE_INIT;
+    l_node_client->state = NODE_CLIENT_STATE_DISCONNECTED;
     pthread_condattr_t attr;
     pthread_condattr_init(&attr);
     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
     pthread_cond_init(&l_node_client->wait_cond, &attr);
     pthread_mutex_init(&l_node_client->wait_mutex, NULL);
     l_node_client->events = NULL; //dap_events_new();
-    l_node_client->client = dap_client_new(l_node_client->events, stage_status_callback, stage_status_error_callback);
+    l_node_client->client = dap_client_new(l_node_client->events, stage_status_callback, s_stage_status_error_callback);
     l_node_client->client->_inheritor = l_node_client;
+    l_node_client->remote_node_addr.uint64 = a_node_info->hdr.address.uint64;
+    dap_client_set_active_channels(l_node_client->client,"CN");
 
     int hostlen = 128;
     char host[hostlen];
-    if(node_info->hdr.ext_addr_v4.s_addr)
+    if(a_node_info->hdr.ext_addr_v4.s_addr)
     {
-        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = node_info->hdr.ext_addr_v4 };
+        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = a_node_info->hdr.ext_addr_v4 };
         inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host, hostlen);
     }
     else
     {
-        struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = node_info->hdr.ext_addr_v6 };
+        struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = a_node_info->hdr.ext_addr_v6 };
         inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), host, hostlen);
     }
     // address not defined
@@ -135,11 +305,11 @@ dap_chain_node_client_t* dap_chain_node_client_connect(dap_chain_node_info_t *no
     }
     dap_client_set_uplink(l_node_client->client, strdup(host), listen_port_tcp);
 //    dap_client_stage_t a_stage_target = STAGE_ENC_INIT;
-    dap_client_stage_t a_stage_target = STAGE_STREAM_STREAMING;
+    dap_client_stage_t l_stage_target = STAGE_STREAM_STREAMING;
 
     l_node_client->state = NODE_CLIENT_STATE_CONNECT;
     // Handshake & connect
-    dap_client_go_stage(l_node_client->client, a_stage_target, a_stage_end_callback);
+    dap_client_go_stage(l_node_client->client, l_stage_target, s_stage_connected_callback);
     return l_node_client;
 }
 
@@ -150,144 +320,36 @@ void dap_chain_node_client_close(dap_chain_node_client_t *a_client)
 {
     if(a_client) {
         // clean client
-        dap_client_delete(a_client->client);
-        dap_events_delete(a_client->events);
+        //dap_client_delete(a_client->client);
         pthread_cond_destroy(&a_client->wait_cond);
         pthread_mutex_destroy(&a_client->wait_mutex);
         DAP_DELETE(a_client);
     }
 }
 
-/*
- // callback for dap_client_request_enc() in client_mempool_send_datum()
- static void s_response_proc(dap_client_t *a_client, void *str, size_t str_len)
- {
- printf("* s_response_proc a_client=%x str=%s str_len=%d\n", a_client, str, str_len);
- dap_chain_node_client_t *l_client = a_client->_inheritor;
- assert(l_client);
- if(l_client) {
- if(str_len > 0) {
- //            l_client->read_data_t.data = DAP_NEW_Z_SIZE(uint8_t, str_len + 1);
- //          if(l_client->read_data_t.data) {
- //                memcpy(l_client->read_data_t.data, str, str_len);
- //                l_client->read_data_t.data_len = str_len;
- }
- }
- pthread_mutex_lock(&l_client->wait_mutex);
- l_client->state = NODE_CLIENT_STATE_SENDED;
- pthread_cond_signal(&l_client->wait_cond);
- pthread_mutex_unlock(&l_client->wait_mutex);
- }
- */
-
-/*// callback for dap_client_request_enc() in client_mempool_send_datum()
- static void s_response_error(dap_client_t *a_client, int val)
- {
- printf("* s_response_error a_client=%x val=%d\n", a_client, val);
- client_mempool_t *mempool = a_client->_inheritor;
- assert(mempool);
- if(mempool) {
- pthread_mutex_lock(&mempool->wait_mutex);
- mempool->state = CLIENT_MEMPOOL_ERROR;
- pthread_cond_signal(&mempool->wait_cond);
- pthread_mutex_unlock(&mempool->wait_mutex);
- }
- }
-
- // set new state and delete previous read data
- static void dap_chain_node_client_reset(dap_chain_node_client_t *a_client, int new_state)
- {
- if(!a_client)
- return;
- pthread_mutex_lock(&a_client->wait_mutex);
- //a_client->read_data_t.data_len = 0;
- //DAP_DELETE(a_client->read_data_t.data);
- //a_client->read_data_t.data = NULL;
- a_client->state = new_state;
- pthread_mutex_unlock(&a_client->wait_mutex);
- }*/
-
-static void dap_chain_node_client_callback(dap_stream_ch_chain_net_pkt_t *a_ch_chain_net, size_t a_data_size,
-        void *a_arg)
-{
-    dap_chain_node_client_t *client = (dap_chain_node_client_t*) a_arg;
-    assert(client);
-    // end of session
-    if(!a_ch_chain_net)
-    {
-        pthread_mutex_lock(&client->wait_mutex);
-        client->state = NODE_CLIENT_STATE_END;
-        pthread_cond_signal(&client->wait_cond);
-        pthread_mutex_unlock(&client->wait_mutex);
-        return;
-    }
-
-    int l_state;
-    //printf("*callback type=%d\n", a_ch_chain_net->hdr.type);
-
-    switch (a_ch_chain_net->hdr.type) {
-    case STREAM_CH_CHAIN_NET_PKT_TYPE_PING:
-        l_state = NODE_CLIENT_STATE_PING;
-        break;
-    case STREAM_CH_CHAIN_NET_PKT_TYPE_PONG:
-        l_state = NODE_CLIENT_STATE_PONG;
-        break;
-    case STREAM_CH_CHAIN_NET_PKT_TYPE_GET_NODE_ADDR:
-        l_state = NODE_CLIENT_STATE_GET_NODE_ADDR;
-        client->recv_data_len = a_data_size;
-        if(client->recv_data_len > 0) {
-            client->recv_data = DAP_NEW_SIZE(uint8_t, a_data_size);
-            memcpy(client->recv_data, a_ch_chain_net->data, a_data_size);
-        }
-
-        break;
-    case STREAM_CH_CHAIN_NET_PKT_TYPE_SET_NODE_ADDR:
-        l_state = NODE_CLIENT_STATE_SET_NODE_ADDR;
-        break;
-//    case STREAM_CH_CHAIN_NET_PKT_TYPE_GLOVAL_DB:
-//        l_state = NODE_CLIENT_STATE_CONNECTED;
-//        break;
-
-    default:
-        l_state = NODE_CLIENT_STATE_ERROR;
-
-    }
-    if(client)
-    {
-        pthread_mutex_lock(&client->wait_mutex);
-        client->state = l_state;
-        pthread_cond_signal(&client->wait_cond);
-        pthread_mutex_unlock(&client->wait_mutex);
-    }
-}
 
 /**
  * Send stream request to server
  */
-int dap_chain_node_client_send_chain_net_request(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
-        char *a_buf, size_t a_buf_size)
+int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
+        const void *a_pkt_data, size_t a_pkt_data_size)
 {
     if(!a_client || a_client->state < NODE_CLIENT_STATE_CONNECTED)
         return -1;
-    dap_stream_t *l_stream = dap_client_get_stream(a_client->client);
+
+//    dap_stream_t *l_stream = dap_client_get_stream(a_client->client);
     dap_stream_ch_t * l_ch = dap_client_get_stream_ch(a_client->client, a_ch_id);
-    if(l_ch)
-    {
-        dap_stream_ch_chain_net_t * l_ch_chain = DAP_STREAM_CH_CHAIN_NET(l_ch);
-        l_ch_chain->notify_callback = dap_chain_node_client_callback;
-        l_ch_chain->notify_callback_arg = a_client;
-        int l_res = dap_stream_ch_chain_net_pkt_write(l_ch, a_type, a_buf, a_buf_size);
-        if(l_res <= 0)
-            return -1;
-        bool is_ready = true;
-        dap_events_socket_set_writable(l_ch->stream->events_socket, is_ready);
-        //dap_stream_ch_ready_to_write(ch, true);
-    }
-    else
+    if(l_ch){
+//        dap_stream_ch_chain_net_t * l_ch_chain = DAP_STREAM_CH_CHAIN_NET(l_ch);
+
+        dap_stream_ch_pkt_write(l_ch, a_type, a_pkt_data, a_pkt_data_size);
+        dap_stream_ch_set_ready_to_write(l_ch, true);
+        return 0;
+    }else
         return -1;
-    return 1;
 }
 
+
 /**
  * wait for the complete of request
  *
@@ -295,11 +357,11 @@ int dap_chain_node_client_send_chain_net_request(dap_chain_node_client_t *a_clie
  * waited_state state which we will wait, sample NODE_CLIENT_STATE_CONNECT or NODE_CLIENT_STATE_SENDED
  * return -1 false, 0 timeout, 1 end of connection or sending data
  */
-int chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state, int timeout_ms)
+int dap_chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state, int a_timeout_ms)
 {
     int ret = -1;
     if(!a_client)
-        return -1;
+        return -3;
     pthread_mutex_lock(&a_client->wait_mutex);
     // have waited
     if(a_client->state == a_waited_state) {
@@ -309,7 +371,7 @@ int chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state
     // prepare for signal waiting
     struct timespec to;
     clock_gettime(CLOCK_MONOTONIC, &to);
-    int64_t nsec_new = to.tv_nsec + timeout_ms * 1000000ll;
+    int64_t nsec_new = to.tv_nsec + a_timeout_ms * 1000000ll;
     // if the new number of nanoseconds is more than a second
     if(nsec_new > (long) 1e9) {
         to.tv_sec += nsec_new / (long) 1e9;
@@ -319,13 +381,17 @@ int chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state
         to.tv_nsec = (long) nsec_new;
     // signal waiting
     do {
+
         int wait = pthread_cond_timedwait(&a_client->wait_cond, &a_client->wait_mutex, &to);
-        if(wait == 0 && a_client->state == a_waited_state) {
-            ret = 1;
+        if(wait == 0 && (
+                    a_client->state == a_waited_state ||
+                    a_client->state == NODE_CLIENT_STATE_ERROR )
+          ) {
+            ret = a_client->state == a_waited_state ? 0 : -2;
             break;
         }
         else if(wait == ETIMEDOUT) { // 110 260
-            ret = 0;
+            ret = -1;
             break;
         }
     }
diff --git a/dap_chain_node_client.h b/dap_chain_node_client.h
index a9fd376732a8c113d9266b97cd66ffebceb32b9a..200519dbcd8541931fa82185872d5ed344ffd17d 100644
--- a/dap_chain_node_client.h
+++ b/dap_chain_node_client.h
@@ -31,19 +31,18 @@
 // connection states
 typedef enum dap_chain_node_client_state{
     NODE_CLIENT_STATE_ERROR = -1,
-    NODE_CLIENT_STATE_INIT,
-    NODE_CLIENT_STATE_GET_NODE_ADDR,
-    NODE_CLIENT_STATE_SET_NODE_ADDR,
-    NODE_CLIENT_STATE_PING,
-    NODE_CLIENT_STATE_PONG,
-    NODE_CLIENT_STATE_CONNECT,
-    NODE_CLIENT_STATE_CONNECTED,
+    NODE_CLIENT_STATE_DISCONNECTED=0,
+    NODE_CLIENT_STATE_GET_NODE_ADDR=1,
+    NODE_CLIENT_STATE_NODE_ADDR_LEASED=2,
+    NODE_CLIENT_STATE_PING=3,
+    NODE_CLIENT_STATE_PONG=4,
+    NODE_CLIENT_STATE_CONNECT=5,
+    NODE_CLIENT_STATE_CONNECTED=100,
     //NODE_CLIENT_STATE_SEND,
     //NODE_CLIENT_STATE_SENDED,
-    NODE_CLIENT_STATE_SYNC_GDB,
-    NODE_CLIENT_STATE_SYNC_CHAINS,
-    NODE_CLIENT_STATE_STANDBY,
-    NODE_CLIENT_STATE_END
+    NODE_CLIENT_STATE_SYNC_GDB=101,
+    NODE_CLIENT_STATE_SYNC_CHAINS=102,
+    NODE_CLIENT_STATE_SYNCED=103
 } dap_chain_node_client_state_t;
 
 typedef struct dap_chain_node_client dap_chain_node_client_t;
@@ -56,19 +55,21 @@ typedef struct dap_chain_node_client {
     dap_chain_cell_id_t cell_id;
     dap_client_t *client;
     dap_events_t *events;
+    char last_error[128];
 
-    dap_chain_node_client_callback_t callback_stream_connected;
+    dap_chain_node_client_callback_t callback_connected;
     pthread_cond_t wait_cond;
     pthread_mutex_t wait_mutex;
-    uint8_t *recv_data;
-    size_t recv_data_len;
 
     // For hash indexing
     UT_hash_handle hh;
     dap_chain_node_addr_t remote_node_addr;
     struct in_addr remote_ipv4;
     struct in6_addr remote_ipv6;
+
+    bool keep_connection;
 } dap_chain_node_client_t;
+#define DAP_CHAIN_NODE_CLIENT(a) ( (dap_chain_node_client_t *) (a)->_inheritor )
 
 
 int dap_chain_node_client_init(void);
@@ -92,8 +93,8 @@ void dap_chain_node_client_close(dap_chain_node_client_t *client);
 /**
  * Send stream request to server
  */
-int dap_chain_node_client_send_chain_net_request(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
-        char *a_buf, size_t a_buf_size);
+int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
+        const void *a_buf, size_t a_buf_size);
 
 /**
  * wait for the complete of request
@@ -102,5 +103,5 @@ int dap_chain_node_client_send_chain_net_request(dap_chain_node_client_t *a_clie
  * waited_state state which we will wait, sample NODE_CLIENT_STATE_CONNECT or NODE_CLIENT_STATE_SENDED
  * return -1 false, 0 timeout, 1 end of connection or sending data
  */
-int chain_node_client_wait(dap_chain_node_client_t *client, dap_chain_node_client_state_t waited_state, int timeout_ms);
+int dap_chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state, int a_timeout_ms);