diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 86d1935c47c392c49944c0dc8fc6d2a0808ffb1f..fb6708089779162cee5620f8c45df78af08daf7a 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -634,6 +634,35 @@ void dap_chain_add_callback_notify(dap_chain_t *a_chain, dap_chain_callback_noti } +/** + * @brief Add a callback to monitor blocks received enough confirmations + * @param a_chain + * @param a_callback + * @param a_arg + */ +void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, void *a_arg, uint64_t a_conf_cnt) +{ + if(!a_chain){ + log_it(L_ERROR, "NULL chain passed to dap_chain_add_callback_notify()"); + return; + } + if(!a_callback){ + log_it(L_ERROR, "NULL callback passed to dap_chain_add_callback_notify()"); + return; + } + dap_chain_atom_confirmed_notifier_t * l_notifier = DAP_NEW_Z(dap_chain_atom_confirmed_notifier_t); + if (l_notifier == NULL){ + log_it(L_ERROR, "Can't allocate memory for notifier in dap_chain_add_callback_notify()"); + return; + } + l_notifier->block_notify_cnt = a_conf_cnt; + l_notifier->callback = a_callback; + l_notifier->arg = a_arg; + pthread_rwlock_wrlock(&a_chain->rwlock); + a_chain->atom_confirmed_notifiers = dap_list_append(a_chain->atom_confirmed_notifiers, l_notifier); + pthread_rwlock_unlock(&a_chain->rwlock); +} + /** * @brief dap_chain_get_last_atom_hash * @param a_chain diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h index ee066d615550300e37807300dc263aad7a5a68cd..e2655426f789bcfc77a82fd10c4ffa73ffbb3283 100644 --- a/modules/chain/include/dap_chain.h +++ b/modules/chain/include/dap_chain.h @@ -232,6 +232,8 @@ typedef struct dap_chain { dap_list_t *atom_notifiers; + dap_list_t *atom_confirmed_notifiers; + dap_config_t *config; void * _pvt; // private data @@ -246,6 +248,12 @@ typedef struct dap_chain_atom_notifier { void *arg; } dap_chain_atom_notifier_t; +typedef struct dap_chain_atom_confirmed_notifier { + uint64_t block_notify_cnt; + dap_chain_callback_notify_t callback; + void *arg; +} dap_chain_atom_confirmed_notifier_t; + typedef struct dap_chain_pvt { char *cs_name, *file_storage_dir; bool cs_started, need_reorder; @@ -281,6 +289,7 @@ dap_chain_t *dap_chain_load_from_cfg(const char *a_chain_net_name, dap_chain_net void dap_chain_delete(dap_chain_t * a_chain); void dap_chain_add_callback_notify(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_arg); +void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, void *a_arg, uint64_t a_conf_cnt); void dap_chain_atom_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size); void dap_chain_atom_add_from_threshold(dap_chain_t *a_chain); dap_chain_atom_ptr_t dap_chain_get_atom_by_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size); diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 85b25313f3d4a20faddae904c2a758d4c4eccf2d..f0b9d40e92ae93f9962a185790e7abb53e560f23 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -38,6 +38,13 @@ #define LOG_TAG "dap_chain_cs_blocks" +#ifndef DAP_CHAIN_BLOCKS_TEST +#define DAP_FORK_MAX_DEPTH_DEFAULT 40 +#else +#define DAP_FORK_MAX_DEPTH_DEFAULT 5 +#endif + + typedef struct dap_chain_block_datum_index { dap_chain_hash_fast_t datum_hash; int ret_code; @@ -80,6 +87,8 @@ typedef struct dap_chain_cs_blocks_pvt { pthread_rwlock_t rwlock; struct cs_blocks_hal_item *hal; + // Number of blocks for one block confirmation + uint64_t block_confirm_cnt; } dap_chain_cs_blocks_pvt_t; #define PVT(a) ((dap_chain_cs_blocks_pvt_t *)(a)->_pvt ) @@ -319,6 +328,8 @@ static int s_chain_cs_blocks_new(dap_chain_t *a_chain, dap_config_t *a_chain_con pthread_rwlock_init(&l_cs_blocks_pvt->datums_rwlock, NULL); pthread_rwlock_init(&l_cs_blocks_pvt->forked_branches_rwlock, NULL); + + l_cs_blocks_pvt->block_confirm_cnt = dap_config_get_item_uint64_default(a_chain_config,"blocks","blocks_for_confirmation",DAP_FORK_MAX_DEPTH_DEFAULT); const char * l_genesis_blocks_hash_str = dap_config_get_item_str_default(a_chain_config,"blocks","genesis_block",NULL); if ( l_genesis_blocks_hash_str ){ int lhr; @@ -1596,22 +1607,22 @@ static void s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_bloc } -static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t a_main_branch_length, dap_chain_cell_t *a_cell) +static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t a_main_branch_length, dap_chain_cell_t *a_cell) { dap_chain_cs_blocks_t * l_blocks = a_blocks; if (!a_blocks){ log_it(L_ERROR,"a_blocks is NULL"); - return; + return false; } if (!a_bcache){ log_it(L_ERROR,"a_bcache is NULL"); - return; + return false; } if (!a_bcache->forked_branches){ log_it(L_ERROR,"This block is not a forked."); - return; + return false; } // Find longest forked branch @@ -1667,7 +1678,9 @@ static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ } // 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; } + return false; } /** @@ -1724,6 +1737,24 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size); dap_chain_atom_add_from_threshold(a_chain); pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + + dap_chain_block_cache_t *l_bcache_last = HASH_LAST(PVT(l_blocks)->blocks); + // Send it to notificator listeners +#ifndef DAP_CHAIN_BLOCKS_TEST + if (!dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id))){ +#endif + dap_list_t *l_iter; + DL_FOREACH(a_chain->atom_confirmed_notifiers, l_iter) { + dap_chain_atom_confirmed_notifier_t *l_notifier = (dap_chain_atom_confirmed_notifier_t*)l_iter->data; + dap_chain_block_cache_t *l_tmp = l_bcache_last; + int l_checked_atoms_cnt = l_notifier->block_notify_cnt != 0 ? l_notifier->block_notify_cnt : PVT(l_blocks)->block_confirm_cnt; + for (; l_tmp && l_checked_atoms_cnt; l_tmp = l_tmp->hh.prev, l_checked_atoms_cnt--); + if (l_checked_atoms_cnt == 0 && l_tmp) + l_notifier->callback(l_notifier->arg, a_chain, a_chain->active_cell_id, &l_tmp->block_hash, (void*)l_tmp->block, l_tmp->block_size); + } +#ifndef DAP_CHAIN_BLOCKS_TEST + } +#endif return ATOM_ACCEPT; } @@ -1742,7 +1773,25 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da l_block_cache->block_number = l_last->block_cache->block_number + 1; HASH_ADD(hh, l_cur_branch->forked_branch_atoms, block_hash, sizeof(dap_hash_fast_t), l_new_item); uint64_t l_main_branch_length = PVT(l_blocks)->blocks_count - l_cur_branch->connected_block->block_number; - s_select_longest_branch(l_blocks, l_cur_branch->connected_block, l_main_branch_length, l_cell); + if (s_select_longest_branch(l_blocks, l_cur_branch->connected_block, l_main_branch_length, l_cell)){ + dap_chain_block_cache_t *l_bcache_last = HASH_LAST(PVT(l_blocks)->blocks); + // Send it to notificator listeners +#ifndef DAP_CHAIN_BLOCKS_TEST + if (!dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id))){ +#endif + dap_list_t *l_iter; + DL_FOREACH(a_chain->atom_confirmed_notifiers, l_iter) { + dap_chain_atom_confirmed_notifier_t *l_notifier = (dap_chain_atom_confirmed_notifier_t*)l_iter->data; + dap_chain_block_cache_t *l_tmp = l_bcache_last; + int l_checked_atoms_cnt = l_notifier->block_notify_cnt != 0 ? l_notifier->block_notify_cnt : PVT(l_blocks)->block_confirm_cnt; + for (; l_tmp && l_checked_atoms_cnt; l_tmp = l_tmp->hh.prev, l_checked_atoms_cnt--); + if (l_checked_atoms_cnt == 0 && l_tmp) + l_notifier->callback(l_notifier->arg, a_chain, a_chain->active_cell_id, &l_tmp->block_hash, (void*)l_tmp->block, l_tmp->block_size); + } +#ifndef DAP_CHAIN_BLOCKS_TEST + } +#endif + } pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED to a forked branch.", a_atom); return ATOM_FORK; @@ -1965,7 +2014,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain, } if (ret == ATOM_MOVE_TO_THRESHOLD) { // search block and previous block in main branch - unsigned l_checked_atoms_cnt = DAP_FORK_MAX_DEPTH; + unsigned l_checked_atoms_cnt = PVT(l_blocks)->block_confirm_cnt; for (dap_chain_block_cache_t *l_tmp = l_bcache_last; l_tmp && l_checked_atoms_cnt; l_tmp = l_tmp->hh.prev, l_checked_atoms_cnt--){ if(dap_hash_fast_compare(&l_tmp->block_hash, &l_block_hash)){ debug_if(s_debug_more,L_DEBUG,"%s","Block is already exist in main branch."); diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h index dd538ac6bcb08f874b82cd549d9cd93818ce7711..f3bf3fe8287e938663b02d5d918534869c6e8ed8 100644 --- a/modules/type/blocks/include/dap_chain_cs_blocks.h +++ b/modules/type/blocks/include/dap_chain_cs_blocks.h @@ -26,8 +26,6 @@ #include "dap_chain_block.h" #include "dap_chain_block_cache.h" -#define DAP_FORK_MAX_DEPTH 100 - #define DAP_REWARD_INIT_TIMESTAMP 1700870400UL // 25 Nov 2023 00:00:00 GMT typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t; diff --git a/modules/type/blocks/tests/dap_chain_blocks_test.c b/modules/type/blocks/tests/dap_chain_blocks_test.c index 3f0708c388ec09473cd2d05d1cced260ad6e0c44..1d1c7d768706dd41ff5f7050975b45f453c40455 100644 --- a/modules/type/blocks/tests/dap_chain_blocks_test.c +++ b/modules/type/blocks/tests/dap_chain_blocks_test.c @@ -8,6 +8,24 @@ #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 *last_notified_hash; + int *cnt; +} notify_arg_t; + +void callback_notify(void *a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, dap_chain_hash_fast_t *a_atom_hash, void *a_atom, size_t a_atom_size) +{ + notify_arg_t *l_arg = (notify_arg_t*)a_arg; + (*l_arg->cnt)++; + *l_arg->last_notified_hash = *a_atom_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) { size_t l_block_size = 0; @@ -65,8 +83,19 @@ void dap_chain_blocks_test() dap_config_t l_cfg = {}; dap_assert_PIF(dap_chain_cs_create(l_chain, &l_cfg) == 0, "Chain cs creating: "); + + 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; + 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; + dap_chain_atom_confirmed_notify_add(l_chain, callback_notify, (void*)l_arg, 2); + dap_hash_fast_t l_forked_block_hash = {}; dap_hash_fast_t l_block_hash = {}; + dap_hash_fast_t l_genesis_block_hash = {}; dap_chain_block_t *l_block_repeat_first_forked = NULL; dap_chain_block_t *l_block_double_main_branch = NULL; @@ -89,6 +118,7 @@ void dap_chain_blocks_test() dap_test_msg("Add genesis block..."); l_block_hash = dap_chain_block_test_add_new_block (NULL, l_chain, NULL, NULL); dap_hash_fast_t *l_block_hash_copy = DAP_DUP(&l_block_hash); + l_genesis_block_hash = l_block_hash; l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy); l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy); l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy); @@ -108,11 +138,15 @@ 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: "); + 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_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: "); @@ -158,11 +192,15 @@ 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: "); /* ========================== Add second forked branch ======================= */ dap_test_msg("Add atom to second forked branch..."); l_block_hash = dap_chain_block_test_add_new_block (&l_forked_block_hash, l_chain, NULL, NULL); + dap_hash_fast_t l_third_confirmed_block = l_block_hash; l_block_hash_copy = DAP_DUP(&l_block_hash); l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy); @@ -182,9 +220,27 @@ 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: "); + 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: "); - dap_pass_msg("Fork handling test: ") + dap_test_msg("Add 6th atom to second forked branch..."); + l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain, NULL, NULL); + l_block_hash_copy = DAP_DUP(&l_block_hash); + 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_test_msg("Add new block into former main chain..."); + // size_t l_block_size = 0; + // dap_chain_block_t * l_block = dap_chain_block_new(&l_last_former_main_branch_hash, &l_block_size); + // dap_assert_PIF(l_block != NULL, "Creating of block:"); + // dap_hash_fast(l_block, l_block_size, &l_block_hash); + // ret_val = l_chain->callback_atom_add(l_chain, (dap_chain_atom_ptr_t)l_block, l_block_size, &l_block_hash, false); + // dap_assert_PIF(ret_val == ATOM_REJECT, "Add new block into former main chain. Must be rejected because this fork is deeper max than depth: "); + + dap_pass_msg("Fork handling test: "); } diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c index a33348a5ee95819f0bdb127e5ede47e9f2fadc91..5ca2f079d162661c1a4c88c5cc126032493f6d35 100644 --- a/modules/wallet/dap_chain_wallet.c +++ b/modules/wallet/dap_chain_wallet.c @@ -312,10 +312,14 @@ int dap_chain_wallet_init() if ( !(l_dir = opendir(c_wallets_path)) ) { /* Path is not exist ? Create the dir and exit */ #ifdef _WIN32 - mkdir(c_wallets_path); + int l_res = mkdir(c_wallets_path); #else - mkdir(c_wallets_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + int l_res = mkdir(c_wallets_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); #endif + if (l_res) { + log_it(L_ERROR, "Can't create wallet dir %s", c_wallets_path); + return l_res; + } return 0; }