From 40e67d56df06047c0ea0397942b033ecc679d7ad Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Wed, 5 Apr 2023 20:21:47 +0300
Subject: [PATCH] [*] Esbocs precommit correct handling

---
 .../consensus/esbocs/dap_chain_cs_esbocs.c    | 152 ++++++++++--------
 1 file changed, 84 insertions(+), 68 deletions(-)

diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index d0ed624ec7..dda86267b6 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -37,6 +37,9 @@ static bool s_session_candidate_to_chain(
 static void s_session_candidate_submit(dap_chain_esbocs_session_t *a_session);
 static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, dap_chain_block_t *a_candidate,
                                        size_t a_candidate_size, dap_hash_fast_t *a_candidate_hash);
+static void s_session_candidate_precommit(dap_chain_esbocs_session_t *a_session, dap_chain_esbocs_message_t *a_message);
+static void s_session_round_finish(dap_chain_esbocs_session_t *a_session, dap_chain_esbocs_store_t *l_store);
+
 static bool s_session_timer(void *a_arg);
 static void s_message_send(dap_chain_esbocs_session_t *a_session, uint8_t a_message_type, dap_hash_fast_t *a_block_hash,
                                     const void *a_data, size_t a_data_size, dap_list_t *a_validators);
@@ -434,9 +437,18 @@ static void s_session_send_startsync(dap_chain_esbocs_session_t *a_session)
         return;     // My last block hash is different, so skip this round
     if (!s_validator_check(&a_session->my_signing_addr, a_session->cur_round.validators_list))
         return;     // I'm not a selected validator, just skip sync message
-    debug_if(PVT(a_session->esbocs)->debug, L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U"."
-                                                   " Sent START_SYNC pkt, attempt %"DAP_UINT64_FORMAT_U,
-                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id, a_session->cur_round.sync_attempt);
+    if (PVT(a_session->esbocs)->debug) {
+        dap_string_t *l_addr_list = dap_string_new("");
+        for (dap_list_t *it = a_session->cur_round.validators_list; it; it = it->next) {
+            dap_string_append_printf(l_addr_list, NODE_ADDR_FP_STR"; ",
+                                     NODE_ADDR_FP_ARGS_S(((dap_chain_esbocs_validator_t *)it->data)->node_addr));
+        }
+        log_it(L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U"."
+                       " Sent START_SYNC pkt, attempt %"DAP_UINT64_FORMAT_U" current validators list: %s",
+                            a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                a_session->cur_round.sync_attempt, l_addr_list->str);
+        dap_string_free(l_addr_list, true);
+    }
     s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC, &l_last_block_hash,
                    &a_session->cur_round.sync_attempt, sizeof(uint64_t),
                    a_session->cur_round.validators_list);
@@ -701,11 +713,8 @@ static void s_session_state_change(dap_chain_esbocs_session_t *a_session, enum s
         HASH_ITER(hh, a_session->cur_round.message_items, l_chain_message, l_chain_message_tmp) {
             if (l_chain_message->message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT &&
                     dap_hash_fast_compare(&l_chain_message->message->hdr.candidate_hash,
-                                          &a_session->cur_round.attempt_candidate_hash))
-            {
-                dap_chain_esbocs_message_t *l_msg = l_chain_message->message;
-                size_t l_msg_size = sizeof(*l_msg) + l_msg->hdr.sign_size + l_msg->hdr.message_size;
-                s_session_packet_in(a_session, NULL, NULL, &l_chain_message->message_hash, (uint8_t*)l_msg, l_msg_size);
+                                          &a_session->cur_round.attempt_candidate_hash)) {
+                s_session_candidate_precommit(a_session, l_chain_message->message);
             }
         }
         // Send own PreCommit
@@ -729,7 +738,7 @@ static void s_session_proc_state(dap_chain_esbocs_session_t *a_session)
         dap_time_t l_round_timeout = PVT(a_session->esbocs)->round_start_sync_timeout;
         bool l_round_skip = !s_validator_check(&a_session->my_signing_addr, a_session->cur_round.validators_list);
         if (l_round_skip)
