From a38aa534533872ec2f2414a017be790ca4fd0370 Mon Sep 17 00:00:00 2001 From: "pavel.uhanov" <pavel.uhanov@demlabs.net> Date: Thu, 13 Feb 2025 15:23:21 +0000 Subject: [PATCH] feature-15600 --- .../dap_chain_net_srv_stake_pos_delegate.c | 86 +++++++++++++++++-- .../dap_chain_net_srv_stake_pos_delegate.h | 1 + modules/type/blocks/dap_chain_cs_blocks.c | 17 +++- 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 7bf277cea4..e042e897cf 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -109,6 +109,10 @@ struct srv_stake { dap_chain_net_srv_stake_item_t *itemlist; dap_chain_net_srv_stake_item_t *tx_itemlist; struct cache_item *cache; + struct { + bool in_process; + dap_chain_net_srv_stake_item_t *sandbox; + } hardfork; }; static int s_cli_srv_stake(int a_argc, char **a_argv, void **a_str_reply); @@ -179,7 +183,10 @@ static dap_pkey_t *s_get_pkey_by_hash_callback(const uint8_t *a_hash) dap_chain_net_srv_stake_item_t *l_stake = NULL; for ( ; l_srv_stake_list && !l_stake; l_srv_stake_list = l_srv_stake_list->next) { struct srv_stake *l_srv_stake = l_srv_stake_list->data; - HASH_FIND(hh, l_srv_stake->itemlist, a_hash, sizeof(dap_hash_fast_t), l_stake); + if (l_srv_stake->hardfork.in_process) + HASH_FIND(hh, l_srv_stake->hardfork.sandbox, a_hash, sizeof(dap_hash_fast_t), l_stake); + else + HASH_FIND(hh, l_srv_stake->itemlist, a_hash, sizeof(dap_hash_fast_t), l_stake); } return l_stake ? l_stake->pkey : NULL; } @@ -275,13 +282,15 @@ static void s_pos_delegate_delete(void *a_service_internal) HASH_DELETE(ht, l_srv_stake->tx_itemlist, l_stake); } HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) { - // Clang bug at this, l_stake should change at every loop cycle HASH_DEL(l_srv_stake->itemlist, l_stake); s_srv_stake_item_free((void *)l_stake); } + HASH_ITER(hh, l_srv_stake->hardfork.sandbox, l_stake, l_tmp) { + HASH_DEL(l_srv_stake->hardfork.sandbox, l_stake); + s_srv_stake_item_free((void *)l_stake); + } struct cache_item *l_cache_item = NULL, *l_cache_tmp = NULL; HASH_ITER(hh, l_srv_stake->cache, l_cache_item, l_cache_tmp) { - // Clang bug at this, l_stake should change at every loop cycle HASH_DEL(l_srv_stake->cache, l_cache_item); DAP_DELETE(l_cache_item); } @@ -484,6 +493,29 @@ static void s_stake_recalculate_weights(dap_chain_net_id_t a_net_id) while (s_weights_truncate(l_srv_stake, l_limit_min)); } +static void s_stake_key_delegate_sandbox(struct srv_stake *a_srv_stake, dap_chain_addr_t *a_signing_addr, dap_pkey_t *a_pkey) +{ + dap_return_if_pass(!a_srv_stake || !a_signing_addr || !a_pkey); + log_it(L_NOTICE, "Add key %s delegation in hardfork process", dap_hash_fast_to_str_static(&a_signing_addr->data.hash_fast)); + dap_chain_net_srv_stake_item_t *l_stake = NULL; + bool l_found = false; + HASH_FIND(hh, a_srv_stake->hardfork.sandbox, &a_signing_addr->data.hash_fast, sizeof(dap_hash_fast_t), l_stake); + if (!l_stake) + l_stake = DAP_NEW_Z_RET_IF_FAIL(dap_chain_net_srv_stake_item_t); + else + l_found = true; + if (dap_pkey_get_size(l_stake->pkey)) { + log_it(L_DEBUG, "Full pkey by hash %s was replaced", dap_hash_fast_to_str_static(&a_signing_addr->data.hash_fast)); + DAP_DELETE(l_stake->pkey); + } + l_stake->pkey = DAP_DUP_SIZE(a_pkey, dap_pkey_get_size(a_pkey)); + if (!l_found) { + l_stake->signing_addr = *a_signing_addr; + HASH_ADD(hh, a_srv_stake->hardfork.sandbox, signing_addr.data.hash_fast, sizeof(dap_hash_fast_t), l_stake); + } + return; +} + void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr_t *a_signing_addr, dap_chain_datum_decree_t *a_decree, uint256_t a_value, dap_chain_node_addr_t *a_node_addr, dap_pkey_t *a_pkey) { @@ -4302,6 +4334,10 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net_id); if (!l_srv_stake) return -2; + if (l_srv_stake->hardfork.in_process && l_srv_stake->hardfork.sandbox) { + log_it(L_ERROR, "Temp hardfork table already existed in net %"DAP_UINT64_FORMAT_U, a_net_id.uint64); + return -3; + } dap_chain_net_srv_stake_item_t *l_stake, *l_tmp; HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) { if (dap_hash_fast_is_blank(&l_stake->tx_hash)) { @@ -4310,11 +4346,17 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da } } // clean prev table - s_pos_delegate_purge(a_net_id); + if (!l_srv_stake->hardfork.in_process) + s_pos_delegate_purge(a_net_id); + // restore poa keys for ( dap_list_t* l_iter = dap_list_first(l_current_list); l_iter; l_iter = l_iter->next) { l_stake = (dap_chain_net_srv_stake_item_t *)l_iter->data; - dap_chain_net_srv_stake_key_delegate(l_net, &l_stake->signing_addr, NULL, l_stake->value, &l_stake->node_addr, l_stake->pkey); + if (l_srv_stake->hardfork.in_process) { + s_stake_key_delegate_sandbox(l_srv_stake, &l_stake->signing_addr, l_stake->pkey); + } else { + dap_chain_net_srv_stake_key_delegate(l_net, &l_stake->signing_addr, NULL, l_stake->value, &l_stake->node_addr, l_stake->pkey); + } } dap_list_free_full(l_current_list, s_srv_stake_item_free); @@ -4341,9 +4383,39 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da dap_list_free_full(l_current_list, NULL); return -4; } - dap_chain_net_srv_stake_key_delegate(l_net, &l_addr, l_current_decree, l_value, &l_node_addr, dap_chain_datum_decree_get_pkey(l_current_decree)); - dap_chain_net_srv_stake_add_approving_decree_info(l_current_decree, l_net); + if (l_srv_stake->hardfork.in_process) { + s_stake_key_delegate_sandbox(l_srv_stake, &l_addr, dap_chain_datum_decree_get_pkey(l_current_decree)); + } else { + dap_chain_net_srv_stake_key_delegate(l_net, &l_addr, l_current_decree, l_value, &l_node_addr, dap_chain_datum_decree_get_pkey(l_current_decree)); + dap_chain_net_srv_stake_add_approving_decree_info(l_current_decree, l_net); + } } dap_list_free_full(l_current_list, NULL); return 0; } + +/** + * @brief switch key delegate table + * @param a_net_id net id to switch + * @param a_to_temp true - to sandbox, false - to main + * @return if OK - 0, other if error + */ +int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_sandbox) +{ + struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net_id); + if (!l_srv_stake) + return -1; + if (l_srv_stake->hardfork.in_process == a_to_sandbox) { + log_it(L_DEBUG, "Key delegate table already switched to %s table", a_to_sandbox ? "sandbox" : "main"); + return -2; + } + if (!a_to_sandbox) { // free temp table if switch to main + dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp = NULL; + HASH_ITER(hh, l_srv_stake->hardfork.sandbox, l_stake, l_tmp) { + HASH_DEL(l_srv_stake->itemlist, l_stake); + s_srv_stake_item_free((void *)l_stake); + } + } + l_srv_stake->hardfork.in_process = a_to_sandbox; + return 0; +} \ No newline at end of file diff --git a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h index d8d3ba9785..ff21ac8e41 100644 --- a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h +++ b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h @@ -82,3 +82,4 @@ void dap_chain_net_srv_stake_add_approving_decree_info(dap_chain_datum_decree_t void dap_chain_net_srv_stake_remove_approving_decree_info(dap_chain_net_t *a_net, dap_chain_addr_t *a_signing_addr); int dap_chain_net_srv_stake_hardfork_data_export(dap_chain_net_t *a_net, dap_list_t **a_out); int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, dap_hash_fast_t *a_hardfork_decree_hash); +int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_sandbox); \ No newline at end of file diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index b23851f2cf..147849011f 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -1735,8 +1735,9 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id); assert(l_net); if ( !dap_chain_net_get_load_mode(l_net) ) { - if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL)) < 0 ) { - log_it(L_ERROR, "Can't save atom to file, code %d", ret); + if ( dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL) < 0 ) { + log_it(L_ERROR, "Can't save atom to file"); + dap_chain_net_srv_stake_switch_table(a_chain->net_id, false); return ATOM_REJECT; } else if (a_chain->is_mapped) { l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) ); // Switching to mapped area @@ -1748,6 +1749,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped); if (!l_block_cache) { log_it(L_DEBUG, "%s", "... corrupted block"); + dap_chain_net_srv_stake_switch_table(a_chain->net_id, false); return ATOM_REJECT; } debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str); @@ -1838,6 +1840,10 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da log_it(L_ERROR, "Can't find hardfork decree hash in candidate block meta"); return ATOM_REJECT; } + if (dap_chain_net_srv_stake_switch_table(a_chain->net_id, false)) { // to main + log_it(L_CRITICAL, "Can't accept hardfork genesis block %s: error in switching to main table", dap_hash_fast_to_str_static(a_atom_hash)); + return ATOM_REJECT; + } if (dap_chain_net_srv_stake_hardfork_data_import(a_chain->net_id, l_hardfork_decree_hash)) { // True import log_it(L_ERROR, "Can't accept hardfork genesis block %s: error in hardfork data restoring", dap_hash_fast_to_str_static(a_atom_hash)); return ATOM_REJECT; @@ -2008,7 +2014,14 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain, log_it(L_ERROR, "Can't find hardfork decree hash in candidate block meta"); return ATOM_REJECT; } + if (dap_chain_net_srv_stake_switch_table(a_chain->net_id, true)) { // to Sandbox + log_it(L_ERROR, "Can't accept hardfork genesis block %s: error in switching to sandbox table", dap_hash_fast_to_str_static(a_atom_hash)); + return ATOM_REJECT; + } if (dap_chain_net_srv_stake_hardfork_data_import(a_chain->net_id, l_hardfork_decree_hash)) { // Sandbox + if (dap_chain_net_srv_stake_switch_table(a_chain->net_id, false)) { // return to main + log_it(L_CRITICAL, "Can't accept hardfork genesis block %s: error in switching to main table", dap_hash_fast_to_str_static(a_atom_hash)); + } log_it(L_ERROR, "Can't accept hardfork genesis block %s: error in hardfork data restoring", dap_hash_fast_to_str_static(a_atom_hash)); return ATOM_REJECT; } -- GitLab