From 78d71892a119039645008a5460f9af31c27d1714 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Mon, 3 Apr 2023 09:58:51 +0000
Subject: [PATCH] Features 8332

---
 .../dap_chain_net_srv_stake_pos_delegate.c    | 213 ++++++++++++++----
 .../dap_chain_net_srv_stake_pos_delegate.h    |   4 +-
 modules/type/blocks/dap_chain_cs_blocks.c     |   2 +-
 3 files changed, 171 insertions(+), 48 deletions(-)

diff --git a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
index 6f3164d042..c8b0737339 100644
--- a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
@@ -75,8 +75,10 @@ int dap_chain_net_srv_stake_pos_delegate_init()
          "\tDelegate public key in specified certificate with specified net name. Pay with specified value of m-tokens of native net token.\n"
     "srv_stake approve -net <net_name> -tx <transaction_hash> -poa_cert <priv_cert_name>\n"
          "\tApprove stake transaction by root node certificate within specified net name\n"
-    "srv_stake keylist -net <net_name> [-cert <delegated_cert>]\n"
+    "srv_stake list keys -net <net_name> [-cert <delegated_cert>]\n"
          "\tShow the list of active stake keys (optional delegated with specified cert).\n"
+    "srv_stake list tx -net <net_name> \n"
+         "\tShow the list of key delegation transactions.\n"
     "srv_stake invalidate -net <net_name> {-tx <transaction_hash> | -cert <delegated_cert> | -cert_pkey_hash <pkey_hash>}"
                             " {-wallet <wallet_name> -fee <value> | -poa_cert <cert_name>}\n"
          "\tInvalidate requested delegated stake transaction by hash or cert name or cert pkey hash within net name and"
@@ -160,7 +162,10 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr
     l_stake->value = a_value;
     l_stake->tx_hash = *a_stake_tx_hash;
     if (!l_found)
+    {
         HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake);
+        HASH_ADD(ht, s_srv_stake->h_itemlist, tx_hash, sizeof(dap_chain_hash_fast_t), l_stake);
+    }
 
 }
 
@@ -1051,10 +1056,60 @@ static void s_srv_stake_print(dap_chain_net_srv_stake_item_t *a_stake, dap_strin
     DAP_DELETE(l_pkey_hash_str);
 }
 
+/**
+ * @brief The get_tx_cond_pos_del_from_tx struct
+ */
+struct get_tx_cond_pos_del_from_tx
+{
+    dap_list_t * ret;
+
+};
+
+/**
+ * @brief s_get_tx_filter_callback
+ * @param a_net
+ * @param a_tx
+ * @param a_arg
+ */
+static void s_get_tx_filter_callback(dap_chain_net_t* a_net, dap_chain_datum_tx_t *a_tx, void *a_arg)
+{
+    struct get_tx_cond_pos_del_from_tx * l_args = (struct get_tx_cond_pos_del_from_tx* ) a_arg;
+    int l_out_idx_tmp = 0;
+    dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
+    dap_hash_fast_t l_datum_hash;
+
+    if (NULL != (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE,
+                                                                 &l_out_idx_tmp)))
+    {
+        dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_datum_hash);
+        if(dap_chain_ledger_tx_hash_is_used_out_item(a_net->pub.ledger,&l_datum_hash,l_out_idx_tmp)==NULL)
+        {
+            dap_chain_net_srv_stake_item_t *l_stake = NULL;
+            HASH_FIND(ht, s_srv_stake->h_itemlist, &l_datum_hash, sizeof(dap_hash_fast_t), l_stake);
+            if(!l_stake){
+                l_args->ret = dap_list_append(l_args->ret,a_tx);
+            }
+        }
+    }
+    return;
+}
+
+static int callback_compare_tx_list(const void * a_datum1, const void * a_datum2, void *a_unused)
+{
+    UNUSED(a_unused);
+    dap_chain_datum_tx_t *l_datum1 = (dap_chain_datum_tx_t*) a_datum1;
+    dap_chain_datum_tx_t *l_datum2 = (dap_chain_datum_tx_t*) a_datum2;
+    if(!l_datum1 || !l_datum2 || l_datum1->header.ts_created == l_datum2->header.ts_created)
+        return 0;
+    if(l_datum1->header.ts_created > l_datum2->header.ts_created)
+        return 1;
+    return -1;
+}
+
 static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_APPROVE, CMD_KEY_LIST, CMD_INVALIDATE, CMD_MIN_VALUE
+        CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_APPROVE, CMD_LIST, CMD_INVALIDATE, CMD_MIN_VALUE
     };
     int l_arg_index = 1;
 
