From cafdf34d298471a65c0b5ca2953ca8507c9edf61 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Sun, 23 Jul 2023 15:08:01 +0000
Subject: [PATCH] hotfix-9105

---
 dap-sdk                                       |  2 +-
 modules/chain/dap_chain.c                     | 21 +++-------
 modules/chain/dap_chain_cell.c                |  2 +-
 modules/chain/dap_chain_ledger.c              | 41 ++++++++++++++++--
 modules/chain/include/dap_chain.h             |  9 ++++
 modules/chain/include/dap_chain_ledger.h      |  7 +++-
 modules/chain/tests/dap_chain_ledger_tests.c  |  2 +-
 modules/common/dap_chain_common.c             | 11 +++++
 modules/common/include/dap_chain_common.h     |  1 +
 .../consensus/dag-poa/dap_chain_cs_dag_poa.c  |  6 +--
 modules/net/dap_chain_net.c                   | 42 +++++++++----------
 modules/net/dap_chain_node_cli_cmd.c          | 33 +++++++++++----
 modules/net/include/dap_chain_net.h           | 11 +++++
 modules/type/dag/dap_chain_cs_dag.c           | 13 ++----
 14 files changed, 136 insertions(+), 65 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 4d57135408..94a7061f5e 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 4d571354084d3781ea0de431269609496348b76e
+Subproject commit 94a7061f5e9d6332a3de7ddfa70b0b7d6b86abbf
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 029c26b86f..326f4538c9 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -354,25 +354,15 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
         if (l_cfg)
 		{
             dap_chain_t		*l_chain		= NULL;
-            dap_chain_id_t	l_chain_id		= {{0}};
-            uint64_t		l_chain_id_u	= 0;
+            dap_chain_id_t	l_chain_id		= {};
             const char		*l_chain_id_str	= NULL;
             const char 		*l_chain_name	= NULL;
 
             // Recognize chains id
-            if ( (l_chain_id_str = dap_config_get_item_str(l_cfg,"chain","id")) != NULL )
-			{
-                if (sscanf(l_chain_id_str, "0x%"DAP_UINT64_FORMAT_X, & l_chain_id_u)		!=1)
-				{
-                    if (sscanf(l_chain_id_str, "0x%"DAP_UINT64_FORMAT_x, &l_chain_id_u)		!=1)
-					{
-                        if (sscanf(l_chain_id_str, "%"DAP_UINT64_FORMAT_U, &l_chain_id_u)	!=1)
-						{
-                            log_it (L_ERROR,"Can't recognize '%s' string as chain net id, hex or dec",l_chain_id_str);
-                            dap_config_close(l_cfg);
-                            return NULL;
-                        }
-                    }
+            if ( (l_chain_id_str = dap_config_get_item_str(l_cfg,"chain","id")) != NULL ) {
+                if (dap_chain_id_parse(l_chain_id_str, &l_chain_id) != 0) {
+                    dap_config_close(l_cfg);
+                    return NULL;
                 }
             } else {
                 log_it (L_ERROR, "Wasn't found chain id string in config");
@@ -380,7 +370,6 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
                 return NULL;
             }
 
-            l_chain_id.uint64 = l_chain_id_u;
             log_it (L_NOTICE, "Chain id 0x%016"DAP_UINT64_FORMAT_x"  ( \"%s\" )", l_chain_id.uint64, l_chain_id_str);
 
             // Read chain name
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index b9b2cb4b94..40554b4008 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -125,7 +125,7 @@ dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_c
 dap_chain_cell_t * dap_chain_cell_create_fill2(dap_chain_t * a_chain, const char *a_filename)
 {
     uint64_t l_cell_id_uint64;
-    dap_sscanf(a_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64);
+    sscanf(a_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64);
     return dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64});
 }
 
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index a13a7cbb29..8078dc806d 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -273,6 +273,11 @@ typedef struct dap_chain_ledger_tx_notifier {
     void *arg;
 } dap_chain_ledger_tx_notifier_t;
 
+typedef struct dap_chain_ledger_bridged_tx_notificator {
+    dap_chain_ledger_bridged_tx_notify_t callback;
+    void *arg;
+} dap_chain_ledger_bridged_tx_notificator_t;
+
 // dap_ledget_t private section
 typedef struct dap_ledger_private {
     const char *net_native_ticker;
@@ -309,6 +314,10 @@ typedef struct dap_ledger_private {
     bool check_token_emission;
     dap_chain_cell_id_t local_cell_id;
 
+    //Notificators
+    dap_list_t *bridged_tx_notificators;
+    dap_list_t *tx_add_notifiers;
+
     bool load_mode;
     bool cached;
     dap_chain_ledger_cache_tx_check_callback_t cache_tx_check_callback;
@@ -2494,7 +2503,7 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
  * @param a_net_name char * network name, for example "kelvin-testnet"
  * @return dap_ledger_t*
  */
-dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs)
+dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, dap_chain_net_id_t a_net_id, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs)
 {
     dap_ledger_t *l_ledger = dap_chain_ledger_handle_new();
     if (!l_ledger) {
@@ -2502,6 +2511,7 @@ dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const
         return NULL;
     }
     l_ledger->net_name = a_net_name;
+    l_ledger->net_id = a_net_id;
     dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger);
     l_ledger_pvt->net_native_ticker = a_net_native_ticker;
     l_ledger_pvt->poa_certs = a_poa_certs;
@@ -4597,6 +4607,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
 
     //Update balance : raise
     bool l_multichannel = false;
+    bool l_cross_network = false;
     for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
         if (!l_tx_out->data) {
             debug_if(s_debug_more, L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache");
@@ -4642,6 +4653,10 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             log_it(L_DEBUG, "Unknown item type %d", l_type);
             break;
         }
+        if (!l_addr)
+            continue;
+        else if (l_addr->net_id.uint64 != a_ledger->net_id.uint64)
+            l_cross_network = true;
         char *l_addr_str = dap_chain_addr_to_str(l_addr);
         dap_ledger_wallet_balance_t *wallet_balance = NULL;
         char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL);
@@ -4709,10 +4724,16 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
                          l_tx_item, s_sort_ledger_tx_item); // tx_hash_fast: name of key field
     if(a_safe_call) pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
     // Callable callback
