diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 05d3c5dde8616d58b5bd49565c39d68181b06918..3b2083799cfafa935e21a69e44a77d32b4c5abc8 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -68,7 +68,7 @@ typedef struct dap_chain_cs_blocks_pvt { // All the blocks are here dap_chain_block_cache_t *blocks; - _Atomic uint64_t blocks_count; + _Atomic uint64_t blocks_count; // Brnches and forks size_t forked_br_cnt; @@ -91,6 +91,11 @@ typedef struct dap_chain_cs_blocks_pvt { uint64_t block_confirm_cnt; } dap_chain_cs_blocks_pvt_t; +typedef struct dap_chain_block_fork_resolved_notificator{ + dap_chain_cs_blocks_callback_fork_resolved_t callback; + void *arg; +} dap_chain_block_fork_resolved_notificator_t; + #define PVT(a) ((dap_chain_cs_blocks_pvt_t *)(a)->_pvt ) #define print_rdlock(blocks) log_it(L_DEBUG, "Try to rdlock, %s, %d, thread_id=%u", __FUNCTION__, __LINE__, dap_gettid());\ @@ -172,6 +177,7 @@ static int s_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_c static bool s_seed_mode = false; static bool s_debug_more = false; +static dap_list_t *s_fork_resolved_notificators = NULL; /** * @brief dap_chain_cs_blocks_init @@ -379,6 +385,25 @@ dap_chain_block_cache_t * dap_chain_block_cache_get_by_hash(dap_chain_cs_blocks_ return l_ret; } +int dap_chain_block_add_fork_notificator(dap_chain_cs_blocks_callback_fork_resolved_t a_callback, void *a_arg) +{ + if (!a_callback) + return -100; + + dap_chain_block_fork_resolved_notificator_t *l_notificator = DAP_NEW_Z(dap_chain_block_fork_resolved_notificator_t); + if (!l_notificator) { + log_it(L_CRITICAL, "%s", c_error_memory_alloc); + return -1; + } + + l_notificator->arg = a_arg; + l_notificator->callback = a_callback; + + s_fork_resolved_notificators = dap_list_append(s_fork_resolved_notificators, l_notificator); + + return 0; +} + static char *s_blocks_decree_set_reward(dap_chain_net_t *a_net, dap_chain_t *a_chain, uint256_t a_value, dap_cert_t *a_cert) { dap_return_val_if_fail(a_net && a_cert && a_cert->enc_key && @@ -1649,6 +1674,10 @@ static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ } if (a_main_branch_length < l_longest_branch_length){ + dap_list_t *l_reverted_blocks_list= NULL; + uint64_t l_reverted_blocks_cnt = 0; + uint64_t l_main_blocks_cnt = 0; + log_it(L_INFO,"Found new longest branch. Start switching."); // Switch branches dap_chain_block_forked_branch_atoms_table_t *l_new_forked_branch = NULL; @@ -1661,8 +1690,11 @@ static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ l_new_item->block_cache = l_atom; l_new_item->block_hash = l_atom->block_hash; HASH_ADD(hh, l_new_forked_branch, block_hash, sizeof(dap_hash_fast_t), l_new_item); + l_reverted_blocks_cnt++; + dap_hash_fast_t *l_reverted_block_hash = DAP_DUP_SIZE(&l_atom->block_hash, sizeof(l_atom->block_hash)); + l_reverted_blocks_list = dap_list_prepend(l_reverted_blocks_list, l_reverted_block_hash); l_atom = l_atom->hh.next; - } + } // Next we must to remove all blocks from main branch and delete all datums in this atoms from storages dap_chain_block_forked_branch_atoms_table_t *l_last_new_forked_item = HASH_LAST(l_new_forked_branch); for (l_curr_index = 0; l_last_new_forked_item && l_curr_index < a_main_branch_length; l_last_new_forked_item = l_last_new_forked_item->hh.prev, ++l_curr_index){ @@ -1684,7 +1716,15 @@ static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ s_add_atom_datums(l_blocks, l_curr_atom); dap_chain_atom_notify(a_cell, &l_curr_atom->block_hash, (byte_t*)l_curr_atom->block, l_curr_atom->block_size); HASH_DEL(new_main_branch, l_item); + l_main_blocks_cnt++; } + // Notify about branch switching + for (dap_list_t *l_temp = s_fork_resolved_notificators; l_temp; l_temp = l_temp->next){ + dap_chain_block_fork_resolved_notificator_t *l_notificator = (dap_chain_block_fork_resolved_notificator_t*)l_temp->data; + l_notificator->callback(l_blocks->chain, a_bcache->block_hash, l_reverted_blocks_list, l_reverted_blocks_cnt, l_main_blocks_cnt, l_notificator->arg); + } + + dap_list_free_full(l_reverted_blocks_list, NULL); // Next we save pointer to new forked branch (former main branch) instead of it l_longest_branch_cache_ptr->forked_branch_atoms = l_new_forked_branch; return true; diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h index f3bf3fe8287e938663b02d5d918534869c6e8ed8..489595cd33ee8c2c4361e1bcd74faf23205070e6 100644 --- a/modules/type/blocks/include/dap_chain_cs_blocks.h +++ b/modules/type/blocks/include/dap_chain_cs_blocks.h @@ -35,6 +35,8 @@ typedef void (*dap_chain_cs_blocks_callback_op_results_t)(dap_chain_cs_blocks_t typedef int (*dap_chain_cs_blocks_callback_block_verify_t)(dap_chain_cs_blocks_t *a_cs_blocks, dap_chain_block_t *a_block, dap_hash_fast_t *a_block_hash, size_t a_block_size); typedef size_t (*dap_chain_cs_blocks_callback_block_sign_t)(dap_chain_cs_blocks_t *, dap_chain_block_t **, size_t); typedef dap_chain_block_t *(*dap_chain_cs_block_move_t)(dap_chain_cs_blocks_t *, size_t *); +typedef void (*dap_chain_cs_blocks_callback_fork_resolved_t)(dap_chain_t *a_chain, dap_hash_fast_t a_block_before_fork_hash, dap_list_t *a_reverted_blocks, + uint64_t a_reverted_blocks_cnt, uint64_t a_main_blocks_cnt, void * a_arg); typedef dap_chain_block_t * (*dap_chain_cs_blocks_callback_block_create_t)(dap_chain_cs_blocks_t *, dap_chain_datum_t *, dap_chain_hash_fast_t *, @@ -85,6 +87,8 @@ int dap_chain_cs_blocks_init(); void dap_chain_cs_blocks_deinit(); dap_chain_block_cache_t *dap_chain_block_cache_get_by_hash(dap_chain_cs_blocks_t *a_blocks, dap_chain_hash_fast_t *a_block_hash); +int dap_chain_block_add_fork_notificator(dap_chain_cs_blocks_callback_fork_resolved_t a_callback, void *a_arg); + DAP_STATIC_INLINE char *dap_chain_cs_blocks_get_fee_group(const char *a_net_name) { return dap_strdup_printf("local.%s.fees", a_net_name); diff --git a/modules/type/blocks/tests/dap_chain_blocks_test.c b/modules/type/blocks/tests/dap_chain_blocks_test.c index 1d1c7d768706dd41ff5f7050975b45f453c40455..c515e951d4736a347b3e723d19f26e96edcbfe78 100644 --- a/modules/type/blocks/tests/dap_chain_blocks_test.c +++ b/modules/type/blocks/tests/dap_chain_blocks_test.c @@ -6,12 +6,20 @@ #include "dap_chain_cs_blocks.h" #include "dap_chain_cs_esbocs.h" #include "dap_chain_cs.h" -// #include "dap_chain_cs_blocks.h" -dap_hash_fast_t g_last_confirmed_block_hash = {}; -dap_hash_fast_t g_last_notified_block_hash = {}; -int g_confirmed_blocks_counter = 0; -int g_custom_notify_counter = 0; +typedef struct { + dap_hash_fast_t block_before_fork_hash; + dap_list_t *reverted_blocks; + uint64_t reverted_blocks_cnt; + uint64_t main_blocks_cnt; +} last_fork_resolved_notification_data_t; + +static dap_hash_fast_t s_last_confirmed_block_hash = {}; +static dap_hash_fast_t s_last_notified_block_hash = {}; +static int s_confirmed_blocks_counter = 0; +static int s_custom_notify_counter = 0; + +static last_fork_resolved_notification_data_t s_fork_resolved_arg = {}; typedef struct { dap_hash_fast_t *last_notified_hash; @@ -25,6 +33,21 @@ void callback_notify(void *a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id *l_arg->last_notified_hash = *a_atom_hash; } +static void *s_callback_list_copy(const void *a_data, UNUSED_ARG void *a_usr_data) +{ + return DAP_DUP((dap_hash_fast_t *)a_data); +} + +void callback_fork_resolved_notify(dap_chain_t *a_chain, dap_hash_fast_t a_block_before_fork_hash, dap_list_t *a_reverted_blocks, + uint64_t a_reverted_blocks_cnt, uint64_t a_main_blocks_cnt, void * a_arg) +{ + last_fork_resolved_notification_data_t *l_arg = (last_fork_resolved_notification_data_t*)a_arg; + + l_arg->reverted_blocks = dap_list_copy_deep(a_reverted_blocks, s_callback_list_copy, NULL); + l_arg->main_blocks_cnt = a_main_blocks_cnt; + l_arg->reverted_blocks_cnt = a_reverted_blocks_cnt; + l_arg->block_before_fork_hash = a_block_before_fork_hash; +} dap_hash_fast_t dap_chain_block_test_add_new_block (dap_hash_fast_t *a_prev_block_hash, dap_chain_t *a_chain, dap_chain_block_t **a_block, size_t *a_block_size) { @@ -85,14 +108,16 @@ void dap_chain_blocks_test() notify_arg_t *l_arg = DAP_NEW_Z(notify_arg_t); - l_arg->cnt = &g_confirmed_blocks_counter; - l_arg->last_notified_hash = &g_last_confirmed_block_hash; + l_arg->cnt = &s_confirmed_blocks_counter; + l_arg->last_notified_hash = &s_last_confirmed_block_hash; dap_chain_atom_confirmed_notify_add(l_chain, callback_notify, (void*)l_arg, 0); l_arg = DAP_NEW_Z(notify_arg_t); - l_arg->cnt = &g_custom_notify_counter; - l_arg->last_notified_hash = &g_last_notified_block_hash; + l_arg->cnt = &s_custom_notify_counter; + l_arg->last_notified_hash = &s_last_notified_block_hash; dap_chain_atom_confirmed_notify_add(l_chain, callback_notify, (void*)l_arg, 2); + dap_chain_block_add_fork_notificator(callback_fork_resolved_notify, &s_fork_resolved_arg); + dap_hash_fast_t l_forked_block_hash = {}; dap_hash_fast_t l_block_hash = {}; dap_hash_fast_t l_genesis_block_hash = {}; @@ -138,14 +163,14 @@ void dap_chain_blocks_test() l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy); - dap_assert_PIF((g_custom_notify_counter == 1 && dap_hash_fast_compare(&g_last_notified_block_hash, &l_genesis_block_hash)), "Check custom notify: "); + dap_assert_PIF((s_custom_notify_counter == 1 && dap_hash_fast_compare(&s_last_notified_block_hash, &l_genesis_block_hash)), "Check custom notify: "); l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain, &l_block_repeat_middle_forked, &l_block_repeat_middle_forked_size); l_block_repeat_middle_forked_hash = l_block_hash; l_block_hash_copy = DAP_DUP(&l_block_hash); l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy); - dap_assert_PIF((g_custom_notify_counter == 2 && dap_hash_fast_compare(&g_last_notified_block_hash, &l_forked_block_hash)), "Check custom notify: "); + dap_assert_PIF((s_custom_notify_counter == 2 && dap_hash_fast_compare(&s_last_notified_block_hash, &l_forked_block_hash)), "Check custom notify: "); dap_chain_atom_verify_res_t ret_val = l_chain->callback_atom_add(l_chain, (dap_chain_atom_ptr_t)l_block_double_main_branch, l_block_double_main_branch_size, &l_block_double_main_branch_hash, false); dap_assert_PIF(ret_val == ATOM_PASS, "Add existing block into middle of main chain. Must be passed: "); @@ -177,6 +202,8 @@ void dap_chain_blocks_test() l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy); dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_second_branch_atoms_list), "Check branches is switched: "); + dap_assert_PIF(dap_hash_fast_compare(&s_fork_resolved_arg.block_before_fork_hash, &l_forked_block_hash) && + s_fork_resolved_arg.main_blocks_cnt == 3 && s_fork_resolved_arg.reverted_blocks_cnt == 2, "Check branches is switched notification: "); dap_test_msg("Add block to former main branch"); l_block_hash = dap_chain_block_test_add_new_block ((dap_hash_fast_t*)dap_list_last(l_first_branch_atoms_list)->data, l_chain, NULL, NULL); @@ -192,10 +219,12 @@ void dap_chain_blocks_test() l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy); dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is switched: "); + + dap_hash_fast_t l_last_former_main_branch_hash = l_block_hash; // genesis block must be confirmed, check counter and hash of confirmed block - dap_assert_PIF((g_confirmed_blocks_counter == 1 && dap_hash_fast_compare(&g_last_confirmed_block_hash, &l_genesis_block_hash)), "Check confirmed block: "); + dap_assert_PIF((s_confirmed_blocks_counter == 1 && dap_hash_fast_compare(&s_last_confirmed_block_hash, &l_genesis_block_hash)), "Check confirmed block: "); /* ========================== Add second forked branch ======================= */ dap_test_msg("Add atom to second forked branch..."); @@ -221,7 +250,7 @@ void dap_chain_blocks_test() dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_third_branch_atoms_list), "Check branches is switched: "); // second block must be confirmed, check counter and hash of confirmed block - dap_assert_PIF((g_confirmed_blocks_counter == 2 && dap_hash_fast_compare(&g_last_confirmed_block_hash, &l_forked_block_hash)), "Check confirmed block: "); + dap_assert_PIF((s_confirmed_blocks_counter == 2 && dap_hash_fast_compare(&s_last_confirmed_block_hash, &l_forked_block_hash)), "Check confirmed block: "); ret_val = l_chain->callback_atom_add(l_chain, (dap_chain_atom_ptr_t)l_block_repeat_middle_forked, l_block_repeat_middle_forked_size, &l_block_repeat_middle_forked_hash, false); dap_assert_PIF(ret_val == ATOM_PASS, "Add existing block into middle of forked chain. Must be passed: "); @@ -232,7 +261,7 @@ void dap_chain_blocks_test() l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy); // third block must be confirmed, check counter and hash of confirmed block - dap_assert_PIF((g_confirmed_blocks_counter == 3 && dap_hash_fast_compare(&g_last_confirmed_block_hash, &l_third_confirmed_block)), "Check confirmed block: "); + dap_assert_PIF((s_confirmed_blocks_counter == 3 && dap_hash_fast_compare(&s_last_confirmed_block_hash, &l_third_confirmed_block)), "Check confirmed block: "); // dap_test_msg("Add new block into former main chain..."); // size_t l_block_size = 0;