@@ -1079,8 +1134,8 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
         l_cmd_num = CMD_APPROVE;
     }
     // Show the tx list with frozen staker funds
-    else if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "keylist", NULL)) {
-        l_cmd_num = CMD_KEY_LIST;
+    else if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "list", NULL)) {
+        l_cmd_num = CMD_LIST;
     }
     // Return staker's funds
     else if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "invalidate", NULL)) {
@@ -1090,6 +1145,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
     else if (dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "min_value", NULL)) {
         l_cmd_num = CMD_MIN_VALUE;
     }
+    else if(dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "test_com", NULL)) {
+        //l_cmd_num = CMD_test;
+    }
 
     switch (l_cmd_num) {
         case CMD_ORDER:
@@ -1244,53 +1302,118 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                                               l_decree_hash_str);
             DAP_DELETE(l_decree_hash_str);
         } break;
-        case CMD_KEY_LIST: {
-            const char *l_net_str = NULL,
-                       *l_cert_str = NULL;
+        case CMD_LIST: {
+            const char * sub_com = NULL;
             l_arg_index++;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
-            if (!l_net_str) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'keylist' requires parameter -net");
-                return -3;
-            }
-            dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-            if (!l_net) {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
-                return -4;
-            }
-            dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp;
-            dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
-            if (l_cert_str) {
-                dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
-                if (!l_cert) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
-                    return -18;
+            if(dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "keys", &sub_com)){
+                const char *l_net_str = NULL,
+                           *l_cert_str = NULL;
+                l_arg_index++;
+                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+                if (!l_net_str) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'keylist' requires parameter -net");
+                    return -3;
                 }
-                dap_chain_addr_t l_signing_addr;
-                if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, l_net->pub.id)) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
-                    return -20;
-                }
-                HASH_FIND(hh, s_srv_stake->itemlist, &l_signing_addr, sizeof(dap_chain_addr_t), l_stake);
-                if (!l_stake) {
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate isn't delegated or it's delegating isn't approved");
-                    return -21;
+                dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+                if (!l_net) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                    return -4;
                 }
-            }
-            dap_string_t *l_reply_str = dap_string_new("Pkey hash\t\t\tStake value\tTx hash\n");
-            if (l_stake)
-                s_srv_stake_print(l_stake, l_reply_str);
-            else
-                HASH_ITER(hh, s_srv_stake->itemlist, l_stake, l_tmp) {
-                    if (l_stake->net->pub.id.uint64 != l_net->pub.id.uint64) {
-                        continue;
+                dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp;
+                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
+                if (l_cert_str) {
+                    dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+                    if (!l_cert) {
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found");
+                        return -18;
+                    }
+                    dap_chain_addr_t l_signing_addr;
+                    if (dap_chain_addr_fill_from_key(&l_signing_addr, l_cert->enc_key, l_net->pub.id)) {
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong");
+                        return -20;
                     }
+                    HASH_FIND(hh, s_srv_stake->itemlist, &l_signing_addr, sizeof(dap_chain_addr_t), l_stake);
+                    if (!l_stake) {
+                        dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate isn't delegated or it's delegating isn't approved");
+                        return -21;
+                    }
+                }
+                dap_string_t *l_reply_str = dap_string_new("Pkey hash\t\t\tStake value\tTx hash\n");
+                if (l_stake)
                     s_srv_stake_print(l_stake, l_reply_str);
+                else
+                    HASH_ITER(hh, s_srv_stake->itemlist, l_stake, l_tmp) {
+                        if (l_stake->net->pub.id.uint64 != l_net->pub.id.uint64) {
+                            continue;
+                        }
+                        s_srv_stake_print(l_stake, l_reply_str);
+                    }
+                if (!HASH_CNT(hh, s_srv_stake->itemlist)) {
+                    dap_string_append(l_reply_str, "No keys found");
                 }
-            if (!HASH_CNT(hh, s_srv_stake->itemlist)) {
-                dap_string_append(l_reply_str, "No keys found");
+                *a_str_reply = dap_string_free(l_reply_str, false);
+            }else if(dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "tx", &sub_com))
+            {
+                const char *l_net_str = NULL;
+                l_arg_index++;
+                dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+                if (!l_net_str) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'approve' requires parameter -net");
+                    return -3;
+                }
+                dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+                if (!l_net) {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                    return -4;
+                }
+                struct get_tx_cond_pos_del_from_tx * l_args = DAP_NEW_Z(struct get_tx_cond_pos_del_from_tx);
+                dap_string_t * l_str_tmp = dap_string_new(NULL);
+                dap_hash_fast_t l_datum_hash;
+                dap_chain_datum_tx_t *l_datum_tx = NULL;
+                dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
+                int l_out_idx_tmp = 0;
+                char *l_hash_str = NULL;
+                char *spaces = {"--------------------------------------------------------------------------------------------------------------------"};
+                char *l_signing_addr_str = NULL;
+                char *l_balance = NULL;
+                char* l_node_address_text_block = NULL;
+                dap_chain_net_get_tx_all(l_net,TX_SEARCH_TYPE_NET,s_get_tx_filter_callback, l_args);
+                l_args->ret = dap_list_sort(l_args->ret, callback_compare_tx_list);
+                for(dap_list_t *tx = l_args->ret; tx; tx = tx->next)
+                {
+                    l_datum_tx = (dap_chain_datum_tx_t*)tx->data;
+                    dap_time_t l_ts_create = (dap_time_t)l_datum_tx->header.ts_created;
+                    char buf[50] = {[0]='\0'};
+                    dap_hash_fast(l_datum_tx, dap_chain_datum_tx_get_size(l_datum_tx), &l_datum_hash);
+                    l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_datum_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE,
+                                                                                     &l_out_idx_tmp);
+                    l_hash_str = dap_chain_hash_fast_to_str_new(&l_datum_hash);                    
+                    dap_string_append_printf(l_str_tmp,"%s \n",spaces);
+                    dap_string_append_printf(l_str_tmp,"%s \n",dap_ctime_r(&l_ts_create, buf));
+                    dap_string_append_printf(l_str_tmp,"tx_hash:\t%s \n",l_hash_str);
+
+                    l_signing_addr_str = dap_chain_addr_to_str(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr);
+                    char *l_pkey_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr.data.hash_fast);
+                    l_balance = dap_chain_balance_to_coins(l_tx_out_cond->header.value);
+
+                    dap_string_append_printf(l_str_tmp,"signing_addr:\t%s \n",l_signing_addr_str);
+                    dap_string_append_printf(l_str_tmp,"signing_hash:\t%s \n",l_pkey_hash_str);
+                    l_node_address_text_block = dap_strdup_printf("node_address:\t" NODE_ADDR_FP_STR,NODE_ADDR_FP_ARGS_S(l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr));
+                    dap_string_append_printf(l_str_tmp,"%s \n",l_node_address_text_block);
+                    dap_string_append_printf(l_str_tmp,"value:\t\t%s \n",l_balance);
+
+                    DAP_DELETE(l_node_address_text_block);
+                    DAP_DELETE(l_signing_addr_str);
+                    DAP_DELETE(l_pkey_hash_str);
+                    DAP_DELETE(l_balance);
+                    DAP_DELETE(l_hash_str);
+                }
+
+                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_args);
             }
