From 717b5381b5f28e8f03cf7ecde507f758e29bfa76 Mon Sep 17 00:00:00 2001 From: "daniil.frolov" <daniil.frolov@demlabs.net> Date: Mon, 10 Jun 2024 05:53:10 +0000 Subject: [PATCH] hotfix-11968 --- modules/chain/dap_chain_ch.c | 7 +- .../consensus/esbocs/dap_chain_cs_esbocs.c | 6 +- modules/net/dap_chain_net.c | 2 + modules/type/blocks/dap_chain_cs_blocks.c | 218 +++++++++++------- .../blocks/include/dap_chain_block_cache.h | 7 +- .../type/blocks/tests/dap_chain_blocks_test.c | 77 +++++-- 6 files changed, 203 insertions(+), 114 deletions(-) diff --git a/modules/chain/dap_chain_ch.c b/modules/chain/dap_chain_ch.c index bc96f36faa..624617f17e 100644 --- a/modules/chain/dap_chain_ch.c +++ b/modules/chain/dap_chain_ch.c @@ -647,10 +647,6 @@ static bool s_sync_in_chains_callback(void *a_arg) } case ATOM_FORK: { debug_if(s_debug_more, L_WARNING, "Atom with hash %s for %s:%s added to a fork branch.", l_atom_hash_str, l_chain->net_name, l_chain->name); - if (dap_chain_atom_save(l_chain->cells, l_atom, l_atom_size, NULL) < 0) - log_it(L_ERROR, "Can't save atom %s to the file", l_atom_hash_str); - else - l_ack_send = true; break; } default: @@ -1367,7 +1363,8 @@ static bool s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg) struct legacy_sync_context *l_context = l_ch_chain->legacy_sync_context; if (!l_context || l_context->state != DAP_CHAIN_CH_STATE_UPDATE_CHAINS_REMOTE) { log_it(L_WARNING, "Can't process UPDATE_CHAINS packet cause synchronization sequence violation"); - dap_stream_ch_write_error_unsafe(a_ch, l_context->request_hdr.net_id, + if(l_context) + dap_stream_ch_write_error_unsafe(a_ch, l_context->request_hdr.net_id, l_context->request_hdr.chain_id, l_context->request_hdr.cell_id, DAP_CHAIN_CH_ERROR_INCORRECT_SYNC_SEQUENCE); break; diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index fb9a18318c..407e7e41b8 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -1590,7 +1590,8 @@ static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, da // Process candidate a_session->processing_candidate = a_candidate; dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_session->chain); - if (l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size, a_candidate_hash) == ATOM_ACCEPT) { + dap_chain_atom_verify_res_t l_verify_status = l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size, a_candidate_hash); + if (l_verify_status == ATOM_ACCEPT || l_verify_status == ATOM_FORK) { // validation - OK, gen event Approve s_message_send(a_session, DAP_CHAIN_ESBOCS_MSG_TYPE_APPROVE, a_candidate_hash, NULL, 0, a_session->cur_round.validators_list); @@ -1700,6 +1701,9 @@ static bool s_session_candidate_to_chain(dap_chain_esbocs_session_t *a_session, case ATOM_REJECT: log_it(L_WARNING,"Atom with hash %s rejected", l_candidate_hash_str); break; + case ATOM_FORK: + log_it(L_WARNING,"Atom with hash %s is added to forked branch.", l_candidate_hash_str); + break; default: log_it(L_CRITICAL, "Wtf is this ret code ? Atom hash %s code %d", l_candidate_hash_str, l_res); } diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index f5e39df6e4..caa3896508 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2547,6 +2547,7 @@ static void s_sync_timer_callback(void *a_arg) l_net_pvt->sync_context.state = l_net_pvt->sync_context.last_state = SYNC_STATE_WAITING; } else { l_net_pvt->sync_context.cur_chain = l_net_pvt->sync_context.cur_chain->next; + log_it(L_DEBUG, "[%s:%d] Go to next chain %p", __FUNCTION__, __LINE__, l_net_pvt->sync_context.cur_chain); if (!l_net_pvt->sync_context.cur_chain) { if (l_net_pvt->sync_context.last_state == SYNC_STATE_SYNCED) { l_net_pvt->state = NET_STATE_ONLINE; @@ -2562,6 +2563,7 @@ static void s_sync_timer_callback(void *a_arg) if (l_net_pvt->sync_context.cur_chain->callback_load_from_gdb) { // This type of chain is GDB based and not synced by chains protocol l_net_pvt->sync_context.cur_chain = l_net_pvt->sync_context.cur_chain->next; + log_it(L_DEBUG, "[%s:%d] Go to next chain %p", __FUNCTION__, __LINE__, l_net_pvt->sync_context.cur_chain); l_net_pvt->sync_context.last_state = SYNC_STATE_SYNCED; return; } diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 7738c1efde..364539a96d 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -155,7 +155,7 @@ int dap_chain_cs_blocks_init() { dap_chain_cs_type_add("blocks", s_chain_cs_blocks_new); s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false); - s_debug_more = dap_config_get_item_bool_default(g_config, "blocks", "debug_more", false); + s_debug_more = true; //dap_config_get_item_bool_default(g_config, "blocks", "debug_more", false); dap_cli_server_cmd_add ("block", s_cli_blocks, "Create and explore blockchains", "New block create, fill and complete commands:\n" "block -net <net_name> -chain <chain_name> new\n" @@ -1528,7 +1528,7 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks) } } -static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t current_block_idx, dap_chain_cell_t *a_cell) +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) { dap_chain_cs_blocks_t * l_blocks = a_blocks; if (!a_blocks){ @@ -1549,9 +1549,9 @@ static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ // Find longest forked branch dap_list_t *l_branch = a_bcache->forked_branches; dap_chain_block_forked_branch_t *l_longest_branch_cache_ptr = l_branch ? (dap_chain_block_forked_branch_t*)l_branch->data : NULL; - uint64_t l_longest_branch_length = current_block_idx; + uint64_t l_longest_branch_length = a_main_branch_length; while (l_branch){ - uint64_t l_branch_length = dap_list_length(((dap_chain_block_forked_branch_t*)l_branch->data)->forked_branch_atoms); + uint64_t l_branch_length = (((dap_chain_block_forked_branch_t*)l_branch->data)->forked_branch_atoms)->hh.tbl->num_items; if (l_branch_length > l_longest_branch_length){ l_longest_branch_length = l_branch_length; l_longest_branch_cache_ptr = (dap_chain_block_forked_branch_t*)l_branch->data; @@ -1559,34 +1559,45 @@ static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_ l_branch = l_branch->next; } - if (current_block_idx < l_longest_branch_length){ + if (a_main_branch_length < l_longest_branch_length){ + log_it(L_INFO,"Found new longest branch. Start switching."); // Switch branches - dap_list_t *l_new_forked_branch = NULL; - // First we must to remove all blocks from main branch to forked - // branch and delete all datums in this atoms from storages - dap_chain_block_cache_t *l_atom = (dap_chain_block_cache_t *)a_bcache->hh.tbl->tail->prev, - *l_tmp = (dap_chain_block_cache_t *)a_bcache; + dap_chain_block_forked_branch_atoms_table_t *l_new_forked_branch = NULL; + // First we must save all atoms from main branch into new forked branch unsigned l_curr_index; - for (l_atom = l_atom->hh.next, l_curr_index = 0; - current_block_idx > l_curr_index; l_atom = l_atom->hh.prev, l_curr_index++){ - l_new_forked_branch = dap_list_prepend(l_new_forked_branch, l_atom); - HASH_DEL(a_bcache, l_atom); - --PVT(l_blocks)->blocks_count; - s_delete_atom_datums(l_blocks, l_atom); + dap_chain_block_cache_t *l_atom = NULL; + for (l_atom = a_bcache->hh.next, l_curr_index = 0; + a_main_branch_length > l_curr_index && l_atom; l_curr_index++){ + dap_chain_block_forked_branch_atoms_table_t *l_new_item = DAP_NEW_Z(dap_chain_block_forked_branch_atoms_table_t); + 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_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); + l_curr_index = 0; + 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++){ + s_delete_atom_datums(l_blocks, l_last_new_forked_item->block_cache); + --PVT(l_blocks)->blocks_count; + HASH_DEL(PVT(l_blocks)->blocks, l_last_new_forked_item->block_cache); + } + + // Next we add all atoms from new main branch into blockchain + // and their datums into storages and remove old HT with former forked atoms + dap_chain_block_forked_branch_atoms_table_t *new_main_branch = l_longest_branch_cache_ptr->forked_branch_atoms, + *l_temp = NULL, *l_item = NULL; - // Next we add all atoms into HT and their datums into storages - dap_list_t * new_main_branch = l_longest_branch_cache_ptr->forked_branch_atoms; - while(new_main_branch){ - dap_chain_block_cache_t *l_curr_atom = (dap_chain_block_cache_t *)(new_main_branch->data); + HASH_ITER(hh, new_main_branch, l_item, l_temp){ + dap_chain_block_cache_t *l_curr_atom = l_item->block_cache; ++PVT(l_blocks)->blocks_count; HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_curr_atom->block_hash), l_curr_atom); debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", l_curr_atom); 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); - new_main_branch = new_main_branch->next; + HASH_DEL(new_main_branch, l_item); } - dap_list_free(l_longest_branch_cache_ptr->forked_branch_atoms); + // 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; } } @@ -1634,41 +1645,39 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da } debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str); - dap_chain_block_cache_t * l_prev_bcache = NULL, *l_tmp = NULL; - uint64_t l_current_item_index = 0; - dap_chain_cs_blocks_pvt_t *l_block_pvt = PVT(l_blocks); pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock); - l_prev_bcache = l_block_pvt->blocks ? l_block_pvt->blocks->hh.tbl->tail->prev : NULL; - if (l_prev_bcache){ - for (l_prev_bcache = l_prev_bcache->hh.next; - l_prev_bcache && l_current_item_index < DAP_FORK_MAX_DEPTH; - l_current_item_index++, l_prev_bcache = l_prev_bcache->hh.prev){ - if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){ - ++PVT(l_blocks)->blocks_count; - HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache); - debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom); - s_add_atom_datums(l_blocks, l_block_cache); - 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); - return ATOM_ACCEPT; + if (PVT(l_blocks)->blocks){ + dap_chain_block_cache_t *l_last_block = HASH_LAST(PVT(l_blocks)->blocks); + if (l_last_block && dap_hash_fast_compare(&l_last_block->block_hash, &l_block_prev_hash)){ + ++PVT(l_blocks)->blocks_count; + HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache); + debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom); + s_add_atom_datums(l_blocks, l_block_cache); + 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); + return ATOM_ACCEPT; + } + + + for (size_t i = 0; i < PVT(l_blocks)->forked_br_cnt; i++){ + dap_chain_block_forked_branch_t *l_cur_branch = PVT(l_blocks)->forked_branches[i]; + dap_chain_block_forked_branch_atoms_table_t *l_last = HASH_LAST(l_cur_branch->forked_branch_atoms); + if(!l_last){ + continue; } - if(l_prev_bcache && l_prev_bcache->forked_branches){ - // Check forked branches - dap_list_t * l_forked_branches = l_prev_bcache->forked_branches; - while(l_forked_branches){ - dap_chain_block_forked_branch_t *l_cur_branch_cache = (dap_chain_block_forked_branch_t*)l_forked_branches->data; - dap_chain_block_cache_t * l_branch_last_bcache = (dap_chain_block_cache_t *)(dap_list_last(l_cur_branch_cache->forked_branch_atoms))->data; - if(dap_hash_fast_compare(&l_branch_last_bcache->block_hash, &l_block_prev_hash)){ - l_cur_branch_cache->forked_branch_atoms = dap_list_append(l_cur_branch_cache->forked_branch_atoms, l_block_cache); - s_select_longest_branch(l_blocks, l_prev_bcache, l_current_item_index, l_cell); - 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; - } - l_forked_branches = l_forked_branches->next; - } + if (dap_hash_fast_compare(&l_last->block_hash, &l_block_prev_hash)){ + dap_chain_block_forked_branch_atoms_table_t *l_new_item = DAP_NEW_Z(dap_chain_block_forked_branch_atoms_table_t); + l_new_item->block_cache = l_block_cache; + l_new_item->block_hash = l_block_cache->block_hash; + 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); + 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; } } } else { @@ -1694,7 +1703,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da */ ret = ATOM_REJECT; case ATOM_REJECT: - debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom); + debug_if(s_debug_more, L_DEBUG, "Verified atom %p with hash %s: REJECTED", a_atom, dap_chain_hash_fast_to_str_static(&l_block_hash)); break; case ATOM_FORK:{ dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id); @@ -1718,17 +1727,23 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str); dap_chain_block_cache_t *l_prev_bcache = NULL, *l_tmp = NULL; pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock); + log_it(L_INFO, "New fork. Previous block hash %s, current block hash %s", dap_chain_hash_fast_to_str_static(&l_block_prev_hash), + l_block_cache->block_hash_str); HASH_FIND(hh, PVT(l_blocks)->blocks, &l_block_prev_hash, sizeof(dap_hash_fast_t), l_prev_bcache); - if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){ - // make forked branch list - dap_chain_block_forked_branch_t *forked_branch_cache = DAP_NEW_Z(dap_chain_block_forked_branch_t); - dap_list_t *forked_branch = NULL; - forked_branch = dap_list_append(forked_branch, l_block_cache); - forked_branch_cache->connected_block = l_prev_bcache; - forked_branch_cache->forked_branch_atoms = forked_branch; + if (l_prev_bcache){ + dap_chain_block_forked_branch_atoms_table_t *l_new_item = DAP_NEW_Z(dap_chain_block_forked_branch_atoms_table_t); + l_new_item->block_cache = l_block_cache; + l_new_item->block_hash = l_block_cache->block_hash; + l_block_cache->block_number = l_prev_bcache->block_number + 1; + + dap_chain_block_forked_branch_t *forked_branch = DAP_NEW_Z(dap_chain_block_forked_branch_t); + forked_branch->connected_block = l_prev_bcache; + HASH_ADD(hh, forked_branch->forked_branch_atoms, block_hash, sizeof(dap_hash_fast_t), l_new_item); + PVT(l_blocks)->forked_br_cnt++; PVT(l_blocks)->forked_branches = DAP_REALLOC_COUNT(PVT(l_blocks)->forked_branches, PVT(l_blocks)->forked_br_cnt); - PVT(l_blocks)->forked_branches[PVT(l_blocks)->forked_br_cnt-1] = forked_branch_cache; + PVT(l_blocks)->forked_branches[PVT(l_blocks)->forked_br_cnt-1] = forked_branch; + l_prev_bcache->forked_branches = dap_list_append(l_prev_bcache->forked_branches, PVT(l_blocks)->forked_branches[PVT(l_blocks)->forked_br_cnt-1]); pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); debug_if(s_debug_more, L_DEBUG, "Fork is made successfuly."); @@ -1738,8 +1753,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da return ATOM_REJECT; } case ATOM_PASS: - debug_if(s_debug_more, L_DEBUG, "... %s is already present", l_block_cache->block_hash_str); - return ATOM_REJECT; + debug_if(s_debug_more, L_DEBUG, "... %s is already present", dap_chain_hash_fast_to_str_static(&l_block_hash)); + break; default: debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret); break; @@ -1784,14 +1799,22 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, // 2nd level consensus if(l_blocks->callback_block_verify) - if (l_blocks->callback_block_verify(l_blocks, l_block, a_atom_size)) + if (l_blocks->callback_block_verify(l_blocks, l_block, a_atom_size)){ + log_it(L_WARNING, "Block rejected by block verificator."); return ATOM_REJECT; + } // Parse metadata bool l_is_genesis = dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_GENESIS); dap_hash_t *l_prev_hash_meta_data = (dap_hash_t *)dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_PREV); dap_hash_t l_block_prev_hash = l_prev_hash_meta_data ? *l_prev_hash_meta_data : (dap_hash_t){}; + char* l_block_str = dap_chain_hash_fast_to_str_new(&l_block_hash); + char* l_prev_block_str = dap_chain_hash_fast_to_str_new(&l_block_prev_hash); + + debug_if(s_debug_more, L_DEBUG,"Verify new block with hash %s. previous block %s", l_block_str, l_prev_block_str); + DAP_DELETE(l_block_str); + DAP_DELETE(l_prev_block_str); // genesis or seed mode if (l_is_genesis) { if (!PVT(l_blocks)->blocks) { @@ -1809,8 +1832,10 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, return ATOM_REJECT; } #else - PVT(l_blocks)->genesis_block_hash = *a_atom_hash; + PVT(l_blocks)->genesis_block_hash = *a_atom_hash; #endif + debug_if(s_debug_more,L_DEBUG,"%s","Accepting new genesis block"); + return ATOM_ACCEPT; } else { log_it(L_WARNING,"Cant accept genesis block: already present data in blockchain"); return ATOM_REJECT; @@ -1822,38 +1847,57 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, if (l_bcache_last && dap_hash_fast_compare(&l_bcache_last->block_hash, &l_block_prev_hash)) return ATOM_ACCEPT; - dap_chain_block_cache_t *l_prev_bcache = NULL, *l_tmp = NULL; + // search block and previous block in forked branch pthread_rwlock_rdlock(& PVT(l_blocks)->rwlock); - HASH_ITER(hh, PVT(l_blocks)->blocks, l_prev_bcache, l_tmp){ - if(l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, a_atom_hash)){ + for (size_t i = 0; i < PVT(l_blocks)->forked_br_cnt; i++){ + dap_chain_block_forked_branch_t *l_cur_branch = PVT(l_blocks)->forked_branches[i]; + dap_chain_block_forked_branch_atoms_table_t *l_item = NULL; + // Check block already present in forked branch + HASH_FIND(hh, l_cur_branch->forked_branch_atoms, &l_block_hash, sizeof(dap_hash_fast_t), l_item); + if (l_item && dap_hash_fast_compare(&l_item->block_hash, &l_block_hash)){ + debug_if(s_debug_more,L_DEBUG,"%s","Block already exist in forked branch."); + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + return ATOM_PASS; + } + l_item = NULL; + // Find previous block is last block in current branch + HASH_FIND(hh, l_cur_branch->forked_branch_atoms, &l_block_prev_hash, sizeof(dap_hash_fast_t), l_item); + if (l_item && l_item->hh.next != NULL){ pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + debug_if(s_debug_more,L_DEBUG,"%s","Found previous block in forked branch. Can't add block into branch because previous block is not last in the branch."); return ATOM_PASS; + } else if (l_item && l_item->hh.next == NULL) { + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + debug_if(s_debug_more,L_DEBUG,"%s","Accept block to a forked branch."); + return ATOM_ACCEPT; } + } - if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){ + // search block and previous block in main branch + unsigned l_checked_atoms_cnt = DAP_FORK_MAX_DEPTH; + 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)){ pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); - return ATOM_FORK; + debug_if(s_debug_more,L_DEBUG,"%s","Block is already exist in main branch."); + return ATOM_PASS; } - if(l_prev_bcache && l_prev_bcache->forked_branches){ - // Check forked branches - dap_list_t * l_forked_branches = l_prev_bcache->forked_branches; - while(l_forked_branches){ - dap_list_t *forked_branch = ((dap_chain_block_forked_branch_t *)l_forked_branches->data)->forked_branch_atoms; - dap_chain_block_cache_t *l_forked_branch_last_block = (dap_chain_block_cache_t *)(dap_list_last(forked_branch)->data); - if(l_forked_branch_last_block && dap_hash_fast_compare(&l_forked_branch_last_block->block_hash, &l_block_prev_hash)){ - pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); - return ATOM_ACCEPT; - } - l_forked_branches = l_forked_branches->next; + if (dap_hash_fast_compare(&l_tmp->block_hash, &l_block_prev_hash)){ + if (l_tmp->hh.next != NULL){ + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + debug_if(s_debug_more,L_DEBUG,"%s","New fork!"); + return ATOM_FORK; + } else { + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + debug_if(s_debug_more,L_DEBUG,"%s","Accept block to a main branch."); + return ATOM_ACCEPT; } } } - pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); - return ATOM_MOVE_TO_THRESHOLD; } - - return ATOM_ACCEPT; + debug_if(s_debug_more,L_DEBUG,"%s","Can't find valid previous block in chain or forked branches."); + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + return ATOM_REJECT; } /** diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h index 27dfe47095..0eda48a142 100644 --- a/modules/type/blocks/include/dap_chain_block_cache.h +++ b/modules/type/blocks/include/dap_chain_block_cache.h @@ -71,10 +71,15 @@ typedef struct dap_chain_block_cache { UT_hash_handle hh; } dap_chain_block_cache_t; +typedef struct dap_chain_block_forked_branch_atoms_table{ + dap_hash_fast_t block_hash; + dap_chain_block_cache_t *block_cache; + UT_hash_handle hh; +} dap_chain_block_forked_branch_atoms_table_t; typedef struct dap_chain_block_forked_branch { dap_chain_block_cache_t *connected_block; // pointer to a block connected with this forked branch - dap_list_t *forked_branch_atoms; + dap_chain_block_forked_branch_atoms_table_t *forked_branch_atoms; } dap_chain_block_forked_branch_t; int dap_chain_block_cache_init(); diff --git a/modules/type/blocks/tests/dap_chain_blocks_test.c b/modules/type/blocks/tests/dap_chain_blocks_test.c index 15c8487040..289a18c3e1 100644 --- a/modules/type/blocks/tests/dap_chain_blocks_test.c +++ b/modules/type/blocks/tests/dap_chain_blocks_test.c @@ -8,16 +8,21 @@ #include "dap_chain_cs.h" // #include "dap_chain_cs_blocks.h" -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_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; dap_hash_fast_t l_block_hash = {}; dap_chain_block_t * l_block = dap_chain_block_new(a_prev_block_hash, &l_block_size); dap_assert_PIF(l_block != NULL, "Creating of block:"); dap_hash_fast(l_block, l_block_size, &l_block_hash); - // dap_test_msg("Created genesis block %s", dap_chain_hash_fast_to_str_static(&l_block_hash)); dap_chain_atom_verify_res_t ret_val = a_chain->callback_atom_add(a_chain, (dap_chain_atom_ptr_t)l_block, l_block_size, &l_block_hash); - dap_assert_PIF( (ret_val == ATOM_ACCEPT || ret_val == ATOM_FORK), "Adding of block: "); + dap_assert_PIF( (ret_val == ATOM_ACCEPT || ret_val == ATOM_FORK), "Add block into chain: "); + + if (a_block) + *a_block = l_block; + + if(a_block_size) + *a_block_size = l_block_size; return l_block_hash; } @@ -31,7 +36,7 @@ bool dap_chain_block_test_compare_chain_hash_lists(dap_chain_t* a_chain, dap_lis dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get(l_iter, DAP_CHAIN_ITER_OP_FIRST, &l_atom_size_from_iter); for (dap_list_t *l_branch_temp = a_atoms_hash_list; l_branch_temp && l_atom; l_branch_temp = l_branch_temp->next, l_atom = a_chain->callback_atom_iter_get(l_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size_from_iter)){ - dap_test_msg("Check block %s and %s", dap_chain_hash_fast_to_str_static(l_iter->cur_hash), + dap_test_msg("Check block %s : num %d and %s", dap_chain_hash_fast_to_str_static(l_iter->cur_hash), l_iter->cur_num, dap_chain_hash_fast_to_str_static((dap_hash_fast_t*)l_branch_temp->data)); if (!dap_hash_fast_compare(l_iter->cur_hash, (dap_hash_fast_t*)l_branch_temp->data)){ a_chain->callback_atom_iter_delete(l_iter); @@ -61,19 +66,34 @@ void dap_chain_blocks_test() dap_hash_fast_t l_forked_block_hash = {}; dap_hash_fast_t l_block_hash = {}; + + dap_chain_block_t *l_block_repeat_first_forked = NULL; + dap_chain_block_t *l_block_double_main_branch = NULL; + dap_chain_block_t *l_block_repeat_middle_forked = NULL; + dap_chain_block_t *l_block_middle_prev_forked = NULL; + dap_hash_fast_t l_block_repeat_first_forked_hash = {}; + dap_hash_fast_t l_block_double_main_branch_hash = {}; + dap_hash_fast_t l_block_repeat_middle_forked_hash = {}; + dap_hash_fast_t l_block_middle_prev_forked_hash = {}; + + size_t l_block_repeat_first_forked_size = 0; + size_t l_block_double_main_branch_size = 0; + size_t l_block_repeat_middle_forked_size = 0; + size_t l_block_middle_prev_forked_size = 0; + dap_list_t *l_first_branch_atoms_list = NULL; dap_list_t *l_second_branch_atoms_list = NULL; dap_list_t *l_third_branch_atoms_list = NULL; dap_test_msg("Add genesis block..."); - l_block_hash = dap_chain_block_test_add_new_block (NULL, l_chain); + 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_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); dap_test_msg("Add second block..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + 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_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); @@ -81,37 +101,50 @@ void dap_chain_blocks_test() l_forked_block_hash = l_block_hash; dap_test_msg("Add 2 blocks to main branch..."); - for (int i = 0; i < 2; i++){ - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); - 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); - } + l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain, &l_block_double_main_branch, &l_block_double_main_branch_size); + l_block_double_main_branch_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); + + + 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_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); + dap_assert_PIF(ret_val == ATOM_PASS, "Add existing block into middle of main chain. Must be passed: "); dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check chain after atoms adding to the main branch "); /* ========================== Forked branches testing ======================= */ /* ========================== Add first forked branch ======================= */ dap_test_msg("Add forked branch..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_forked_block_hash, l_chain); + l_block_hash = dap_chain_block_test_add_new_block (&l_forked_block_hash, l_chain, &l_block_repeat_first_forked, &l_block_repeat_first_forked_size); + l_block_repeat_first_forked_hash = l_block_hash; l_block_hash_copy = DAP_DUP(&l_block_hash); l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy); - dap_test_msg("Add another atom to the forked branch..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + dap_test_msg("Add second atom to the forked branch..."); + 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_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_first_branch_atoms_list), "Check branches is not switched: "); + ret_val = l_chain->callback_atom_add(l_chain, (dap_chain_atom_ptr_t)l_block_repeat_first_forked, l_block_repeat_first_forked_size, &l_block_repeat_first_forked_hash); + dap_assert_PIF(ret_val == ATOM_PASS, "Add existing first forked block into chain. Must be passed: "); + dap_test_msg("Add third atom to the forked branch..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + 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_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_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); + 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); 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); @@ -119,7 +152,7 @@ void dap_chain_blocks_test() dap_test_msg("Add another block to former main branch"); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + 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_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy); @@ -128,13 +161,13 @@ void dap_chain_blocks_test() /* ========================== 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); + l_block_hash = dap_chain_block_test_add_new_block (&l_forked_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); for (int i = 0; i < 3; i++){ dap_test_msg("Add atom to second forked branch..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + 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); } @@ -142,11 +175,15 @@ void dap_chain_blocks_test() dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is not switched: "); dap_test_msg("Add 5th atom to second forked branch..."); - l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain); + 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); dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_third_branch_atoms_list), "Check branches is switched: "); + + 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); + dap_assert_PIF(ret_val == ATOM_PASS, "Add existing block into middle of forked chain. Must be passed: "); + dap_pass_msg("Fork handling test: ") } \ No newline at end of file -- GitLab