From 6bc0c6884bb40e58718695c2fda80f6c49b55ec0 Mon Sep 17 00:00:00 2001
From: "daniil.frolov" <daniil.frolov@demlabs.net>
Date: Sun, 2 Mar 2025 17:44:21 +0300
Subject: [PATCH] ..

---
 .../dap_stream_ch_chain_net_srv.c             | 180 ++++++++----------
 modules/service/vpn/dap_chain_net_srv_vpn.c   |   4 +-
 2 files changed, 83 insertions(+), 101 deletions(-)

diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index d1afa64200..1a1083c723 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -101,7 +101,6 @@ static bool s_unban_client(dap_chain_net_srv_banlist_item_t *a_item);
 static int s_pay_service(dap_chain_net_srv_usage_t *a_usage, dap_chain_datum_tx_receipt_t *a_receipt);
 
 static bool s_service_start(dap_stream_ch_t *a_ch , dap_stream_ch_chain_net_srv_pkt_request_t *a_request, size_t a_request_size);
-static bool s_grace_period_start(dap_chain_net_srv_grace_t *a_grace);
 static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace);
 static void s_set_usage_data_to_gdb(const dap_chain_net_srv_usage_t *a_usage);
 static uint256_t s_calc_datoshi(const dap_chain_net_srv_usage_t *a_usage, uint256_t *a_prev);
@@ -466,72 +465,27 @@ static bool s_service_start(dap_stream_ch_t *a_ch , dap_stream_ch_chain_net_srv_
 
         l_usage->static_order_hash = a_request->hdr.order_hash;
 
-
-        // check remain limits
-        dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL;
-        l_remain_service = l_usage->service->callbacks.get_remain_service(l_usage->service, l_usage->id, l_usage->client);
-        if (l_remain_service && ((l_remain_service->limits_ts &&  l_usage->price->units_uid.enm == SERV_UNIT_SEC)  || 
-            (l_remain_service->limits_bytes && l_usage->price->units_uid.enm == SERV_UNIT_B))){
-
-            //Start with remain service
-            dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) l_usage->client->ch->stream->session->_inheritor;
-            switch(l_usage->price->units_uid.enm){
-                case SERV_UNIT_SEC:
-                    l_srv_session->limits_ts = l_remain_service->limits_ts;
-                    break;
-                case SERV_UNIT_B:
-                    l_srv_session->limits_bytes = l_remain_service->limits_bytes;
-                    break;
-            }
-            log_it(L_INFO, "User %s has %ld %s remain service. Start service without paying.", dap_chain_hash_fast_to_str_static(&l_usage->client_pkey_hash), 
-                            l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, 
-                            dap_chain_srv_unit_enum_to_str(l_usage->price->units_uid.enm));
-            size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t );
-            dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t,
-                                                                                    l_success_size);
-            if(!l_success) {
-                log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
-                l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_ALLOC_MEMORY_ERROR;
+        dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_usage->tx_cond_hash);
+        // Check tx
+        if (!l_tx){
+            // Start grace
+            dap_chain_net_srv_banlist_item_t *l_item = NULL;
+            pthread_mutex_lock(&l_srv->banlist_mutex);
+            HASH_FIND(hh, l_srv->ban_list, &l_usage->client_pkey_hash, sizeof(dap_chain_hash_fast_t), l_item);
+            pthread_mutex_unlock(&l_srv->banlist_mutex);
+            if (l_item) {   // client banned
+                log_it(L_DEBUG, "Client %s is banned!", dap_chain_hash_fast_to_str_static(&l_usage->client_pkey_hash));
+                l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_BANNED_PKEY_HASH;
                 if(a_ch)
                     dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
                 if (l_usage->service && l_usage->service->callbacks.response_error)
-                l_usage->service->callbacks.response_error(l_usage->service, 0, NULL, &l_err, sizeof(l_err));
-        
-                // TODO go to state error
+                    l_usage->service->callbacks.response_error(l_usage->service, 0, NULL, &l_err, sizeof(l_err));
                 return false;
-            } else {
-                l_success->hdr.usage_id = l_usage->id;
-                l_success->hdr.net_id.uint64 = l_usage->net->pub.id.uint64;
-                l_success->hdr.srv_uid.uint64 = l_usage->service->uid.uint64;
-                dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS, l_success, l_success_size);
-                DAP_DELETE(l_success);
-                // create and fill first receipt
-                l_usage->receipt = dap_chain_datum_tx_receipt_create(l_usage->service->uid, l_price->units_uid, l_price->units, l_price->value_datoshi, NULL, 0);
-                s_service_state_go_to_normal(l_usage);               
-            }                        
-        } else {
-            // Check tx
-            dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_usage->tx_cond_hash);
-            if (!l_tx){
-                // Start grace
-                dap_chain_net_srv_banlist_item_t *l_item = NULL;
-                pthread_mutex_lock(&l_srv->banlist_mutex);
-                HASH_FIND(hh, l_srv->ban_list, &l_usage->client_pkey_hash, sizeof(dap_chain_hash_fast_t), l_item);
-                pthread_mutex_unlock(&l_srv->banlist_mutex);
-                if (l_item) {   // client banned
-                    log_it(L_DEBUG, "Client %s is banned!", dap_chain_hash_fast_to_str_static(&l_usage->client_pkey_hash));
-                    l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_RECEIPT_BANNED_PKEY_HASH;
-                    if(a_ch)
-                        dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof (l_err));
-                    if (l_usage->service && l_usage->service->callbacks.response_error)
-                        l_usage->service->callbacks.response_error(l_usage->service, 0, NULL, &l_err, sizeof(l_err));
-                    return false;
-                }
-                s_service_state_go_to_grace(l_usage);
-            } else {
-                l_usage->tx_cond = l_tx;
-                s_service_substate_pay_service(l_usage);
             }
