From 2f4cce67c9f8d53dc7e979f32ea761403e8dd6ba Mon Sep 17 00:00:00 2001
From: "Dmitriy A. Gerasimov" <dmitriy.gerasimov@demlabs.net>
Date: Fri, 25 Oct 2019 18:21:24 +0700
Subject: [PATCH] [+] Create, dump, list and delete operations for service
 order [+] Timestamp fields added

---
 dap_chain_net_srv.c        | 97 ++++++++++++++++++++++++++++++++++----
 dap_chain_net_srv_common.h | 23 +++++++--
 dap_chain_net_srv_order.c  | 56 +++++++++++++++++-----
 dap_chain_net_srv_order.h  | 17 ++++++-
 4 files changed, 167 insertions(+), 26 deletions(-)

diff --git a/dap_chain_net_srv.c b/dap_chain_net_srv.c
index 0e123c1..5012e43 100755
--- a/dap_chain_net_srv.c
+++ b/dap_chain_net_srv.c
@@ -83,10 +83,13 @@ int dap_chain_net_srv_init(void)
         return -1;
 
     dap_chain_node_cli_cmd_item_create ("net_srv", s_cli_net_srv, "Network services managment",
-        "net_srv -net <chain net name> order list [-srv_uid <Service UID>] [-srv_class <Service Class>]\n"
+        "net_srv -net <chain net name> order find [-srv_uid <Service UID>] [-srv_class <Service Class>] [-price_unit <price unit>]\\\n"
+        "                                         [-price_min <Price minimum>] [-price_max <Price maximum>]\n"
         "\tOrders list, all or by UID and/or class\n"
-        "net_srv -net <chain net name> order delete -id <Proposal ID>\n"
+        "net_srv -net <chain net name> order delete -hash <Order hash>\n"
         "\tOrder delete\n"
+        "net_srv -net <chain net name> order dump -hash <Order hash>\n"
+        "\tOrder dump info\n"
         "net_srv -net <chain net name> order create -srv_uid <Service UID> -srv_class <Service Class> -price <Price>\\\n"
         "        -price_unit <Price Unit> -node_addr <Node Address> -tx_cond <TX Cond Hash> \\\n"
         "        [-expires <Unix time when expires>]\\\n"
@@ -125,8 +128,7 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
         dap_string_t *l_string_ret = dap_string_new("");
         const char *l_order_str = NULL;
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "order", &l_order_str);
-        if ( strcmp( l_order_str, "list" ) == 0 ){
-            dap_string_append(l_string_ret,"Orders:\n");
+        if ( strcmp( l_order_str, "find" ) == 0 ){
 
             // Select with specified service uid
             const char *l_srv_uid_str = NULL;
@@ -135,7 +137,77 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
             // Select with specified service class
             const char *l_srv_class_str = NULL;
             dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-srv_class", &l_srv_class_str);
-        } else if( strcmp( l_order_str, "create" ) == 0 ){
+
+            // Select with specified price units
+            const char*  l_price_unit_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-price_unit", &l_price_unit_str);
+
+            // Select with price not more than price_min
+            const char*  l_price_min_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-price_min", &l_price_min_str);
+
+            // Select with price not more than price_max
+            const char*  l_price_max_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-price_max", &l_price_max_str);
+
+            dap_chain_net_srv_uid_t l_srv_uid={{0}};
+            dap_chain_net_srv_class_t l_srv_class= SERV_CLASS_UNDEFINED;
+            uint64_t l_price_min=0, l_price_max =0 ;
+            dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
+
+            l_srv_uid.uint64 = (uint128_t) atoll( l_srv_uid_str);
+            l_srv_class = (dap_chain_net_srv_class_t) atoi( l_srv_class_str );
+            l_price_min = (uint64_t) atoll ( l_price_min_str );
+            l_price_max = (uint64_t) atoll ( l_price_max_str );
+            l_price_unit.uint32 = (uint32_t) atol ( l_price_unit_str );
+            dap_chain_net_srv_order_t * l_orders;
+            size_t l_orders_size =0;
+            if( dap_chain_net_srv_order_find_all_by( l_net,l_srv_uid,l_srv_class,l_price_unit,l_price_min, l_price_max,&l_orders,&l_orders_size) == 0 ){
+                dap_string_append_printf(l_string_ret,"Found %u orders:\n",l_orders_size);
+                for (size_t i = 0; i< l_orders_size; i++){
+                    dap_chain_net_srv_order_dump_to_string(l_orders+i,l_string_ret);
+                    dap_string_append(l_string_ret,"\n");
+                }
+                ret = 0;
+            }else{
+                ret = -5 ;
+                dap_string_append(l_string_ret,"Can't get orders: some internal error or wrong params\n");
+            }
+
+        }else if( strcmp( l_order_str, "dump" ) == 0 ){
+            // Select with specified service uid
+            const char *l_order_hash_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-hash", &l_order_hash_str);
+            if ( l_order_hash_str ){
+                dap_chain_net_srv_order_t * l_order = dap_chain_net_srv_order_find_by_hash( l_net, l_order_hash_str );
+                if (l_order){
+                    dap_chain_net_srv_order_dump_to_string(l_order,l_string_ret);
+                    ret = 0;
+                }else{
+                    ret = -7 ;
+                    dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_str );
+                }
+            } else{
+                ret = -6 ;
+                dap_string_append(l_string_ret,"need -hash param to obtain what the order we need to dump\n");
+            }
+        }else if( strcmp( l_order_str, "delete" ) == 0 ){
+            // Select with specified service uid
+            const char *l_order_hash_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-hash", &l_order_hash_str);
+            if ( l_order_hash_str ){
+                if (dap_chain_net_srv_order_delete_by_hash_str(l_net,l_order_hash_str) == 0){
+                    ret = 0 ;
+                    dap_string_append_printf(l_string_ret,"Deleted order %s\n", l_order_hash_str );
+                }else{
+                    ret = -8 ;
+                    dap_string_append_printf(l_string_ret,"Can't find order with hash %s\n", l_order_hash_str );
+                }
+            } else{
+                ret = -9 ;
+                dap_string_append(l_string_ret,"need -hash param to obtain what the order we need to dump\n");
+            }
+        }else if( strcmp( l_order_str, "create" ) == 0 ){
             const char* l_srv_uid_str = NULL;
             dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-srv_uid", &l_srv_uid_str);
 
@@ -151,6 +223,9 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
             const char*  l_price_str = NULL;
             dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-price", &l_price_str);
 
+            const char*  l_expires_str = NULL;
+            dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-expires", &l_expires_str);
+
             const char*  l_price_unit_str = NULL;
             dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-price_unit", &l_price_unit_str);
 
@@ -162,18 +237,20 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
                 dap_chain_net_srv_class_t l_srv_class= SERV_CLASS_UNDEFINED;
                 dap_chain_node_addr_t l_node_addr={0};
                 dap_chain_hash_fast_t l_tx_cond_hash={{0}};
-                uint128_t l_price=0;
+                dap_chain_time_t l_expires=0; // TS when the service expires
+                uint64_t l_price=0;
                 dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
-
-                l_srv_uid.uint128 = (uint128_t) atoll( l_srv_uid_str);
+                if (l_expires_str)
+                    l_expires = (dap_chain_time_t ) atoll( l_expires_str);
+                l_srv_uid.uint64 = (uint64_t) atoll( l_srv_uid_str);
                 l_srv_class = (dap_chain_net_srv_class_t) atoi( l_srv_class_str );
                 dap_chain_node_addr_from_str( &l_node_addr, l_node_addr_str );
                 dap_chain_str_to_hash_fast (l_tx_cond_hash_str, &l_tx_cond_hash);
-                l_price = (uint128_t) atoll ( l_price_str );
+                l_price = (uint64_t) atoll ( l_price_str );
                 l_price_unit.uint32 = (uint32_t) atol ( l_price_unit_str );
 
                 char * l_order_new_hash_str = dap_chain_net_srv_order_create (
-                            l_net, l_srv_uid, l_srv_class, l_node_addr,l_tx_cond_hash, l_price, l_price_unit, l_comments);
+                            l_net, l_srv_uid, l_srv_class, l_node_addr,l_tx_cond_hash, l_price, l_price_unit, l_expires,l_comments);
                 if (l_order_new_hash_str)
                     dap_string_append_printf( l_string_ret, "Created order %s\n", l_order_new_hash_str);
                 else{
diff --git a/dap_chain_net_srv_common.h b/dap_chain_net_srv_common.h
index 3b64cb9..c2b467a 100755
--- a/dap_chain_net_srv_common.h
+++ b/dap_chain_net_srv_common.h
@@ -31,18 +31,23 @@
 #include "dap_stream_ch.h"
 #include "dap_chain_ledger.h"
 
-#define DAP_CHAIN_NET_SRV_UID_SIZE 16
+#define DAP_CHAIN_NET_SRV_UID_SIZE 8
+
 typedef union {
     uint8_t raw[DAP_CHAIN_NET_SRV_UID_SIZE];
-    #if DAP_CHAIN_NET_SRV_UID_SIZE == 8
+#if DAP_CHAIN_NET_SRV_UID_SIZE == 8
     uint64_t raw_ui64[1];
+    uint64_t uint64;
 #elif DAP_CHAIN_NET_SRV_UID_SIZE == 16
-    uint64_t raw_ui64[2];
-    dap_uint128_t raw_ui128[1];
+    uint64_t raw_ui64[1];
     uint128_t uint128;
 #endif
 } dap_chain_net_srv_uid_t;
 
+#define DAP_CHAIN_NET_SRV_PRICE_UNIT_BYTE                             0x00000001
+#define DAP_CHAIN_NET_SRV_PRICE_UNIT_SECOND                           0x00000010
+#define DAP_CHAIN_NET_SRV_PRICE_UNIT_BYTE_PER_SECOND                  0x00000100
+
 typedef union {
     uint8_t raw[4];
     uint32_t raw_ui32[1];
@@ -102,6 +107,16 @@ typedef struct dap_chain_net_srv
     //void * _inhertor;
 } dap_chain_net_srv_t;
 
+DAP_STATIC_INLINE const char * dap_chain_net_srv_price_unit_uid_to_str( dap_chain_net_srv_price_unit_uid_t a_uid )
+{
+    switch ( a_uid.uint32 ) {
+        case DAP_CHAIN_NET_SRV_PRICE_UNIT_BYTE: return "BYTE";
+        case DAP_CHAIN_NET_SRV_PRICE_UNIT_SECOND: return "SECOND";
+        case DAP_CHAIN_NET_SRV_PRICE_UNIT_BYTE_PER_SECOND: return  "BYTE_PER_SECOND";
+        default: return "UNKNOWN";
+    }
+}
+
 // Initialize dap_chain_net_srv_abstract_t structure
 void dap_chain_net_srv_abstract_set(dap_chain_net_srv_abstract_t *a_cond, uint8_t a_class, uint128_t a_type_id,
         uint64_t a_price, uint8_t a_price_units, const char *a_decription);
diff --git a/dap_chain_net_srv_order.c b/dap_chain_net_srv_order.c
index acfb73a..282b3da 100644
--- a/dap_chain_net_srv_order.c
+++ b/dap_chain_net_srv_order.c
@@ -56,6 +56,7 @@ char* dap_chain_net_srv_order_create(
         dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
         uint64_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
+        dap_chain_time_t a_expires, // TS when the service expires
         const char * a_comments
         )
 {
@@ -64,6 +65,7 @@ char* dap_chain_net_srv_order_create(
         dap_chain_hash_fast_t* l_order_hash = DAP_NEW_Z(dap_chain_hash_fast_t);
         l_order->version = 1;
         l_order->srv_uid = a_srv_uid;
+        l_order->ts_created = (dap_chain_time_t) time(NULL);
         l_order->srv_class = a_srv_class;
         l_order->node_addr.uint64 = a_node_addr.uint64;
         memcpy(&l_order->tx_cond_hash, &a_tx_cond_hash, DAP_CHAIN_HASH_FAST_SIZE);
@@ -92,27 +94,24 @@ char* dap_chain_net_srv_order_create(
 }
 
 /**
- * @brief dap_chain_net_srv_order_find_by_hash
+ * @brief dap_chain_net_srv_order_find_by_hash_str
  * @param a_net
- * @param a_hash
+ * @param a_hash_str
  * @return
  */
-dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_hash)
+dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash_str(dap_chain_net_t * a_net, const char * a_hash_str)
 {
     dap_chain_net_srv_order_t * l_order = NULL;
-    if ( a_net && a_hash ){
-        char * l_order_hash_str = dap_chain_hash_fast_to_str_new(a_hash );
+    if ( a_net && a_hash_str ){
         char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net);
         size_t l_order_size =0;
-        l_order = (dap_chain_net_srv_order_t *) dap_chain_global_db_gr_get(l_order_hash_str, &l_order_size, l_gdb_group_str );
+        l_order = (dap_chain_net_srv_order_t *) dap_chain_global_db_gr_get(a_hash_str, &l_order_size, l_gdb_group_str );
         if (l_order_size != sizeof (dap_chain_net_srv_order_t) ){
             log_it( L_ERROR, "Found wrong size order");
             DAP_DELETE( l_order );
-            DAP_DELETE( l_order_hash_str );
             DAP_DELETE( l_gdb_group_str );
             return NULL;
         }
-        DAP_DELETE( l_order_hash_str );
         DAP_DELETE( l_gdb_group_str );
     }
     return l_order;
@@ -131,11 +130,11 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net, dap_chain_net_s
         size_t l_order_passed_index;
 lb_order_pass:
         l_order_passed_index =0;
-        for (int i; i< l_orders_count; i++){
+        for (size_t i; i< l_orders_count; i++){
             dap_chain_net_srv_order_t * l_order = (dap_chain_net_srv_order_t *) l_orders[i].value;
             // Check srv uid
-            if ( a_srv_uid.uint128)
-                if ( l_order->srv_uid.uint128 != a_srv_uid.uint128 )
+            if ( a_srv_uid.uint64)
+                if ( l_order->srv_uid.uint64 != a_srv_uid.uint64 )
                     continue;
             // Check srv class
             if ( a_srv_class != SERV_CLASS_UNDEFINED )
@@ -191,3 +190,38 @@ int dap_chain_net_srv_order_delete_by_hash_str(dap_chain_net_t * a_net, const ch
     return ret;
 }
 
+/**
+ * @brief dap_chain_net_srv_order_dump_to_string
+ * @param a_orders
+ * @param a_str_out
+ */
+void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,dap_string_t * a_str_out)
+{
+    if (a_order && a_str_out ){
+        dap_chain_hash_fast_t l_hash;
+        char l_hash_str[DAP_CHAIN_HASH_FAST_SIZE * 2 + 4];
+        dap_hash_fast(a_order,sizeof (*a_order),&l_hash );
+        dap_chain_hash_fast_to_str(&l_hash,l_hash_str,sizeof(l_hash_str)-1);
+        dap_string_append_printf(a_str_out, "== Order %s ==\n", l_hash_str);
+        dap_string_append_printf(a_str_out, "  version:          %u\n", a_order->version );
+
+        switch ( a_order->srv_class) {
+            case SERV_CLASS_ONCE: dap_string_append_printf(a_str_out, "  srv_class:        SERV_CLASS_ONCE\n" ); break;;
+            case SERV_CLASS_PERMANENT: dap_string_append_printf(a_str_out, "  srv_class:        SERV_CLASS_PERMANENT\n" ); break;
+            case SERV_CLASS_UNDEFINED: dap_string_append_printf(a_str_out, "  srv_class:        SERV_CLASS_UNDEFINED\n" ); break;
+            //default: dap_string_append_printf(a_str_out, "  srv_class:        UNKNOWN\n" );
+        }
+        dap_string_append_printf(a_str_out, "  srv_uid:          0x%016llX\n", a_order->srv_uid.uint64 );
+        dap_string_append_printf(a_str_out, "  price:            \u00a0%.3Lf (%llu)\n", dap_chain_balance_to_coins(a_order->price) , a_order->price);
+        if( a_order->price_unit.uint32 )
+            dap_string_append_printf(a_str_out, "  price_unit:       0x%016llX\n", dap_chain_net_srv_price_unit_uid_to_str(a_order->price_unit) );
+        if ( a_order->node_addr.uint64)
+            dap_string_append_printf(a_str_out, "  node_addr:        "NODE_ADDR_FP_STR"\n", NODE_ADDR_FP_ARGS_S(a_order->node_addr) );
+
+        dap_chain_hash_fast_to_str(&a_order->tx_cond_hash,l_hash_str,sizeof(l_hash_str)-1);
+        dap_string_append_printf(a_str_out, "  tx_cond_hash:          %s\n", l_hash_str );
+
+        if( a_order->comments[0])
+            dap_string_append_printf(a_str_out, "  comments:          \"%s\"\n", a_order->comments );
+    }
+}
diff --git a/dap_chain_net_srv_order.h b/dap_chain_net_srv_order.h
index e5daf3c..5e870fd 100644
--- a/dap_chain_net_srv_order.h
+++ b/dap_chain_net_srv_order.h
@@ -24,6 +24,7 @@ along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
 
 #pragma once
 #include "dap_common.h"
+#include "dap_string.h"
 #include "dap_chain_net.h"
 #include "dap_chain_net_srv_common.h"
 
@@ -36,6 +37,8 @@ typedef struct dap_chain_net_srv_order
     dap_chain_hash_fast_t tx_cond_hash; // Hash index of conditioned transaction attached with order
     uint64_t price; //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
     dap_chain_net_srv_price_unit_uid_t price_unit; // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
+    dap_chain_time_t ts_created;
+    dap_chain_time_t ts_expires;
     char comments[128];
 } dap_chain_net_srv_order_t;
 
@@ -43,7 +46,17 @@ typedef struct dap_chain_net_srv_order
 int dap_chain_net_srv_order_init(void);
 void dap_chain_net_srv_order_deinit(void);
 
-dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_hash);
+dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash_str(dap_chain_net_t * a_net, const char * a_hash_str);
+
+DAP_STATIC_INLINE dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_hash)
+{
+    if ( a_net && a_hash ){
+        char l_hash_str[DAP_CHAIN_HASH_FAST_SIZE * 2 + 4];
+        dap_chain_hash_fast_to_str(a_hash,l_hash_str,sizeof(l_hash_str)-1);
+        return  dap_chain_net_srv_order_find_by_hash_str(a_net, l_hash_str );
+    }
+}
+
 int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,dap_chain_net_srv_uid_t a_srv_uid, dap_chain_net_srv_class_t a_srv_class,
                                         dap_chain_net_srv_price_unit_uid_t a_price_unit, uint64_t a_price_min, uint64_t a_price_max,
                                         dap_chain_net_srv_order_t ** a_output_orders, size_t * a_output_orders_count);
@@ -70,9 +83,11 @@ char* dap_chain_net_srv_order_create(
         dap_chain_hash_fast_t a_tx_cond_hash, // Hash index of conditioned transaction attached with order
         uint64_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
+        dap_chain_time_t a_expires, // TS when the service expires
         const char * a_comments
         );
 
+void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,dap_string_t * a_str_out);
 
 /**
 * @brief dap_chain_net_srv_order_get_gdb_group_mempool
-- 
GitLab