-    for (dap_list_t *notifier = a_ledger->tx_add_notifiers; notifier != NULL; notifier = notifier->next) {
+    for (dap_list_t *notifier = PVT(a_ledger)->tx_add_notifiers; notifier != NULL; notifier = notifier->next) {
         dap_chain_ledger_tx_notifier_t *l_notify = (dap_chain_ledger_tx_notifier_t *)notifier->data;
         l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx);
     }
+    if (l_cross_network) {
+        for (dap_list_t *it = PVT(a_ledger)->bridged_tx_notificators; it; it = it->next) {
+            dap_chain_ledger_bridged_tx_notificator_t *l_notify = it->data;
+            l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg);
+        }
+    }
     // Count TPS
     clock_gettime(CLOCK_REALTIME, &l_ledger_pvt->tps_end_time);
     l_ledger_pvt->tps_count++;
@@ -5698,7 +5719,21 @@ void dap_chain_ledger_tx_add_notify(dap_ledger_t *a_ledger, dap_chain_ledger_tx_
     }
     l_notifier->callback = a_callback;
     l_notifier->arg = a_arg;
-    a_ledger->tx_add_notifiers = dap_list_append(a_ledger->tx_add_notifiers, l_notifier);
+    PVT(a_ledger)->tx_add_notifiers = dap_list_append(PVT(a_ledger)->tx_add_notifiers, l_notifier);
+}
+
+void dap_chain_ledger_bridged_tx_notify_add(dap_ledger_t *a_ledger, dap_chain_ledger_bridged_tx_notify_t a_callback, void *a_arg)
+{
+    if (!a_ledger || !a_callback)
+        return;
+    dap_chain_ledger_bridged_tx_notificator_t *l_notifier = DAP_NEW_Z(dap_chain_ledger_bridged_tx_notificator_t);
+    if (!l_notifier) {
+        log_it(L_ERROR, "Can't allocate memory for notifier in dap_chain_ledger_tx_add_notify()");
+        return;
+    }
+    l_notifier->callback = a_callback;
+    l_notifier->arg = a_arg;
+    PVT(a_ledger)->bridged_tx_notificators = dap_list_append(PVT(a_ledger)->bridged_tx_notificators , l_notifier);
 }
 
 bool dap_chain_ledger_cache_enabled(dap_ledger_t *a_ledger)
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index fda6fe0e59..fb80f3a4b9 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -223,6 +223,15 @@ typedef struct dap_chain_atom_notifier {
 
 #define DAP_CHAIN(a) ( (dap_chain_t *) (a)->_inheritor)
 
+DAP_STATIC_INLINE int dap_chain_id_parse(const char *a_id_str, dap_chain_id_t *a_id)
+{
+    uint64_t l_id;
+    int res = dap_id_uint64_parse(a_id_str, &l_id);
+    if (!res)
+        a_id->uint64 = l_id;
+    return res;
+}
+
 int dap_chain_init(void);
 void dap_chain_deinit(void);
 
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index 8e9bbd7f56..54426f5ad4 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -38,7 +38,7 @@
 
 typedef struct dap_ledger {
     char *net_name;
-    dap_list_t *tx_add_notifiers;
+    dap_chain_net_id_t net_id;
     void *_internal;
 } dap_ledger_t;
 
@@ -112,6 +112,7 @@ typedef enum dap_chain_ledger_token_decl_add_err{
 typedef bool (*dap_chain_ledger_verificator_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_tx_out_cond, dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 typedef void (*dap_chain_ledger_updater_callback_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_prev_cond);
 typedef void (* dap_chain_ledger_tx_add_notify_t)(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+typedef void (* dap_chain_ledger_bridged_tx_notify_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, void *a_arg);
 typedef bool (*dap_chain_ledger_cache_tx_check_callback_t)(dap_hash_fast_t *a_tx_hash);
 typedef struct dap_chain_net dap_chain_net_t;
 
@@ -146,7 +147,7 @@ typedef struct dap_chain_net dap_chain_net_t;
 int dap_chain_ledger_init();
 void dap_chain_ledger_deinit();
 
-dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs);
+dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, dap_chain_net_id_t a_net_id, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs);
 
 void dap_chain_ledger_set_fee(dap_ledger_t *a_ledger, uint256_t a_fee, dap_chain_addr_t a_fee_addr);
 
@@ -349,6 +350,8 @@ dap_list_t * dap_chain_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, si
 //bool dap_chain_ledger_fee_verificator(dap_ledger_t* a_ledger, dap_chain_tx_out_cond_t* a_cond, dap_chain_datum_tx_t* a_tx, bool a_owner);
 
 void dap_chain_ledger_tx_add_notify(dap_ledger_t *a_ledger, dap_chain_ledger_tx_add_notify_t a_callback, void *a_arg);
+void dap_chain_ledger_bridged_tx_notify_add(dap_ledger_t *a_ledger, dap_chain_ledger_bridged_tx_notify_t a_callback, void *a_arg);
+
 
 bool dap_chain_ledger_cache_enabled(dap_ledger_t *a_ledger);
 void dap_chain_ledger_set_cache_tx_check_callback(dap_ledger_t *a_ledger, dap_chain_ledger_cache_tx_check_callback_t a_callback);
diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c
index 609408f87a..588c694695 100644
--- a/modules/chain/tests/dap_chain_ledger_tests.c
+++ b/modules/chain/tests/dap_chain_ledger_tests.c
@@ -369,7 +369,7 @@ void dap_chain_ledger_test_run(void){
     dap_print_module_name("dap_chain_ledger");
     uint16_t l_flags = 0;
     l_flags |= DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION;
-    dap_ledger_t *l_ledger = dap_chain_ledger_create(l_flags, "Snet", s_token_ticker, NULL);
+    dap_ledger_t *l_ledger = dap_chain_ledger_create(l_flags, l_iddn, "Snet", s_token_ticker, NULL);
     char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf";
     size_t l_seed_ph_size = strlen(l_seed_ph);
     dap_cert_t *l_cert = dap_cert_generate_mem_with_seed("testCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, l_seed_ph, l_seed_ph_size);
diff --git a/modules/common/dap_chain_common.c b/modules/common/dap_chain_common.c
index 1fcc821a40..7c6d2fdb91 100644
--- a/modules/common/dap_chain_common.c
+++ b/modules/common/dap_chain_common.c
@@ -41,6 +41,17 @@ const dap_chain_net_srv_uid_t c_dap_chain_net_srv_uid_null = {0};
 const dap_chain_cell_id_t c_dap_chain_cell_id_null = {0};
 const dap_chain_addr_t c_dap_chain_addr_blank = {0};
 
+int dap_id_uint64_parse(const char *a_id_str, uint64_t *a_id)
+{
+    if (sscanf(a_id_str, "0x%16"DAP_UINT64_FORMAT_X, a_id) != 1 &&
+            sscanf(a_id_str, "0x%16"DAP_UINT64_FORMAT_x, a_id) != 1 &&
+            sscanf(a_id_str, "%"DAP_UINT64_FORMAT_U, a_id) != 1) {
+        log_it (L_ERROR, "Can't recognize '%s' string as 64-bit id, hex or dec", a_id_str);
+        return -1;
+    }
+    return 0;
+}
+
 /*
  * Forward declarations
  */
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index 2dd92b3c5b..92ab735e54 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -62,6 +62,7 @@ typedef union dap_chain_cell_id {
     uint64_t uint64;
 } DAP_ALIGN_PACKED dap_chain_cell_id_t;
 
+int dap_id_uint64_parse(const char *a_id_str, uint64_t *a_id);
 
 /**
   * @struct Node address
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index 03d2a22def..dc8bcd1aeb 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -437,7 +437,7 @@ static void s_poa_round_check_callback_round_clean(dap_global_db_context_t *a_gl
                 HASH_FIND(hh, l_poa_pvt->active_rounds, &l_round_id, sizeof(uint64_t), l_arg);
                 pthread_rwlock_unlock(&l_poa_pvt->rounds_rwlock);
                 if (l_arg) {
-                    log_it(L_INFO, "Event %s is from currently active round [id %llu]", a_values[i].key, l_round_id);
+                    log_it(L_INFO, "Event %s is from currently active round [id %"DAP_UINT64_FORMAT_U"]", a_values[i].key, l_round_id);
                     continue;
                 }
                 dap_global_db_del_unsafe(a_global_db_context, a_group, a_values[i].key);
@@ -693,7 +693,7 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
     dap_chain_node_role_t l_role = dap_chain_net_get_role(l_cur_net);
     if (l_role.enums == NODE_ROLE_ROOT_MASTER || l_role.enums == NODE_ROLE_ROOT) {
         l_dag->callback_cs_event_round_sync = s_callback_event_round_sync;
-        log_it(L_MSG, "Round complete ID %llu, current ID %llu", l_dag->round_completed, l_dag->round_current);
+        log_it(L_MSG, "Round complete ID %"DAP_UINT64_FORMAT_U", current ID %"DAP_UINT64_FORMAT_U, l_dag->round_completed, l_dag->round_current);
         if (l_dag->round_completed > l_dag->round_current) {
             l_dag->round_completed = l_dag->round_current;
             l_dag->round_current = l_dag->round_completed + 1;
@@ -799,7 +799,7 @@ static int s_callback_event_round_sync(dap_chain_cs_dag_t * a_dag, const char a_
         HASH_FIND(hh, l_poa_pvt->active_rounds, &l_round_id, sizeof(uint64_t), l_round_active);
         pthread_rwlock_unlock(&l_poa_pvt->rounds_rwlock);
         if (!l_round_active) {
-            log_it(L_DEBUG, "DAG event came from too old round [last complete id %llu > %llu], skip it",
+            log_it(L_DEBUG, "DAG event came from too old round [last complete id %"DAP_UINT64_FORMAT_U" > %"DAP_UINT64_FORMAT_U"], skip it",
                    a_dag->round_completed, l_event->header.round_id);
             DAP_DELETE(l_event);
             return -2;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 4d59d3820c..c4062c9352 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -294,8 +294,6 @@ static void s_update_links_timer_callback(void *a_arg){
     DAP_DELETE(l_node_info);
 }
 
-static bool s_seed_mode = false;
-
 /**
  * @brief
  * init network settings from cellrame-node.cfg file
@@ -332,7 +330,7 @@ int dap_chain_net_init()
             "\tPurge the cache of chain net ledger and recalculate it from chain file\n"
         "net -net <chain net name> poa_cets list\n"
             "\tPrint list of PoA cerificates for this network\n");
-    s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
+
     s_debug_more = dap_config_get_item_bool_default(g_config,"chain_net","debug_more",false);
 
     char * l_net_dir_str = dap_strdup_printf("%s/network", dap_config_path());
@@ -1500,8 +1498,7 @@ static dap_chain_net_t *s_net_new(const char *a_id, const char *a_name,
     pthread_rwlock_init(&PVT(ret)->downlinks_lock, NULL);
     pthread_rwlock_init(&PVT(ret)->balancer_lock, NULL);
     pthread_rwlock_init(&PVT(ret)->states_lock, NULL);
-    if (sscanf(a_id, "0x%016"DAP_UINT64_FORMAT_X, &ret->pub.id.uint64) != 1) {
-        log_it (L_ERROR, "Wrong id format (\"%s\"). Must be like \"0x0123456789ABCDE\"" , a_id );
+    if (dap_chain_net_id_parse(a_id, &ret->pub.id) != 0) {
         DAP_DELETE(ret);
         return NULL;
     }
@@ -2297,6 +2294,16 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
     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);
 
+    // Bridged netwoks allowed to send transactions to
+    uint16_t l_net_ids_count = 0;
+    char **l_bridged_net_ids = dap_config_get_array_str(l_cfg, "general", "bridged_network_ids", &l_net_ids_count);
+    for (uint16_t i = 0; i< l_net_ids_count; i++) {
+        dap_chain_net_id_t l_id;
+        if (dap_chain_net_id_parse(l_bridged_net_ids[i], &l_id) != 0)
+            continue;
+        l_net->pub.bridged_networks = dap_list_append(l_net->pub.bridged_networks, DAP_DUP(&l_id));
+    }
+
     // nodes for special sync
     char **l_gdb_sync_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "gdb_sync_nodes_addrs",
             &l_net_pvt->gdb_sync_nodes_addrs_count);
@@ -2759,7 +2766,7 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
     if (!l_net_keys)
         log_it(L_WARNING,"PoA certificates for net %s not found.", l_net->pub.name);
     // init LEDGER model
-    l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.name, l_net->pub.native_ticker, l_net_keys);
+    l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.id, l_net->pub.name, l_net->pub.native_ticker, l_net_keys);
 
     DAP_DELETE(l_node_addr_str);
     dap_config_close(l_cfg);
@@ -2842,33 +2849,26 @@ int s_net_load(dap_chain_net_t *a_net)
             if (l_chain )
                l_chain->is_datum_pool_proc = true;
             l_net_pvt->only_static_links = true;
-            l_target_state = NET_STATE_ONLINE;
             log_it(L_INFO,"Root node role established");
         } break;
         case NODE_ROLE_CELL_MASTER:
         case NODE_ROLE_MASTER:{
-
             uint16_t l_proc_chains_count=0;
             char ** l_proc_chains = dap_config_get_array_str(l_cfg,"role-master" , "proc_chains", &l_proc_chains_count );
-            for ( size_t i = 0; i< l_proc_chains_count ; i++){
-                dap_chain_id_t l_chain_id = {{0}};
-                if (sscanf( l_proc_chains[i], "0x%16"DAP_UINT64_FORMAT_X,  &l_chain_id.uint64) ==1 ||
-                         sscanf(l_proc_chains[i], "0x%16"DAP_UINT64_FORMAT_x, &l_chain_id.uint64) == 1) {
+            for ( size_t i = 0; i< l_proc_chains_count ; i++) {
+                dap_chain_id_t l_chain_id = {};
+                if (dap_chain_id_parse(l_proc_chains[i], &l_chain_id) == 0) {
                     dap_chain_t * l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id );
-                    if ( l_chain ){
+                    if (l_chain)
                         l_chain->is_datum_pool_proc = true;
-                    }else{
-                        log_it( L_WARNING, "Can't find chain id " );
-                    }
+                    else
+                        log_it(L_WARNING, "Can't find chain id 0x%016" DAP_UINT64_FORMAT_X, l_chain_id.uint64);
                 }
             }
-            l_net_pvt->only_static_links = true;
-            l_target_state = NET_STATE_ONLINE;
             log_it(L_INFO,"Master node role established");
         } break;
         case NODE_ROLE_FULL:{
             log_it(L_INFO,"Full node role established");
-            l_target_state = NET_STATE_ONLINE;
         } break;
         case NODE_ROLE_LIGHT:
         default:
@@ -2877,9 +2877,9 @@ int s_net_load(dap_chain_net_t *a_net)
     }
     if (!l_net_pvt->only_static_links)
         l_net_pvt->only_static_links = dap_config_get_item_bool_default(l_cfg, "general", "links_static_only", false);
-    if (s_seed_mode || !dap_config_get_item_bool_default(g_config ,"general", "auto_online",false ) ) { // If we seed we do everything manual. First think - prefil list of node_addrs and its aliases
+    if (!dap_config_get_item_bool_default(g_config ,"general", "auto_online", false))
         l_target_state = NET_STATE_OFFLINE;
-    }
+
     l_net_pvt->load_mode = false;
     if (l_net->pub.ledger)
         dap_chain_ledger_load_end(l_net->pub.ledger);
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 72d7304b81..68f97ee6c2 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3174,17 +3174,18 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
 
     dap_chain_datum_t * l_datum = l_datum_hash_hex_str ? (dap_chain_datum_t*) dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str,
                                                                                    &l_datum_size, NULL, NULL ) : NULL;
-    DAP_DELETE(l_gdb_group_mempool);
     size_t l_datum_size2 = l_datum? dap_chain_datum_size( l_datum): 0;
     if (l_datum_size != l_datum_size2) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Corrupted datum %s, size by datum headers is %zd when in mempool is only %zd bytes",
                                           l_datum_hash_hex_str, l_datum_size2, l_datum_size);
         DAP_DELETE(l_datum_hash_hex_str);
+        DAP_DELETE(l_gdb_group_mempool);
         return -8;
     }
     if (!l_datum) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
         DAP_DELETE(l_datum_hash_hex_str);
+        DAP_DELETE(l_gdb_group_mempool);
         return -4;
     }
     dap_hash_fast_t l_datum_hash, l_real_hash;
@@ -3192,6 +3193,7 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't convert datum hash string %s to digital form",
                                           l_datum_hash_hex_str);
         DAP_DELETE(l_datum_hash_hex_str);
+        DAP_DELETE(l_gdb_group_mempool);
         return -7;
     }
     dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_real_hash);
@@ -3199,6 +3201,7 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Datum's real hash doesn't match datum's hash string %s",
                                           l_datum_hash_hex_str);
         DAP_DELETE(l_datum_hash_hex_str);
+        DAP_DELETE(l_gdb_group_mempool);
         return -6;
     }
     char buf[50];
@@ -3233,7 +3236,7 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
     dap_string_append_printf(l_str_tmp, "\n");
     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_tmp->str);
     dap_string_free(l_str_tmp, true);
-
+    DAP_DELETE(l_gdb_group_mempool);
     DAP_DELETE(l_datum_hash_hex_str);
     return ret;
 }
@@ -5464,12 +5467,26 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
     }
 
     // Check, if network ID is same as ID in destination wallet address. If not - operation is cancelled.
-    if (!dap_chain_addr_is_blank(l_addr_to) && l_addr_to->net_id.uint64 != l_net->pub.id.uint64) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "destination wallet network ID=0x%"DAP_UINT64_FORMAT_x
-                                                       " and network ID=0x%"DAP_UINT64_FORMAT_x" is not equal."
-                                                       " Please, change network name or wallet address",
-                                                       l_addr_to->net_id.uint64, l_net->pub.id.uint64);
-        return -13;
+    if (l_addr_to->net_id.uint64 != l_net->pub.id.uint64) {
+        bool l_found = false;
+        for (dap_list_t *it = l_net->pub.bridged_networks; it; it = it->next) {
+            if (((dap_chain_net_id_t *)it->data)->uint64 == l_addr_to->net_id.uint64) {
+                l_found = true;
+                break;
+            }
+        }
+        if (!l_found) {
+            dap_string_t *l_allowed_list = dap_string_new("");
+            dap_string_append_printf(l_allowed_list, "0x%016"DAP_UINT64_FORMAT_X, l_net->pub.id.uint64);
+            for (dap_list_t *it = l_net->pub.bridged_networks; it; it = it->next)
+                dap_string_append_printf(l_allowed_list, ", 0x%016"DAP_UINT64_FORMAT_X, ((dap_chain_net_id_t *)it->data)->uint64);
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Destination network ID=0x%"DAP_UINT64_FORMAT_x
+                                                           " is unreachable. List of available network IDs:\n%s"
+                                                           " Please, change network name or wallet address",
+                                              l_addr_to->net_id.uint64, l_allowed_list->str);
+            dap_string_free(l_allowed_list, true);
+            return -13;
+        }
     }
 
     if(l_tx_num){
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 3e768e20c2..7b99fc79b5 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -88,10 +88,21 @@ typedef struct dap_chain_net{
         const char *native_ticker;
         dap_ledger_t  *ledger;
         dap_chain_net_decree_t *decree;
+
+        dap_list_t *bridged_networks;   // List of bridged network ID's allowed to cross-network TXs
     } pub;
     uint8_t pvt[];
 } dap_chain_net_t;
 
+DAP_STATIC_INLINE int dap_chain_net_id_parse(const char *a_id_str, dap_chain_net_id_t *a_id)
+{
+    uint64_t l_id;
+    int res = dap_id_uint64_parse(a_id_str, &l_id);
+    if (!res)
+        a_id->uint64 = l_id;
+    return res;
+}
+
 typedef bool (dap_chain_datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_chain_t * a_chain, void *a_filter_func_param);
 
 int dap_chain_net_init(void);
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index a0c605e67f..c5fc12cc5e 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -317,18 +317,13 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     l_dag->is_add_directly = dap_config_get_item_bool_default(a_chain_cfg,"dag","is_add_directly",false);
     l_dag->datum_add_hashes_count = dap_config_get_item_uint16_default(a_chain_cfg,"dag","datum_add_hashes_count",1);
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-    l_dag->broadcast_disable = true;
-    char *l_gdb_group = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round" : "dag-%s-%s-round",
+    l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new",
                                           l_net->pub.gdb_groups_prefix, a_chain->name, 0LLU);
-    l_dag->gdb_group_events_round_new = dap_strdup_printf("%s.%s", l_gdb_group,
-                                                          dap_config_get_item_str_default(a_chain_cfg,"dag","gdb_group_events_round_new", "new"));
-    DAP_DELETE(l_gdb_group);
     dap_global_db_add_sync_extra_group(l_net->pub.name, l_dag->gdb_group_events_round_new, s_history_callback_round_notify, l_dag);
-    l_dag->broadcast_disable = false;
     byte_t *l_current_round = dap_global_db_get_sync(l_dag->gdb_group_events_round_new, DAG_ROUND_CURRENT_KEY, NULL, NULL, NULL);
     l_dag->round_current = l_current_round ? *(uint64_t*)l_current_round : 0;
     DAP_DELETE(l_current_round);
-    debug_if(s_debug_more, L_INFO, "Current round id %llu", l_dag->round_current);
+    debug_if(s_debug_more, L_INFO, "Current round id %"DAP_UINT64_FORMAT_U, l_dag->round_current);
     dap_global_db_get_all_raw(l_dag->gdb_group_events_round_new, 0, 0, s_dag_rounds_events_iter, l_dag);
     PVT(l_dag)->mempool_timer = dap_interval_timer_create(15000, s_timer_process_callback, a_chain);
     PVT(l_dag)->events_treshold = NULL;
@@ -735,8 +730,8 @@ static bool s_chain_callback_datums_pool_proc(dap_chain_t *a_chain, dap_chain_da
     dap_get_data_hash_str_static(l_event, l_event_size, l_event_hash_str);
     bool l_res = dap_chain_cs_dag_event_gdb_set(l_dag, l_event_hash_str, l_event, l_event_size, &l_round_item);
     log_it(l_res ? L_INFO : L_ERROR,
-           l_res ? "Event %s placed in the new forming round [id %llu]"
-                 : "Can't add new event [%s] to the new events round [id %llu]",
+           l_res ? "Event %s placed in the new forming round [id %"DAP_UINT64_FORMAT_U"]"
+                 : "Can't add new event [%s] to the new events round [id %"DAP_UINT64_FORMAT_U"]",
            l_event_hash_str, l_round_current);
     return l_res;
 }
-- 
GitLab