+            s_service_state_go_to_grace(l_usage);
+        } else {
+            l_usage->tx_cond = l_tx;
+            s_service_substate_pay_service(l_usage);
         }
     } else if (l_specific_order_free && l_srv->allow_free_srv){
         // Start service for free
@@ -909,22 +863,6 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg)
         dap_stream_ch_pkt_write_unsafe( a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS,
                                        l_success, l_success_size);
 
-        if ( l_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN && 
-                l_usage->service->callbacks.response_success){
-            if( l_usage->service->callbacks.response_success(l_usage->service,l_usage->id,  l_usage->client,
-                                                        l_receipt, l_receipt_size ) !=0 ){
-                log_it(L_NOTICE, "No success by service success callback, inactivating service usage");
-                l_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_REQUEST_INTERNAL_ERROR;
-                s_service_substate_go_to_error(l_usage);
-            }
-        } else if (l_usage->service->callbacks.receipt_next_success) {
-            if (l_usage->service->callbacks.receipt_next_success(l_usage->service, l_usage->id, l_usage->client,
-                                                        l_receipt, l_receipt_size ) != 0 ){
-                log_it(L_NOTICE, "No success by service receipt_next callback, inactivating service usage");
-                l_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_REQUEST_INTERNAL_ERROR;
-                s_service_substate_go_to_error(l_usage);
-            }
-        }
     } break;
 
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA: {
@@ -1006,6 +944,7 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg)
                 break;
             }
 
+            l_usage->tx_cond_hash = l_responce->hdr.tx_cond;
             s_service_substate_pay_service(l_usage);
             
             size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t );
@@ -1107,6 +1046,17 @@ static void s_service_state_go_to_grace(dap_chain_net_srv_usage_t *a_usage)
 
     assert(a_usage->service_state == DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_IDLE);
 
