From 89ce98948a323fe83e8a6a75e77892496c95d0bd Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Sat, 2 Apr 2022 16:04:58 +0300
Subject: [PATCH] [*] Srv datum frozen

---
 modules/common/include/dap_chain_common.h     |   2 +
 .../include/dap_chain_datum_tx_out_cond.h     |  19 +-
 modules/mempool/dap_chain_mempool.c           |  19 +-
 modules/mempool/include/dap_chain_mempool.h   |   3 +
 modules/net/srv/dap_chain_net_srv.c           | 165 ++++++++++--------
 modules/net/srv/dap_chain_net_srv_order.c     |  16 +-
 modules/net/srv/include/dap_chain_net_srv.h   |  11 ++
 .../service/datum/dap_chain_net_srv_datum.c   |  57 +++++-
 8 files changed, 187 insertions(+), 105 deletions(-)

diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index 965c90a460..99f7cb93bd 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -163,6 +163,7 @@ typedef enum {
     SERV_UNIT_DAY = 0x00000003,  // days
     SERV_UNIT_KB = 0x00000010,  // kilobytes
     SERV_UNIT_B = 0x00000011,   // bytes
+    SERV_UNIT_PCS = 0x00000022  // pieces
 } serv_unit_enum_t;
 
 DAP_STATIC_INLINE const char *serv_unit_enum_to_str(serv_unit_enum_t *unit_enum){
@@ -173,6 +174,7 @@ DAP_STATIC_INLINE const char *serv_unit_enum_to_str(serv_unit_enum_t *unit_enum)
     case SERV_UNIT_DAY: return "SERV_UNIT_DAY";
     case SERV_UNIT_KB: return "SERV_UNIT_KB";
     case SERV_UNIT_B: return "SERV_UNIT_B";
+    case SERV_UNIT_PCS: return "SERV_UNIT_PCS";
     default: return "UNDEFINED";
 
     }
diff --git a/modules/common/include/dap_chain_datum_tx_out_cond.h b/modules/common/include/dap_chain_datum_tx_out_cond.h
index f7f57e8241..39a407918d 100644
--- a/modules/common/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/common/include/dap_chain_datum_tx_out_cond.h
@@ -32,7 +32,8 @@
 enum dap_chain_tx_out_cond_subtype {
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY = 0x01,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE = 0x02,
-    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x13,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x3,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_FEE = 0x04,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE = 0xFA       // Virtual type for stake update verificator //TODO change it to new type of callback for ledger tx add
 };
 typedef byte_t dap_chain_tx_out_cond_subtype_t;