-            l_round_timeout += PVT(a_session->esbocs)->round_attempt_timeout * 3 * PVT(a_session->esbocs)->round_attempts_max;
+            l_round_timeout += PVT(a_session->esbocs)->round_attempt_timeout * 4 * PVT(a_session->esbocs)->round_attempts_max;
         if (a_session->ts_round_sync_start && l_time - a_session->ts_round_sync_start >= l_round_timeout) {
             if (a_session->cur_round.validators_synced_count >= PVT(a_session->esbocs)->min_validators_count) {
                 a_session->cur_round.id = s_session_calc_current_round_id(a_session);
@@ -786,7 +795,7 @@ static void s_session_proc_state(dap_chain_esbocs_session_t *a_session)
         }
         break;
     case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH:
-        if (l_time - a_session->ts_attempt_start >= PVT(a_session->esbocs)->round_attempt_timeout) {
+        if (l_time - a_session->ts_attempt_start >= PVT(a_session->esbocs)->round_attempt_timeout * 2) {
             debug_if(l_cs_debug, L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
                                         " Attempt finished by reason: cant't collect minimum number of validator's precommits with same final hash",
                                             a_session->chain->net_name, a_session->chain->name,
@@ -892,6 +901,68 @@ static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, da
     a_session->processing_candidate = NULL;
 }
 
+static void s_session_candidate_precommit(dap_chain_esbocs_session_t *a_session, dap_chain_esbocs_message_t *a_message)
+{
+    bool l_cs_debug = PVT(a_session->esbocs)->debug;
+    uint16_t l_cs_level = PVT(a_session->esbocs)->min_validators_count;
+    byte_t *l_message_data = a_message->msg_n_sign;
+    dap_chain_hash_fast_t *l_candidate_hash = &a_message->hdr.candidate_hash;
+    dap_chain_esbocs_store_t *l_store;
+    char *l_candidate_hash_str = NULL;
+    HASH_FIND(hh, a_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+    if (!l_store) {
+        l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+        log_it(L_WARNING, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                          " Receive PRE_COMMIT message for unknown candidate:%s",
+                            a_session->chain->net_name, a_session->chain->name,
+                                a_session->cur_round.id, a_message->hdr.attempt_num,
+                                    l_candidate_hash_str);
+        DAP_DELETE(l_candidate_hash_str);
+        return;
+    }
+
+    if (dap_hash_fast_is_blank(&l_store->precommit_candidate_hash))
+        // We have not yet precommit candidate. Message will be processed later
+        return;
+    dap_hash_fast_t *l_precommit_hash = (dap_hash_fast_t *)l_message_data;
+    if (!dap_hash_fast_compare(l_precommit_hash, &l_store->precommit_candidate_hash)) {
+        if (l_cs_debug) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            char *l_my_precommit_hash_str = dap_chain_hash_fast_to_str_new(&l_store->precommit_candidate_hash);
+            char *l_remote_precommit_hash_str = dap_chain_hash_fast_to_str_new(l_precommit_hash);
+            log_it(L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                          " Candidate:%s has different final hash of local and remote validators\n"
+                          "(%s and %s)",
+                                a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                    a_message->hdr.attempt_num, l_candidate_hash_str,
+                                        l_my_precommit_hash_str, l_remote_precommit_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            DAP_DELETE(l_my_precommit_hash_str);
+            DAP_DELETE(l_remote_precommit_hash_str);
+        }
+        return;
+    }
+
+    if (l_cs_debug) {
+        l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+        log_it(L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                        " Receive PRE_COMMIT: candidate:%s",
+                            a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                a_message->hdr.attempt_num, l_candidate_hash_str);
+    }
+    if (++l_store->precommit_count >= l_cs_level && !l_store->decide_commit &&
+            dap_hash_fast_compare(&a_session->cur_round.attempt_candidate_hash, l_candidate_hash)) {
+        l_store->decide_commit = true;
+        debug_if(l_cs_debug, L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                    " Candidate:%s precommted by minimum number of validators, try to finish this round",
+                                        a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                            a_message->hdr.attempt_num, l_candidate_hash_str);
+        s_session_round_finish(a_session, l_store);
+        // ATTENTION: New round will be started by incoming atom notifier event
+    }
+    DAP_DEL_Z(l_candidate_hash_str);
+}
+
 static bool s_session_candidate_to_chain(dap_chain_esbocs_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
                                          dap_chain_block_t *a_candidate, size_t a_candidate_size)
 {
@@ -1029,6 +1100,7 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
     uint16_t l_cs_level = PVT(l_session->esbocs)->min_validators_count;
     size_t l_message_data_size = l_message->hdr.message_size;
     byte_t *l_message_data = l_message->msg_n_sign;
+    dap_chain_hash_fast_t *l_candidate_hash = &l_message->hdr.candidate_hash;
     dap_sign_t *l_sign = (dap_sign_t *)(l_message_data + l_message_data_size);
     size_t l_sign_size = l_message->hdr.sign_size;
 
@@ -1145,7 +1217,6 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
 
     s_message_chain_add(l_session, l_message, a_data_size, a_data_hash, &l_signing_addr);
 
-    dap_chain_hash_fast_t *l_candidate_hash = &l_message->hdr.candidate_hash;
     switch (l_message->hdr.type) {
     case DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC: {
         uint64_t l_sync_attempt = *(uint64_t *)l_message_data;
@@ -1399,63 +1470,8 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
         DAP_DEL_Z(l_candidate_hash_str);
     } break;
 
-    case DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT: {
-        dap_chain_esbocs_store_t *l_store;
-        char *l_candidate_hash_str = NULL;
-        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
-        if (!l_store) {
-            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-            log_it(L_WARNING, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
-                              " Receive PRE_COMMIT message for unknown candidate:%s",
-                                l_session->chain->net_name, l_session->chain->name,
-                                    l_session->cur_round.id, l_message->hdr.attempt_num,
-                                        l_candidate_hash_str);
-            DAP_DELETE(l_candidate_hash_str);
-            break;
-        }
-
-        if (dap_hash_fast_is_blank(&l_store->precommit_candidate_hash))
-            // We have not yet precommit candidate. Message will be processed later
-            break;
-
-        dap_hash_fast_t *l_precommit_hash = (dap_hash_fast_t *)l_message_data;
-        if (!dap_hash_fast_compare(l_precommit_hash, &l_store->precommit_candidate_hash)) {
-            if (l_cs_debug) {
-                l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-                char *l_my_precommit_hash_str = dap_chain_hash_fast_to_str_new(&l_store->precommit_candidate_hash);
-                char *l_remote_precommit_hash_str = dap_chain_hash_fast_to_str_new(l_precommit_hash);
-                log_it(L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
-                              " Candidate:%s has different final hash of local and remote validators\n"
-                              "(%s and %s)",
-                                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
-                                        l_message->hdr.attempt_num, l_candidate_hash_str,
-                                            l_my_precommit_hash_str, l_remote_precommit_hash_str);
-                DAP_DELETE(l_candidate_hash_str);
-                DAP_DELETE(l_my_precommit_hash_str);
-                DAP_DELETE(l_remote_precommit_hash_str);
-            }
-            break;
-        }
-
-        if (l_cs_debug) {
-            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-            log_it(L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
-                            " Receive PRE_COMMIT: candidate:%s",
-                                l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
-                                    l_message->hdr.attempt_num, l_candidate_hash_str);
-        }
-        if (++l_store->precommit_count >= l_cs_level && !l_store->decide_commit &&
-                dap_hash_fast_compare(&l_session->cur_round.attempt_candidate_hash, l_candidate_hash)) {
-            l_store->decide_commit = true;
-            debug_if(l_cs_debug, L_MSG, "net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
-                                        " Candidate:%s precommted by minimum number of validators, try to finish this round",
-                                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
-                                                l_message->hdr.attempt_num, l_candidate_hash_str);
-            s_session_round_finish(l_session, l_store);
-            // ATTENTION: New round will be started by incoming atom notifier event
-        }
-        DAP_DEL_Z(l_candidate_hash_str);
-    } break;
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT:
+        s_session_candidate_precommit(l_session, l_message);
     default:
         break;
     }
-- 
GitLab