+    a_usage->service_state = DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_GRACE;
+    if (a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_IDLE){
+        s_service_substate_go_to_waiting_prev_tx(a_usage);
+    } else if(a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN){
+        s_service_substate_go_to_waiting_new_tx(a_usage);
+    } else {
+        log_it(L_ERROR, "Wrong substate to start grace");
+        a_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_REQUEST_INTERNAL_ERROR;
+        s_service_substate_go_to_error(a_usage);
+    }
+
     if (a_usage->service->callbacks.response_success){
         if( a_usage->service->callbacks.response_success(a_usage->service,a_usage->id,  a_usage->client,
                         NULL, 0) !=0 ){
@@ -1120,17 +1070,6 @@ static void s_service_state_go_to_grace(dap_chain_net_srv_usage_t *a_usage)
         s_service_substate_go_to_error(a_usage);
         return;
     }
-
-    a_usage->service_state = DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_GRACE;
-    if (a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_IDLE){
-        s_service_substate_go_to_waiting_prev_tx(a_usage);
-    } else if(a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN){
-        s_service_substate_go_to_waiting_new_tx(a_usage);
-    } else {
-        log_it(L_ERROR, "Wrong substate to start grace");
-        a_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_SERVICE_REQUEST_INTERNAL_ERROR;
-        s_service_substate_go_to_error(a_usage);
-    }
 }
 
 static void s_service_state_go_to_normal(dap_chain_net_srv_usage_t *a_usage)