@@ -41,10 +42,11 @@ DAP_STATIC_INLINE const char *dap_chain_tx_out_cond_subtype_to_str(dap_chain_tx_
     switch (a_subtype) {
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY";
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE";
+    case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_FEE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_FEE";
     case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE";
-    default: return "UNDEFINED";
-
+    default: {}
     }
+    return "UNDEFINED";
 }
 
 /**
@@ -57,7 +59,9 @@ typedef struct dap_chain_tx_out_cond {
         dap_chain_tx_item_type_t item_type;
         /// Condition subtype
         dap_chain_tx_out_cond_subtype_t subtype;
-        /// Number of Datoshis ( DAP/10^9 ) to be reserver for service
+        /// Service uid that only could be used for this out
+        dap_chain_net_srv_uid_t srv_uid;
+        /// Number of Datoshis ( DAP/10^18 ) to be reserved for service
         uint256_t value;
         /// When time expires this output could be used only by transaction owner
         dap_chain_time_t ts_expires;
@@ -67,16 +71,12 @@ typedef struct dap_chain_tx_out_cond {
         struct {
             /// Public key hash that could use this conditioned outout
             dap_chain_hash_fast_t pkey_hash;
-            /// Service uid that only could be used for this outout
-            dap_chain_net_srv_uid_t srv_uid;
             /// Price unit thats used to check price max
             dap_chain_net_srv_price_unit_uid_t unit;
             /// Maximum price per unit
             uint256_t unit_price_max_datoshi;
         } srv_pay;
         struct {
-            // Service uid that only could be used for this outout
-            dap_chain_net_srv_uid_t srv_uid;
             // Token ticker to change to
             char token[DAP_CHAIN_TICKER_SIZE_MAX];
             // Chain network to change to
@@ -85,8 +85,6 @@ typedef struct dap_chain_tx_out_cond {
             uint256_t value;
         } srv_xchange;
         struct {
-            // Service uid that only could be used for this outout
-            dap_chain_net_srv_uid_t srv_uid;
             // Stake holder address
             dap_chain_addr_t hldr_addr;
             // Fee address
@@ -99,6 +97,7 @@ typedef struct dap_chain_tx_out_cond {
             dap_chain_node_addr_t signer_node_addr;
         } srv_stake;
     } subtype;
+    byte_t free_space[256]; // for future changes
     uint32_t params_size; // Condition parameters size
     uint8_t params[]; // condition parameters, pkey, hash or smth like this
 } DAP_ALIGN_PACKED dap_chain_tx_out_cond_t;
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 4aa40a2f6f..bdd5049085 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -354,9 +354,9 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 
 }
 
-dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t * a_net, dap_chain_hash_fast_t *a_tx_prev_hash,
-                                                              const dap_chain_addr_t* a_addr_to, dap_enc_key_t *a_key_tx_sign,
-                                                              dap_chain_datum_tx_receipt_t * a_receipt)
+dap_chain_datum_t *dap_chain_tx_create_cond_input(dap_chain_net_t * a_net, dap_chain_hash_fast_t *a_tx_prev_hash,
+                                                  const dap_chain_addr_t* a_addr_to, dap_enc_key_t *a_key_tx_sign,
+                                                  dap_chain_datum_tx_receipt_t * a_receipt)
 {
     dap_ledger_t * l_ledger = a_net ? dap_chain_ledger_by_net_name( a_net->pub.name ) : NULL;
     if ( ! a_net || ! l_ledger || ! a_addr_to )
@@ -436,7 +436,7 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t *
     l_out_cond->header.value = l_old_val;
 
     // add 'sign' items
-    if (a_key_tx_sign){
+    if (a_key_tx_sign) {
         if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_tx_sign) != 1) {
             dap_chain_datum_tx_delete(l_tx);
             log_it( L_ERROR, "Can't add sign output");
@@ -445,10 +445,17 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t *
     }
     size_t l_tx_size = dap_chain_datum_tx_get_size( l_tx );
     dap_chain_datum_t *l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_TX, l_tx, l_tx_size );
+    DAP_DELETE(l_tx);
+    return l_datum;
+}
 
+dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t * a_net, dap_chain_hash_fast_t *a_tx_prev_hash,
+                                                              const dap_chain_addr_t* a_addr_to, dap_enc_key_t *a_key_tx_sign,
+                                                              dap_chain_datum_tx_receipt_t * a_receipt)
+{
+    dap_chain_datum_t *l_datum = dap_chain_tx_create_cond_input(a_net, a_tx_prev_hash, a_addr_to, a_key_tx_sign, a_receipt);
     dap_chain_hash_fast_t *l_key_hash = DAP_NEW_Z( dap_chain_hash_fast_t );
-    dap_hash_fast( l_tx, l_tx_size, l_key_hash );
-    DAP_DELETE( l_tx );
+    dap_hash_fast(l_datum->data, l_datum->header.data_size, l_key_hash);
 
     char * l_key_str = dap_chain_hash_fast_to_str_new( l_key_hash );
 
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index a89a68be4b..60b532ac3a 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -58,6 +58,9 @@ dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond(dap_chain_net_t * a_net,
         uint256_t a_value, uint256_t a_value_per_unit_max, dap_chain_net_srv_price_unit_uid_t a_unit,
         dap_chain_net_srv_uid_t a_srv_uid, uint256_t a_value_fee, const void *a_cond, size_t a_cond_size);
 
+dap_chain_datum_t *dap_chain_tx_create_cond_input(dap_chain_net_t * a_net, dap_chain_hash_fast_t *a_tx_prev_hash,
+                                                  const dap_chain_addr_t* a_addr_to, dap_enc_key_t *a_key_tx_sign,
+                                                  dap_chain_datum_tx_receipt_t * a_receipt);
 dap_chain_hash_fast_t* dap_chain_mempool_tx_create_cond_input(dap_chain_net_t * a_net, dap_chain_hash_fast_t *a_tx_prev_hash,
         const dap_chain_addr_t *a_addr_to, dap_enc_key_t *a_key_tx_sign, dap_chain_datum_tx_receipt_t *a_receipt);
 
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 9edc256250..f1f25554f0 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -610,6 +610,95 @@ bool dap_chain_net_srv_pay_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chai
     if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash))
         return false;
     return dap_hash_fast_compare(&l_pkey_hash, &a_cond->subtype.srv_pay.pkey_hash);
+    // TODO add comparision a_tx sign pkey with receipt provider sign pkey
+}
+
+int dap_chain_net_srv_parse_pricelist(dap_chain_net_srv_t *a_srv, const char *a_config_section)
+{
+    int ret = 0;
+    if (!a_config_section)
+        return ret;
+    a_srv->grace_period = dap_config_get_item_uint32_default(g_config, a_config_section, "grace_period", 60);
+    //! IMPORTANT ! This fetch is single-action and cannot be further reused, since it modifies the stored config data
+    uint16_t l_pricelist_count = 0;
+    char **l_pricelist = dap_config_get_array_str(g_config, a_config_section, "pricelist", &l_pricelist_count);
+    for (uint16_t i = 0; i < l_pricelist_count; i++) {
+        dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
+        short l_iter = 0;
+        char *l_ctx;
+        for (char *l_price_token = strtok_r(l_pricelist[i], ":", &l_ctx); l_price_token || l_iter == 6; l_price_token = strtok_r(NULL, ":", &l_ctx), ++l_iter) {
+            //log_it(L_DEBUG, "Tokenizer: %s", l_price_token);
+            switch (l_iter) {
+            case 0:
+                l_price->net_name = l_price_token;
+                if (!(l_price->net = dap_chain_net_by_name(l_price->net_name))) {
+                    log_it(L_ERROR, "Error parsing pricelist: can't find network \"%s\"", l_price_token);
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 1:
+                l_price->value_datoshi = dap_chain_uint256_to(dap_chain_coins_to_balance(l_price_token));
+                if (!l_price->value_datoshi) {
+                    log_it(L_ERROR, "Error parsing pricelist: text on 2nd position \"%s\" is not floating number", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 2:
+                dap_stpcpy(l_price->token, l_price_token);
+                continue;
+            case 3:
+                l_price->units = strtoul(l_price_token, NULL, 10);
+                if (!l_price->units) {
+                    log_it(L_ERROR, "Error parsing pricelist: text on 4th position \"%s\" is not unsigned integer", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 4:
+                if (!strcmp(l_price_token,      "SEC"))
+                    l_price->units_uid.enm = SERV_UNIT_SEC;
+                else if (!strcmp(l_price_token, "DAY"))
+                    l_price->units_uid.enm = SERV_UNIT_DAY;
+                else if (!strcmp(l_price_token, "MB"))
+                    l_price->units_uid.enm = SERV_UNIT_MB;
+                else if (!strcmp(l_price_token, "KB"))
+                    l_price->units_uid.enm = SERV_UNIT_KB;
+                else if (!strcmp(l_price_token, "B"))
+                    l_price->units_uid.enm = SERV_UNIT_B;
+                else if (!strcmp(l_price_token, "PCS"))
+                    l_price->units_uid.enm = SERV_UNIT_PCS;
+                else {
+                    log_it(L_ERROR, "Error parsing pricelist: wrong unit type \"%s\"", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 5:
+                if (!(l_price->wallet = dap_chain_wallet_open(l_price_token, dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL)))) {
+                    log_it(L_ERROR, "Error parsing pricelist: can't open wallet \"%s\"", l_price_token);
+                    l_iter = 0;
+                    DAP_DELETE(l_price);
+                    break;
+                }
+                continue;
+            case 6:
+                log_it(L_INFO, "Price item correct, added to service");
+                DL_APPEND(a_srv->pricelist, l_price);
+                ret++;
+                break;
+            default:
+                break;
+            }
+            log_it(L_DEBUG, "Done with price item %d", i);
+            break; // double break exits tokenizer loop and steps to next price item
+        }
+    }
+    return ret;
 }
 
 /**
@@ -646,81 +735,7 @@ dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,
         l_sdata = DAP_NEW_Z(service_list_t);
         memcpy(&l_sdata->uid, &l_uid, sizeof(l_uid));
         l_sdata->srv = l_srv;
-        if (a_config_section) {
-            l_srv->grace_period = dap_config_get_item_uint32_default(g_config, a_config_section, "grace_period", 60);
-            //! IMPORTANT ! This fetch is single-action and cannot be further reused, since it modifies the stored config data
-            uint16_t l_pricelist_count = 0;
-            char **l_pricelist = dap_config_get_array_str(g_config, a_config_section, "pricelist", &l_pricelist_count);
-            for (uint16_t i = 0; i < l_pricelist_count; i++) {
-                dap_chain_net_srv_price_t *l_price = DAP_NEW_Z(dap_chain_net_srv_price_t);
-                short l_iter = 0;
-                char *l_ctx;
-                for (char *l_price_token = strtok_r(l_pricelist[i], ":", &l_ctx); l_price_token || l_iter == 6; l_price_token = strtok_r(NULL, ":", &l_ctx), ++l_iter) {
-                    //log_it(L_DEBUG, "Tokenizer: %s", l_price_token);
-                    switch (l_iter) {
-                    case 0:
-                        l_price->net_name = l_price_token;
-                        if (!(l_price->net = dap_chain_net_by_name(l_price->net_name))) {
-                            log_it(L_ERROR, "Error parsing pricelist: can't find network \"%s\"", l_price_token);
-                            DAP_DELETE(l_price);
-                            break;
-                        }
-                        continue;
-                    case 1:
-                        l_price->value_datoshi = dap_chain_uint256_to(dap_chain_coins_to_balance(l_price_token));
-                        if (!l_price->value_datoshi) {
-                            log_it(L_ERROR, "Error parsing pricelist: text on 2nd position \"%s\" is not floating number", l_price_token);
-                            l_iter = 0;
-                            DAP_DELETE(l_price);
-                            break;
-                        }
-                        continue;
-                    case 2:
-                        dap_stpcpy(l_price->token, l_price_token);
-                        continue;
-                    case 3:
-                        l_price->units = strtoul(l_price_token, NULL, 10);
-                        if (!l_price->units) {
-                            log_it(L_ERROR, "Error parsing pricelist: text on 4th position \"%s\" is not unsigned integer", l_price_token);
-                            l_iter = 0;
-                            DAP_DELETE(l_price);
-                            break;
-                        }
-                        continue;
-                    case 4:
-                        if (!strcmp(l_price_token,      "SEC"))
-                            l_price->units_uid.enm = SERV_UNIT_SEC;
-                        else if (!strcmp(l_price_token, "DAY"))
-                            l_price->units_uid.enm = SERV_UNIT_DAY;
-                        else if (!strcmp(l_price_token, "MB"))
-                            l_price->units_uid.enm = SERV_UNIT_MB;
-                        else {
-                            log_it(L_ERROR, "Error parsing pricelist: wrong unit type \"%s\"", l_price_token);
-                            l_iter = 0;
-                            DAP_DELETE(l_price);
-                            break;
-                        }
-                        continue;
-                    case 5:
-                        if (!(l_price->wallet = dap_chain_wallet_open(l_price_token, dap_config_get_item_str_default(g_config, "resources", "wallets_path", NULL)))) {
-                            log_it(L_ERROR, "Error parsing pricelist: can't open wallet \"%s\"", l_price_token);
-                            l_iter = 0;
-                            DAP_DELETE(l_price);
-                            break;
-                        }
-                        continue;
-                    case 6:
-                        log_it(L_INFO, "Price item correct, added to service");
-                        DL_APPEND(l_srv->pricelist, l_price);
-                        break;
-                    default:
-                        break;
-                    }
-                    log_it(L_DEBUG, "Done with price item %d", i);
-                    break; // double break exits tokenizer loop and steps to next price item
-                }
-            }
-        }
+        dap_chain_net_srv_parse_pricelist(l_srv, a_config_section);
         HASH_ADD(hh, s_srv_list, uid, sizeof(l_srv->uid), l_sdata);
     }else{
         log_it(L_ERROR, "Already present service with 0x%016"DAP_UINT64_FORMAT_X, a_uid.uint64);
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 79ddfab3f4..87ae6a8458 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -346,10 +346,14 @@ char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_ord
     return l_order_hash_str;
 }
 
-dap_chain_net_srv_order_t *dap_chain_net_srv_order_read(byte_t *a_order)
+dap_chain_net_srv_order_t *dap_chain_net_srv_order_read(byte_t *a_order, size_t a_order_size)
 {
-    if (((dap_chain_net_srv_order_t *)a_order)->version == 3)
-        return DAP_DUP_SIZE(a_order, dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)a_order));
+    dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)a_order;
+    size_t l_order_size = dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)a_order);
+    if (l_order->version > 3 || l_order->direction > SERV_DIR_SELL || l_order_size != a_order_size)
+        return NULL;
+    if (l_order->version == 3)
+        return DAP_DUP_SIZE(a_order, l_order_size);
     dap_chain_net_srv_order_old_t *l_old = (dap_chain_net_srv_order_old_t *)a_order;
     size_t l_ret_size = dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)l_old) +
                             sizeof(dap_chain_net_srv_order_t) - sizeof(dap_chain_net_srv_order_old_t);
@@ -437,10 +441,8 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_
     size_t l_orders_size = 0;
     for (size_t i = 0; i < l_orders_count; i++) {
         DAP_DEL_Z(l_order);
-        l_order = dap_chain_net_srv_order_read(l_orders[i].value);
-        size_t l_order_size = dap_chain_net_srv_order_get_size((dap_chain_net_srv_order_t *)l_orders[i].value);
-        if (l_order->version > 3 || l_order->direction > SERV_DIR_SELL ||
-                l_order_size != l_orders[i].value_len) {
+        l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len);
+        if (!l_order) {
             dap_chain_global_db_gr_del(l_orders[i].key, l_gdb_group_str);
             continue; // order is corrupted
         }
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index 4c9dc61140..ecbc6070ef 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -285,6 +285,7 @@ dap_chain_datum_tx_receipt_t * dap_chain_net_srv_issue_receipt(dap_chain_net_srv
                                                                dap_chain_net_srv_price_t * a_price,
                                                                const void * a_ext, size_t a_ext_size);
 uint8_t dap_stream_ch_chain_net_srv_get_id();
+int dap_chain_net_srv_parse_pricelist(dap_chain_net_srv_t *a_srv, const char *a_config_section);
 
 DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chain_net_srv_price_unit_uid_t a_uid )
 {
@@ -294,6 +295,16 @@ DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chai
         case SERV_UNIT_MB: return "MEGABYTE";
         case SERV_UNIT_SEC: return "SECOND";
         case SERV_UNIT_DAY: return  "DAY";
+        case SERV_UNIT_PCS: return "PIECES";
         default: return "UNKNOWN";
     }
 }
+
+DAP_STATIC_INLINE dap_chain_net_srv_uid_compare(dap_chain_net_srv_uid_t a, dap_chain_net_srv_uid_t b)
+{
+#if DAP_CHAIN_NET_SRV_UID_SIZE == 8
+    return a.uint64 == b.uint64;
+#else // DAP_CHAIN_NET_SRV_UID_SIZE == 16
+    return !memcmp(&a, &b, DAP_CHAIN_NET_SRV_UID_SIZE);
+#endif
+}
diff --git a/modules/service/datum/dap_chain_net_srv_datum.c b/modules/service/datum/dap_chain_net_srv_datum.c
index 22298f28a1..9b209bec77 100644
--- a/modules/service/datum/dap_chain_net_srv_datum.c
+++ b/modules/service/datum/dap_chain_net_srv_datum.c
@@ -33,6 +33,7 @@
 
 #define LOG_TAG "chain_net_srv_datum"
 
+static dap_chain_net_srv *s_srv_datum = NULL;
 static int s_srv_datum_cli(int argc, char ** argv, char **a_str_reply);
 
 void s_order_notficator(void *a_arg, const char a_op_code, const char *a_group, const char *a_key, const void *a_value, const size_t a_value_len);
@@ -44,10 +45,12 @@ int dap_chain_net_srv_datum_init()
             "\tSaving datum from mempool to file.\n\n"
         "srv_datum -net <chain net name> -chain <chain name> datum load -datum <datum hash>\n"
             "\tLoad datum custum from file to mempool.\n\n");
-    uint16_t l_net_arr_len = 0;
-    char **l_net_arr_str = dap_config_get_array_str(g_config, "srv_datum", "networks", &l_net_arr_len);
-    for (int i = 0; i < l_net_arr_len; i++) {
-        dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_arr_str[i]);
+    s_srv_datum = DAP_NEW_Z(dap_chain_net_srv_t);
+    s_srv_datum->uid.uint64 = DAP_CHAIN_NET_SRV_DATUM_ID;
+    int l_net_count = dap_chain_net_srv_parse_pricelist(s_srv_datum, "srv_datum");
+    dap_chain_net_srv_price_t *l_price;
+    DL_FOREACH(s_srv_datum->pricelist, l_price) {
+        dap_chain_net_t *l_net = l_price->net;
         if (!l_net)
             continue;
         dap_chain_net_srv_order_add_notify_callback(l_net, s_order_notficator, l_net);
@@ -181,12 +184,37 @@ static int s_srv_datum_cli(int argc, char ** argv, char **a_str_reply) {
 
 void s_order_notficator(void *a_arg, const char a_op_code, const char *a_group, const char *a_key, const void *a_value, const size_t a_value_len)
 {
+    if (a_op_code == DAP_DB$K_OPTYPE_DEL)
+        return;
     dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
-    dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)a_value;
+    dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_read(a_value);    // Old format comliance
+    if (!l_order) {
+        dap_chain_global_db_gr_del(a_key, a_group);
+        return; // order is corrupted
+    }
+    if (!dap_chain_net_srv_uid_compare(l_order->srv_uid, s_srv_datum->uid))
+        return; // order from another service
+    dap_chain_net_srv_price_t *l_price = NULL;
+    DL_FOREACH(s_srv_datum->pricelist, l_price) {
+        if (l_price->net == l_net)
+            break;
+    }
+    if (!l_price || l_price->net != l_net) {
+        log_it(L_DEBUG, "Price for net %s is not set", l_net->pub.name);
+        return; // price not set for this network
+    }
+    if ((l_order->price_unit != SERV_UNIT_PCS) || (l_order->direction != SERV_DIR_BUY) ||
+            (strncmp(l_order->price_ticker, l_price->token, DAP_CHAIN_TICKER_SIZE_MAX)) ||
+            (!compare256(l_order->price, l_price->value_datoshi))) {
+        log_it(L_DEBUG, "Price from order (%s) is not equal to price from service pricelist (%s)",
+               dap_chain_balance_to_coins(l_order->price), dap_chain_balance_to_coins(l_price->value_datoshi));
+        return; // price from order is not equal with service price
+    }
     char l_tx_cond_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
     dap_chain_hash_fast_to_str(&l_order->tx_cond_hash, l_tx_cond_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
     dap_chain_t *l_chain;
     dap_chain_datum_t *l_datum = NULL;
+    dap_chain_datum_tx_t *l_tx_cond = NULL;
     DL_FOREACH(l_net->pub.chains, l_chain) {
         size_t l_datum_size;
         char *l_gdb_group = dap_chain_net_get_gdb_group_mempool(l_chain);
@@ -194,8 +222,23 @@ void s_order_notficator(void *a_arg, const char a_op_code, const char *a_group,
         if (l_datum)
             break;
     }
-    if (!l_datum) {
-        log_it(L_DEBUG, "Invalid tx cond hash");
+    if (l_datum)
+        l_tx_cond = (dap_chain_datum_tx_t *)l_datum->data;
+    else
+        l_tx_cond = dap_chain_ledger_tx_find_by_hash(l_net->pub.ledger, &l_order->tx_cond_hash);
+    if (!l_tx_cond) {
+        log_it(L_DEBUG, "Invalid tx cond datum hash");
+        return;
+    }
+    dap_chain_tx_out_cond_t *l_cond_out = (dap_chain_tx_out_cond_t *)
+            dap_chain_datum_tx_item_get(l_tx_cond, NULL, TX_ITEM_TYPE_OUT_COND, &l_tx_out_cond_size);
+    if (!l_cond_out || l_cond_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY) {
+        log_it(L_DEBUG, "Condition with required subtype SRV_PAY not found in requested tx");
+    }
+    dap_hash_fast_t l_sign_hash;
+    if (!dap_sign_get_pkey_hash(l_order->ext_n_sign[l_order->ext_size], &l_sign_hash)) {
+         log_it(L_DEBUG, "Wrong order sign");
+         return;
     }
 }
 
-- 
GitLab