-            *a_str_reply = dap_string_free(l_reply_str, false);
+
         } break;
         case CMD_INVALIDATE: {
             const char *l_net_str = NULL,
@@ -1490,7 +1613,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                 DAP_DELETE(l_decree);
                 return -21;
             }
-        } break;
+        } break;        
         default: {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]);
             return -1;
diff --git a/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h b/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
index e54785d97c..df399d9e6b 100644
--- a/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
+++ b/modules/service/stake_pos_delegate/include/dap_chain_net_srv_stake_pos_delegate.h
@@ -37,7 +37,7 @@ typedef struct dap_chain_net_srv_stake_item {
     dap_chain_addr_t signing_addr;
     dap_chain_hash_fast_t tx_hash;
     dap_chain_node_addr_t node_addr;
-    UT_hash_handle hh;
+    UT_hash_handle hh,ht;
 } dap_chain_net_srv_stake_item_t;
 
 
@@ -54,7 +54,7 @@ typedef struct dap_chain_net_srv_stake_cache_item {
 
 typedef struct dap_chain_net_srv_stake {
     uint256_t delegate_allowed_min;
-    dap_chain_net_srv_stake_item_t *itemlist;
+    dap_chain_net_srv_stake_item_t *itemlist, *h_itemlist;
     dap_chain_net_srv_stake_cache_item_t *cache;
 } dap_chain_net_srv_stake_t;
 
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index bff5afaabb..5dc48804e1 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -170,7 +170,7 @@ int dap_chain_cs_blocks_init()
                 "\t\tDump block info\n\n"
 
             "block -net <net_name> -chain <chain_name> list [-from_hash <block_hash>] [-to_hash <block_hash>]"
-            "[-from_dt <datetime>] [-to_dt <datetime>]\n"
+            "[-from_dt <datetime>] [-to_dt <datetime>] [-cert <priv_cert_name> -unspent]\n"
                 "\t\t List blocks\n\n"
         "Commission collect:\n"
             "block -net <net_name> -chain <chain_name> fee collect\n"
-- 
GitLab