@@ -1139,7 +1078,8 @@ static void s_service_state_go_to_normal(dap_chain_net_srv_usage_t *a_usage)
         return;
 
     if (a_usage->service_state == DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_IDLE &&
-        (a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_IDLE)){
+        (a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_IDLE ||
+         a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN)){
         // start with remain limits
         if (a_usage->service->callbacks.response_success){
             if( a_usage->service->callbacks.response_success(a_usage->service,a_usage->id,  a_usage->client,
@@ -1305,14 +1245,51 @@ static void s_service_substate_pay_service(dap_chain_net_srv_usage_t *a_usage)
         (a_usage->service_state == DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_GRACE && 
         a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_TX_FOR_PAYING)
     ) {
-        a_usage->receipt = dap_chain_net_srv_issue_receipt(a_usage->service, a_usage->price, NULL, 0);
-        dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST,
-            a_usage->receipt, a_usage->receipt->size);
-              
-        a_usage->service_substate = DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN;
-
-        //start timeout timer
-        a_usage->receipt_timeout_timer_start_callback(a_usage);
+        dap_stream_ch_chain_net_srv_remain_service_store_t* l_remain_service = NULL;
+        l_remain_service = a_usage->service->callbacks.get_remain_service(a_usage->service, a_usage->id, a_usage->client);
+        if (l_remain_service && ((l_remain_service->limits_ts &&  a_usage->price->units_uid.enm == SERV_UNIT_SEC)  || 
+            (l_remain_service->limits_bytes && a_usage->price->units_uid.enm == SERV_UNIT_B))){
+
+            //Start with remain service
+            dap_chain_net_srv_stream_session_t * l_srv_session = (dap_chain_net_srv_stream_session_t *) a_usage->client->ch->stream->session->_inheritor;
+            switch(a_usage->price->units_uid.enm){
+                case SERV_UNIT_SEC:
+                    l_srv_session->limits_ts = l_remain_service->limits_ts;
+                    break;
+                case SERV_UNIT_B:
+                    l_srv_session->limits_bytes = l_remain_service->limits_bytes;
+                    break;
+            }
+            log_it(L_INFO, "User %s has %ld %s remain service. Start service without paying.", dap_chain_hash_fast_to_str_static(&a_usage->client_pkey_hash), 
+                            l_remain_service->limits_ts ? l_remain_service->limits_ts : l_remain_service->limits_bytes, 
+                            dap_chain_srv_unit_enum_to_str(a_usage->price->units_uid.enm));
+            size_t l_success_size = sizeof (dap_stream_ch_chain_net_srv_pkt_success_hdr_t );
+            dap_stream_ch_chain_net_srv_pkt_success_t *l_success = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_success_t,
+                                                                                    l_success_size);
+            if(!l_success) {
+                log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
+                a_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_ALLOC_MEMORY_ERROR;
+                s_service_substate_go_to_error(a_usage);
+            } else {
+                l_success->hdr.usage_id = a_usage->id;
+                l_success->hdr.net_id.uint64 = a_usage->net->pub.id.uint64;
+                l_success->hdr.srv_uid.uint64 = a_usage->service->uid.uint64;
+                dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS, l_success, l_success_size);
+                DAP_DELETE(l_success);
+                // create and fill first receipt
+                a_usage->receipt = dap_chain_datum_tx_receipt_create(a_usage->service->uid, a_usage->price->units_uid, a_usage->price->units, a_usage->price->value_datoshi, NULL, 0);
+                s_service_state_go_to_normal(a_usage);               
+            }                        
+        } else {
+            a_usage->receipt = dap_chain_net_srv_issue_receipt(a_usage->service, a_usage->price, NULL, 0);
+            dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST,
+                a_usage->receipt, a_usage->receipt->size);
+                
+            a_usage->service_substate = DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_WAITING_FIRST_RECEIPT_SIGN;
+
+            //start timeout timer
+            a_usage->receipt_timeout_timer_start_callback(a_usage);
+        }
     } else {
         int ret = s_check_tx_params(a_usage);
         if (ret != 0){
@@ -1325,7 +1302,10 @@ static void s_service_substate_pay_service(dap_chain_net_srv_usage_t *a_usage)
             case PAY_SERVICE_STATUS_SUCCESS:
                 // Store last receipt if any problems with transactions
                 dap_global_db_set(SRV_RECEIPTS_GDB_GROUP, dap_chain_hash_fast_to_str_static(&a_usage->client_pkey_hash), a_usage->receipt, a_usage->receipt->size, false, NULL, NULL);
-                s_service_state_go_to_normal(a_usage);
+                if (a_usage->service_state != DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_NORMAL)
+                    s_service_state_go_to_normal(a_usage);
+                else 
+                    s_service_substate_go_to_normal(a_usage);
                 return;
             break;
             case PAY_SERVICE_STATUS_TX_CANT_FIND:
@@ -1369,6 +1349,7 @@ static void s_service_substate_pay_service(dap_chain_net_srv_usage_t *a_usage)
             case PAY_SERVICE_STATUS_MEMALLOC_ERROR:
                 log_it(L_CRITICAL, "%s", c_error_memory_alloc);
                 a_usage->last_err_code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_ALLOC_MEMORY_ERROR;
+                DAP_DEL_Z(a_usage->receipt_next);
                 break;
             case PAY_SERVICE_STATUS_TX_ERROR:
             default: {
@@ -1470,6 +1451,7 @@ static void s_service_substate_go_to_error(dap_chain_net_srv_usage_t *a_usage)
 
     if (a_usage->service_state ==  DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_NORMAL){
         // wait until end of service in this substate
+        DAP_DEL_Z(a_usage->receipt_next);
         a_usage->service_substate=DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_ERROR;
         dap_stream_ch_pkt_write_unsafe(a_usage->client->ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &a_usage->last_err_code, sizeof (a_usage->last_err_code));
         if (a_usage->service->callbacks.response_error)
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index a3f9e3d65f..2a86f8e7f9 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -1391,7 +1391,7 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
 
         if(a_srv_session->limits_ts && a_srv_session->limits_ts < l_current_limit_ts/2 &&
             a_usage->service_state == DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_NORMAL &&
-            a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_NORMAL){
+            a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_NORMAL && !a_usage->receipt_next){
             l_issue_new_receipt = true;
         }
         a_srv_session->last_update_ts = time(NULL);
@@ -1458,7 +1458,7 @@ static void s_update_limits(dap_stream_ch_t * a_ch ,
         a_usage->is_limits_changed = true;
         if (a_srv_session->limits_bytes && a_srv_session->limits_bytes < current_limit_bytes/2 &&
             a_usage->service_state == DAP_CHAIN_NET_SRV_USAGE_SERVICE_STATE_NORMAL &&
-            a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_NORMAL){
+            a_usage->service_substate == DAP_CHAIN_NET_SRV_USAGE_SERVICE_SUBSTATE_NORMAL && !a_usage->receipt_next){
             l_issue_new_receipt = true;
         }
 
-- 
GitLab