diff --git a/CMakeLists.txt b/CMakeLists.txt index cb475b591e18d82736167b25857ac4c58332f58d..87f693ce8f15040dec97208f3d0ec55173b55224 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ endif(NOT DAP_INT128_SUPPORT) if (BUILD_CELLFRAME_SDK_TESTS) enable_testing() add_definitions("-DDAP_LEDGER_TEST") + add_definitions("-DDAP_CHAIN_BLOCKS_TEST") endif() if (BUILD_WITH_ZIP) diff --git a/dap-sdk b/dap-sdk index fef9c1e0ed18345ba26aa8ffe610cc83a55899f2..41abc05d56f0a54a3d1158726aa6f70c030effa2 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit fef9c1e0ed18345ba26aa8ffe610cc83a55899f2 +Subproject commit 41abc05d56f0a54a3d1158726aa6f70c030effa2 diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c index 953b3bd2fa67436160376ad997e8b418f8a8f12d..2bec84dd237bee32e8c33dce017618f091227549 100644 --- a/modules/chain/dap_chain.c +++ b/modules/chain/dap_chain.c @@ -798,6 +798,10 @@ const char* dap_chain_get_path(dap_chain_t *a_chain) } 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) { +#ifdef DAP_CHAIN_BLOCKS_TEST + return; +#endif + if ( !a_chain_cell->chain->atom_notifiers ) return; dap_list_t *l_iter; diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c index 874a84e6db7c53586fb8ca8f3b11359e21a16022..7034d04aa6fefb3f72740630f13e603cee2a45a9 100644 --- a/modules/chain/dap_chain_cell.c +++ b/modules/chain/dap_chain_cell.c @@ -290,7 +290,10 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) if (a_chain->is_mapped) { a_cell->map_pos = a_cell->map + sizeof(dap_chain_cell_file_header_t); for (uint64_t l_el_size = 0; a_cell->map_pos < a_cell->map_end && ( l_el_size = *(uint64_t*)a_cell->map_pos ); ++q, a_cell->map_pos += l_el_size) { - a_chain->callback_atom_add(a_chain, (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t)), l_el_size); + dap_hash_fast_t l_atom_hash = {}; + dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t)); + dap_hash_fast(l_atom, l_el_size, &l_atom_hash); + a_chain->callback_atom_add(a_chain, l_atom, l_el_size, &l_atom_hash); } fseek(a_cell->file_storage, a_cell->map_pos - a_cell->map, SEEK_SET); } else { @@ -316,8 +319,12 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell) l_ret = -6; break; } - if ( a_chain->callback_atom_add(a_chain, l_element, l_el_size) != ATOM_ACCEPT ) + dap_hash_fast_t l_atom_hash = {}; + dap_hash_fast(l_element, l_el_size, &l_atom_hash); + dap_chain_atom_verify_res_t l_res = a_chain->callback_atom_add(a_chain, l_element, l_el_size, &l_atom_hash); + if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK) { DAP_DELETE(l_element); + } ++q; } fseek(a_cell->file_storage, l_full_size, SEEK_SET); diff --git a/modules/chain/dap_chain_ch.c b/modules/chain/dap_chain_ch.c index 6b74b128727f49fdf73106d47a271a42120e7549..bc96f36faad0c0c125868d8a69f7f83d32a30948 100644 --- a/modules/chain/dap_chain_ch.c +++ b/modules/chain/dap_chain_ch.c @@ -621,9 +621,12 @@ static bool s_sync_in_chains_callback(void *a_arg) return false; } char *l_atom_hash_str = NULL; + l_atom_hash_str = DAP_NEW_STACK_SIZE(char, DAP_CHAIN_HASH_FAST_STR_SIZE); + dap_hash_fast_t l_atom_hash = {}; + dap_hash_fast(l_atom, l_atom_size, &l_atom_hash); if (s_debug_more) dap_get_data_hash_str_static(l_atom, l_atom_size, l_atom_hash_str); - dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom, l_atom_size); + dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom, l_atom_size, &l_atom_hash); bool l_ack_send = false; switch (l_atom_add_res) { case ATOM_PASS: @@ -642,6 +645,14 @@ static bool s_sync_in_chains_callback(void *a_arg) debug_if(s_debug_more, L_WARNING, "Atom with hash %s for %s:%s rejected", l_atom_hash_str, l_chain->net_name, l_chain->name); break; } + 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: log_it(L_CRITICAL, "Wtf is this ret code? %d", l_atom_add_res); break; diff --git a/modules/chain/dap_chain_cs.c b/modules/chain/dap_chain_cs.c index d61a52a22a9e84e8543cfa1e6d5a7372105bde84..5d5420556ffaac66494005f36fe2f3fde934f0cc 100644 --- a/modules/chain/dap_chain_cs.c +++ b/modules/chain/dap_chain_cs.c @@ -121,7 +121,15 @@ void dap_chain_cs_add (const char * a_cs_str, dap_chain_callback_new_cfg_t a_ca int dap_chain_cs_create(dap_chain_t * a_chain, dap_config_t * a_chain_cfg) { dap_chain_callback_new_cfg_item_t *l_item = NULL; +#if defined(DAP_CHAIN_BLOCKS_TEST) || defined(DAP_LEDGER_TEST) + const char *l_consensus = NULL; + if (a_chain->id.uint64 == 0) + l_consensus = dap_strdup("dag_poa"); + else + l_consensus = dap_strdup("esbocs"); +#else const char *l_consensus = dap_config_get_item_str( a_chain_cfg, "chain", "consensus"); +#endif if(l_consensus) HASH_FIND_STR(s_cs_callbacks, l_consensus, l_item ); if (l_item) { diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h index f0c360640563ecfd161b013d67cee6561e4aca15..cb3f76092c2751259ec4d68e6e26b0488190be37 100644 --- a/modules/chain/include/dap_chain.h +++ b/modules/chain/include/dap_chain.h @@ -61,14 +61,15 @@ typedef struct dap_chain_datum_iter { } dap_chain_datum_iter_t; typedef enum dap_chain_atom_verify_res{ - ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD + ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD, ATOM_FORK } dap_chain_atom_verify_res_t; static const char* const dap_chain_atom_verify_res_str[] = { [ATOM_ACCEPT] = "accepted", [ATOM_PASS] = "skipped", [ATOM_REJECT] = "rejected", - [ATOM_MOVE_TO_THRESHOLD] = "thresholded" + [ATOM_MOVE_TO_THRESHOLD] = "thresholded", + [ATOM_FORK] = "forked" }; typedef enum dap_chain_iter_op { @@ -84,9 +85,9 @@ typedef void (*dap_chain_callback_t)(dap_chain_t *); typedef int (*dap_chain_callback_new_cfg_t)(dap_chain_t *, dap_config_t *); typedef void (*dap_chain_callback_ptr_t)(dap_chain_t *, void * ); -typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t, size_t ); +typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t*); typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_form_treshold_t)(dap_chain_t *, size_t *); -typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t); +typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t*); typedef size_t (*dap_chain_callback_atom_get_hdr_size_t)(void); typedef dap_chain_atom_iter_t * (*dap_chain_callback_atom_iter_create_t)(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from); diff --git a/modules/chain/tests/CMakeLists.txt b/modules/chain/tests/CMakeLists.txt index 6b4acedc87a31503ec16492c47bbe1e8f29ff392..69f2e3f0ffe89e13cbed7675364773a4e26b717f 100755 --- a/modules/chain/tests/CMakeLists.txt +++ b/modules/chain/tests/CMakeLists.txt @@ -7,7 +7,7 @@ file(GLOB DAP_CHAIN_TESTS_SRC *.c) add_executable(${PROJECT_NAME} ${DAP_CHAIN_TESTS_SRC} ${DAP_CHAIN_TESTS_HEADERS}) -target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_wallet) +target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_wallet dap_chain_net_srv_vpn dap_chain_cs_blocks dap_chain_cs_dag_poa) if (DARWIN) target_link_libraries(${PROJECT_NAME} bz2) diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c index 81246a5e86694957a3e518759127c89b17bd0ee8..65ab04d6b278bcaf66ab412c0a8b7561297d46f0 100644 --- a/modules/chain/tests/dap_chain_ledger_tests.c +++ b/modules/chain/tests/dap_chain_ledger_tests.c @@ -4,12 +4,25 @@ #include "dap_cert.h" #include "dap_chain_wallet.h" #include "dap_math_ops.h" +#include "dap_config.h" +#include "dap_chain.h" #include "dap_chain_net.h" +#include "dap_chain_common.h" +#include "dap_chain_net_srv_vpn.h" +#include "dap_chain_net_srv_stake_lock.h" +#include "dap_chain_net_srv_stake_pos_delegate.h" +#include "dap_chain_net_decree.h" +#include "dap_chain_block.h" +#include "dap_chain_cs_blocks.h" +#include "dap_chain_cs_esbocs.h" +#include "dap_chain_cs.h" +#include "dap_chain_cs_dag_poa.h" static const uint64_t s_fee = 2; static const uint64_t s_total_supply = 500; static const uint64_t s_standard_value_tx = 500; -static const char* s_token_ticker = "TestCoins"; +static const char* s_token_ticker = "TestCoin"; +static const char* s_delegated_token_ticker = "mTestCoin"; dap_chain_datum_token_t *dap_ledger_test_create_datum_decl(dap_cert_t *a_cert, size_t *a_token_size, const char *a_token_ticker, uint256_t a_total_supply, @@ -87,26 +100,610 @@ dap_chain_datum_tx_t *dap_ledger_test_create_tx(dap_enc_key_t *a_key_from, dap_c return l_tx; } -void dap_ledger_test_double_spending( - dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t *a_from_key, dap_chain_net_id_t a_net_id) { - dap_print_module_name("dap_ledger_double_spending"); +dap_chain_datum_tx_t *dap_ledger_test_create_tx_full(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, + dap_chain_addr_t *a_addr_to, uint256_t a_value, dap_ledger_t *a_ledger) { + + dap_chain_addr_t l_addr = {0}; + dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id); + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + int l_out_idx = 0; + dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL); + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0); + dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(a_addr_to, a_value); + uint256_t l_change = {}; + SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_change); + dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr, l_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from); + DAP_DEL_Z(l_in); + DAP_DEL_Z(l_out); + return l_tx; +} + +dap_chain_datum_tx_t *dap_ledger_test_create_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, + dap_chain_addr_t *a_addr_to, uint256_t a_value, dap_ledger_t *a_ledger) { + dap_chain_addr_t l_addr = {0}; + dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id); + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + int l_out_idx = 0; + dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL); + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0); + dap_chain_net_srv_uid_t l_srv_uid = {.uint64 = 1}; + dap_chain_net_srv_price_unit_uid_t l_uint_type = {.enm = SERV_UNIT_SEC}; + dap_pkey_t *l_pkey = dap_pkey_from_enc_key(a_key_from); + dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_pay(l_pkey, l_srv_uid, a_value, uint256_0, l_uint_type, NULL, 0); + uint256_t l_change = {}; + SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_change); + dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr, l_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_cond); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from); + DAP_DEL_Z(l_in); + DAP_DEL_Z(l_out_cond); + DAP_DEL_Z(l_out_change); + return l_tx; +} + +dap_chain_datum_tx_t *dap_ledger_test_create_spend_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, + dap_enc_key_t *a_key_to, uint256_t a_value, dap_ledger_t *a_ledger) { + dap_chain_addr_t l_addr = {0}; + dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id); + // get previous transaction + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + // get previous cond out + int l_out_idx = 0; + dap_chain_tx_out_cond_t *l_tx_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_COND, NULL); + + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 1, 0); + + // create conditional output + dap_chain_net_srv_uid_t l_srv_uid = {.uint64 = 1}; + dap_chain_net_srv_price_unit_uid_t l_unit_type = {.enm = SERV_UNIT_SEC}; + dap_pkey_t *l_pkey = dap_pkey_from_enc_key(a_key_from); + uint256_t l_cond_change = {}; + SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_cond_change); + dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_pay(l_pkey, l_tx_prev_out->header.srv_uid, l_cond_change, uint256_0, l_tx_prev_out->subtype.srv_pay.unit, NULL, 0); + + // create receipt + dap_chain_datum_tx_receipt_t * l_receipt = dap_chain_datum_tx_receipt_create(l_srv_uid, l_unit_type, 1, a_value, NULL, 0); + // Sign with our wallet + l_receipt = dap_chain_datum_tx_receipt_sign_add(l_receipt, a_key_to); + l_receipt = dap_chain_datum_tx_receipt_sign_add(l_receipt, a_key_from); + + + // add all items to tx + dap_chain_addr_t l_addr_to = {0}; + dap_chain_addr_fill_from_key(&l_addr_to, a_key_to, a_ledger->net->pub.id); + dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr_to, a_value); + dap_chain_datum_tx_add_item(&l_tx, (byte_t*)l_receipt); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_cond); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_to); + DAP_DEL_Z(l_in_cond); + DAP_DEL_Z(l_out_cond); + DAP_DEL_Z(l_receipt); + DAP_DEL_Z(l_out_change); + return l_tx; +} + +dap_chain_datum_tx_t *dap_ledger_test_create_return_from_tx_cond(dap_chain_hash_fast_t *a_hash_prev, + dap_enc_key_t *a_key_to, dap_ledger_t *a_ledger) { + // get previous transaction + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + // get previous cond out + int l_out_idx = 1; + dap_chain_tx_out_cond_t *l_tx_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_COND, NULL); + + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 1, 0); + + // add all items to tx + dap_chain_addr_t l_addr_to = {0}; + dap_chain_addr_fill_from_key(&l_addr_to, a_key_to, a_ledger->net->pub.id); + dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr_to, l_tx_prev_out->header.value); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_to); + DAP_DEL_Z(l_in_cond); + DAP_DEL_Z(l_out_change); + return l_tx; +} + +dap_chain_datum_tx_t *dap_ledger_test_create_stake_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, uint256_t a_value, dap_ledger_t *a_ledger) { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; + // get previous transaction + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + // get previous cond out + int l_out_idx = 0; + dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL); + + dap_chain_addr_t l_addr_to = {0}; + dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id); + + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0); + + dap_chain_tx_in_ems_t *l_in_ems = DAP_NEW_Z(dap_chain_tx_in_ems_t); + l_in_ems->header.type = TX_ITEM_TYPE_IN_EMS; + l_in_ems->header.token_emission_chain_id.uint64 = 0; + memset(&l_in_ems->header.token_emission_hash, 0, sizeof(l_in_ems->header.token_emission_hash)); + strcpy(l_in_ems->header.ticker, s_delegated_token_ticker); + + dap_time_t a_time_staking = 1; + dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock( + l_uid, a_value, a_time_staking, uint256_0); + + // add all items to tx + uint256_t value_change = {}; + SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &value_change); + dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, value_change, s_token_ticker); + uint256_t a_delegated_value = {}; + MULT_256_COIN(a_value, dap_chain_coins_to_balance("0.1"), &a_delegated_value); + dap_chain_tx_out_ext_t *l_out_delegated = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, a_delegated_value, s_delegated_token_ticker); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_out_cond); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_delegated); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from); + DAP_DEL_Z(l_in); + DAP_DEL_Z(l_in_ems); + DAP_DEL_Z(l_out_change); + DAP_DEL_Z(l_out_delegated); + DAP_DEL_Z(l_tx_out_cond); + + return l_tx; +} + +dap_chain_datum_tx_t *dap_ledger_test_create_unstake_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, uint256_t a_value, dap_ledger_t *a_ledger) { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; + // get previous transaction + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + // get previous cond out + int l_out_idx = 0; + dap_chain_tx_out_cond_t *l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_cond_get(l_tx_prev, + DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, &l_out_idx); + + if(!l_tx_prev_out_cond || l_tx_prev_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK) + return NULL; + + l_out_idx = 4; + dap_chain_tx_out_ext_t *l_tx_prev_out_ext = (dap_chain_tx_out_ext_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_EXT, NULL); + + dap_chain_addr_t l_addr_to = {0}; + dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id); + + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_t *l_in_ext = dap_chain_datum_tx_item_in_create(a_hash_prev, 2); + + dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 0, 0); + dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, l_tx_prev_out_cond->header.value, s_token_ticker); + dap_chain_addr_t l_addr_burning = {0}; + dap_chain_tx_out_ext_t *l_out_burn = dap_chain_datum_tx_item_out_ext_create(&l_addr_burning, l_tx_prev_out_ext->header.value, s_delegated_token_ticker); + + + // add all items to tx + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ext); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_burn); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from); + + DAP_DEL_Z(l_in_ext); + DAP_DEL_Z(l_out_change); + DAP_DEL_Z(l_in_cond); + DAP_DEL_Z(l_out_burn); + + return l_tx; +} + + +int dap_ledger_test_create_reward_decree(dap_chain_t *a_chain, dap_chain_net_id_t a_net_id, uint256_t a_value, dap_cert_t *a_cert) +{ + // Create decree + size_t l_tsd_total_size = sizeof(dap_tsd_t) + sizeof(uint256_t); + size_t l_decree_size = sizeof(dap_chain_datum_decree_t) + l_tsd_total_size; + dap_chain_datum_decree_t *l_decree = DAP_NEW_Z_SIZE(dap_chain_datum_decree_t, l_decree_size); + if (!l_decree) { + return -1; + } + // Fill the header + l_decree->decree_version = DAP_CHAIN_DATUM_DECREE_VERSION; + l_decree->header.ts_created = dap_time_now(); + l_decree->header.type = DAP_CHAIN_DATUM_DECREE_TYPE_COMMON; + l_decree->header.common_decree_params.net_id = a_net_id; + l_decree->header.common_decree_params.chain_id = a_chain->id; + l_decree->header.common_decree_params.cell_id = (dap_chain_cell_id_t){.uint64 = 0}; + l_decree->header.sub_type = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_REWARD; + l_decree->header.data_size = l_tsd_total_size; + // Fill a TSD section + dap_tsd_t *l_tsd = (dap_tsd_t *)l_decree->data_n_signs; + l_tsd->type = DAP_CHAIN_DATUM_DECREE_TSD_TYPE_VALUE; + l_tsd->size = sizeof(uint256_t); + *(uint256_t*)(l_tsd->data) = a_value; + // Sign it + dap_sign_t *l_sign = dap_cert_sign(a_cert, l_decree, l_decree_size, 0); + if (!l_sign) { + DAP_DELETE(l_decree); + return -2; + } + size_t l_sign_size = dap_sign_get_size(l_sign); + l_decree_size += l_sign_size; + l_decree->header.signs_size = l_sign_size; + void *l_decree_rl = DAP_REALLOC(l_decree, l_decree_size); + if (!l_decree_rl) { + DAP_DELETE(l_decree); + return -3; + } else + l_decree = l_decree_rl; + memcpy(l_decree->data_n_signs + l_tsd_total_size, l_sign, l_sign_size); + DAP_DELETE(l_sign); + + // dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_DECREE, l_decree, l_decree_size); + + dap_hash_fast_t l_decree_hash = {}; + dap_hash_fast(l_decree, l_decree_size, &l_decree_hash); + // a_chain->callback_atom_add(); + dap_assert_PIF(dap_chain_net_decree_apply(&l_decree_hash, l_decree, a_chain)==0, "Decree applying:"); + return 0; +} + +/* int dap_ledger_test_create_reward_tx(dap_chain_t *a_chain, dap_enc_key_t *a_key_to, int block_num, dap_hash_fast_t a_block_hash, uint256_t a_value, dap_ledger_t *a_ledger) +{ + + dap_chain_t *l_chain = a_chain; + //add tx + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_pkey_t *l_sign_pkey = dap_pkey_from_enc_key(a_key_to); + dap_hash_fast_t l_sign_pkey_hash; + dap_pkey_get_hash(l_sign_pkey, &l_sign_pkey_hash); + uint256_t l_value_out = uint256_0; + dap_ledger_t *l_ledger = a_ledger; + + uint256_t l_reward_value = l_chain->callback_calc_reward(l_chain, a_block_hash, l_sign_pkey); + dap_assert_PIF(!IS_ZERO_256(l_reward_value), "Reward calculating:"); + dap_assert_PIF(dap_ledger_is_used_reward(l_ledger, &a_block_hash, &l_sign_pkey_hash), "Reward is collected. "); + //add 'in_reward' items + dap_chain_datum_tx_add_in_reward_item(&l_tx, &a_block_hash); + SUM_256_256(l_value_out, l_reward_value, &l_value_out); + + DAP_DELETE(l_sign_pkey); + uint256_t l_net_fee = uint256_0, l_total_fee = uint256_0; + dap_chain_addr_t l_addr_fee = c_dap_chain_addr_blank; + + // Check and apply sovereign tax for this key + uint256_t l_value_tax = {}; + dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(l_chain->net_id, &l_sign_pkey_hash); + if (l_key_item && !IS_ZERO_256(l_key_item->sovereign_tax) && + !dap_chain_addr_is_blank(&l_key_item->sovereign_addr)) { + MULT_256_COIN(l_value_out, l_key_item->sovereign_tax, &l_value_tax); + if (compare256(l_value_tax, l_value_out) < 1) + SUBTRACT_256_256(l_value_out, l_value_tax, &l_value_out); + } + //add 'out' items + if (!IS_ZERO_256(l_value_out)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } + } + if (!IS_ZERO_256(l_value_tax)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_key_item->sovereign_addr, l_value_tax) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } + } + // add 'sign' item + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_sign_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't sign item in transaction fee"); + return NULL; + } + + return 0; +} */ + +void dap_ledger_test_create_delegate_key_approve_decree() +{ + +} + +/*dap_chain_datum_tx_t *dap_ledger_test_create_delegate_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, dap_chain_hash_fast_t *a_stake_tx_hash, + uint256_t a_value, dap_ledger_t *a_ledger) { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID }; + // get previous transaction + dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev); + // get previous cond out + int l_out_idx = 0; + dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL); + + dap_chain_addr_t l_addr_to = {0}; + dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id); + + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0); + + dap_chain_tx_in_ems_t *l_in_ems = DAP_NEW_Z(dap_chain_tx_in_ems_t); + l_in_ems->header.type = TX_ITEM_TYPE_IN_EMS; + l_in_ems->header.token_emission_chain_id.uint64 = 0; + memset(&l_in_ems->header.token_emission_hash, 0, sizeof(l_in_ems->header.token_emission_hash)); + strcpy(l_in_ems->header.ticker, s_delegated_token_ticker); + + uint64_t a_time_staking = 1; + dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake( + l_uid, a_value, a_key_from, ); + + // add all items to tx + uint256_t value_change = {}; + SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &value_change); + SUBTRACT_256_256(value_change, dap_chain_uint256_from(s_fee), &value_change); + dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, value_change, s_token_ticker); + uint256_t a_delegated_value = {}; + MULT_256_COIN(a_value, dap_chain_coins_to_balance("0.1"), &a_delegated_value); + dap_chain_tx_out_ext_t *l_out_delegated = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, a_delegated_value, s_delegated_token_ticker); + dap_chain_tx_out_cond_t *l_cond_fee = dap_chain_datum_tx_item_out_cond_create_fee(dap_chain_uint256_from(s_fee)); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_out_cond); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_cond_fee); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change); + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_delegated); + dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from); + DAP_DEL_Z(l_in); + DAP_DEL_Z(l_cond_fee); + DAP_DEL_Z(l_in_ems); + DAP_DEL_Z(l_out_change); + DAP_DEL_Z(l_out_delegated); + DAP_DEL_Z(l_tx_out_cond); + + return l_tx; +}*/ + + +uint256_t dap_ledger_test_print_balance(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr) +{ + uint256_t l_balance_after = dap_ledger_calc_balance(a_ledger, a_addr, s_token_ticker); + char *l_balanse_str = dap_chain_balance_print(l_balance_after); + dap_test_msg("Balance = %s %s", l_balanse_str, s_token_ticker); + DAP_DELETE(l_balanse_str); + return l_balance_after; +} + +uint256_t dap_ledger_test_print_delegate_balance(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr) +{ + uint256_t l_balance_after = dap_ledger_calc_balance(a_ledger, a_addr, s_delegated_token_ticker); + char *l_balanse_str = dap_chain_balance_print(l_balance_after); + dap_test_msg("Balance = %s %s", l_balanse_str, s_delegated_token_ticker); + DAP_DELETE(l_balanse_str); + return l_balance_after; +} + +int dap_ledger_test_add_new_datum (uint16_t a_datum_type, void* a_datum, size_t a_datum_size, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash) +{ + dap_chain_datum_t* l_new_datum = dap_chain_datum_create(a_datum_type, a_datum, a_datum_size); + size_t l_new_datum_size = a_datum_size + sizeof(l_new_datum->header); + int status = dap_chain_datum_add(a_chain, l_new_datum, l_new_datum_size, a_datum_hash); + dap_assert(status == 0, "Test of transaction adding to ledger:"); + return status; +} + +dap_hash_fast_t dap_ledger_test_add_tx(dap_chain_net_t *a_net, dap_chain_datum_tx_t *a_tx) +{ + dap_chain_t *l_chain_main = dap_chain_net_get_chain_by_name(a_net, "test_chain_main"); + dap_assert(a_tx, "Test of creating tx:"); + size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx); + dap_hash_fast_t l_hash = {}; + dap_hash_fast(a_tx, l_tx_size, &l_hash); + dap_ledger_test_add_new_datum (DAP_CHAIN_DATUM_TX, a_tx, l_tx_size, l_chain_main, &l_hash); + return l_hash; +} + + + +void dap_ledger_test_datums_removing(dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t *a_from_key, dap_chain_net_id_t a_net_id) +{ + dap_print_module_name("dap_ledger_test_datums_removing"); dap_cert_t *l_first_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*H", 18); + dap_chain_addr_t l_addr = {0}; + dap_chain_addr_fill_from_key(&l_addr, a_from_key, a_net_id); + uint256_t l_balance_before = dap_ledger_test_print_balance(a_ledger, &l_addr); dap_chain_addr_t l_addr_first = {0}; dap_chain_addr_fill_from_key(&l_addr_first, l_first_cert->enc_key, a_net_id); + dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id); + dap_chain_t *l_chain_main = dap_chain_net_get_chain_by_name(l_net, "test_chain_main"); + + // Check common tx removing + dap_chain_datum_tx_t *l_first_tx = dap_ledger_test_create_tx_full(a_from_key, a_prev_hash, &l_addr_first, dap_chain_uint256_from(1U), l_net->pub.ledger); + dap_chain_hash_fast_t l_first_tx_hash = dap_ledger_test_add_tx(l_net, l_first_tx); + + dap_ledger_test_print_balance(a_ledger, &l_addr); + + dap_chain_datum_tx_t *l_second_tx = dap_ledger_test_create_tx_full(a_from_key, &l_first_tx_hash, &l_addr_first, dap_chain_uint256_from(1U), l_net->pub.ledger); + dap_assert(l_second_tx, "Test of creating second tx:"); + dap_chain_hash_fast_t l_second_tx_hash = {0}; + dap_hash_fast(l_second_tx, dap_chain_datum_tx_get_size(l_second_tx), &l_second_tx_hash); + dap_assert(!dap_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false), "Test of second transaction adding to ledger:"); + dap_ledger_test_print_balance(a_ledger, &l_addr); + + // try to remove spent tx + dap_assert(dap_ledger_tx_remove(a_ledger, l_first_tx, &l_first_tx_hash), "Test of removing spent transaction:"); + dap_assert(!dap_ledger_tx_remove(a_ledger, l_second_tx, &l_second_tx_hash), "Test of removing second transaction:"); + dap_assert(!dap_ledger_tx_remove(a_ledger, l_first_tx, &l_first_tx_hash), "Test of removing first transaction:"); + uint256_t l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:"); + + // check cond tx removing + { + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash, + &l_addr_first, dap_chain_uint256_from(1U),a_ledger); + dap_assert_PIF(l_cond_tx, "Test of creating conditional transaction:"); + dap_chain_hash_fast_t l_cond_tx_hash = {0}; + dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_first_tx), &l_cond_tx_hash); + dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Test of conditional transaction adding to ledger:"); + dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of conditional transaction removing from ledger:"); + l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:"); + } + + // try to spend cond tx + { + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash,&l_addr_first, dap_chain_uint256_from(2U),a_ledger); + dap_assert_PIF(l_cond_tx, "Test of creating conditional transaction:"); + dap_hash_fast_t l_cond_tx_hash = {}; + dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash); + dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Test of conditional transaction adding to ledger:"); + dap_ledger_test_print_balance(a_ledger, &l_addr); + + dap_cert_t *l_cond_spender_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*q", 18); + dap_chain_addr_t l_cond_spender_addr = {0}; + dap_chain_addr_fill_from_key(&l_cond_spender_addr, l_cond_spender_cert->enc_key, a_net_id); + uint256_t l_cond_spending_balance_before = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr); + dap_chain_datum_tx_t *l_cond_spendind_tx = dap_ledger_test_create_spend_tx_cond(a_from_key, &l_cond_tx_hash, l_cond_spender_cert->enc_key, dap_chain_uint256_from(1U),a_ledger); + dap_chain_hash_fast_t l_spend_cond_tx_hash = {0}; + dap_hash_fast(l_cond_spendind_tx, dap_chain_datum_tx_get_size(l_cond_spendind_tx), &l_spend_cond_tx_hash); + dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_spendind_tx, &l_spend_cond_tx_hash, false), "Test adding of transaction spending to a conditional transaction to ledger:"); + uint256_t l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr); + dap_assert(!compare256(l_cond_spending_balance_after, dap_chain_uint256_from(1U)), "Check balance after spending:"); + dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr); + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_spendind_tx, &l_spend_cond_tx_hash), "Test removing of transaction spending to a conditional transaction to ledger:"); + l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr); + dap_assert(!compare256(l_cond_spending_balance_before, l_cond_spending_balance_after), "Test spender balance after removing:"); + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of conditional transaction removing from ledger:"); + l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:"); + } + + // try to return funds from conditional tx and delete this tx + { + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash, &l_addr_first, dap_chain_uint256_from(2U),a_ledger); + dap_hash_fast_t l_cond_tx_hash = {}; + dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash); + dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Adding of cond transaction to ledger is"); + + dap_cert_t *l_cond_spending_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*q", 18); + dap_chain_addr_t l_cond_spending_addr = {0}; + dap_chain_addr_fill_from_key(&l_cond_spending_addr, l_cond_spending_cert->enc_key, a_net_id); + uint256_t l_cond_spending_balance_before = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr); + dap_chain_datum_tx_t *l_cond_returning_tx = dap_ledger_test_create_return_from_tx_cond(&l_cond_tx_hash, a_from_key ,a_ledger); + dap_chain_hash_fast_t l_cond_returning_tx_hash = {0}; + dap_hash_fast(l_cond_returning_tx, dap_chain_datum_tx_get_size(l_cond_returning_tx), &l_cond_returning_tx_hash); + int err_code = dap_ledger_tx_add(a_ledger, l_cond_returning_tx, &l_cond_returning_tx_hash, false); + printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code)); + dap_assert(!err_code, "Returning of funds from cond transaction is"); + uint256_t l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr); + dap_assert(compare256(l_cond_spending_balance_after, dap_chain_uint256_from(2U)), "Returning of funds from conditional tx from ledger testing"); + + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_returning_tx, &l_cond_returning_tx_hash), "Tx cond removing from ledger is "); + l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr); + dap_assert(!compare256(l_cond_spending_balance_before, l_cond_spending_balance_after), "Removing conditional tx from ledger testing"); + + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Tx cond removing from ledger is "); + l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before, l_cond_spending_balance_after), "Removing conditional tx from ledger testing"); + } + + // check stake adding and removing + { + dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_stake_tx_cond(a_from_key, a_prev_hash, dap_chain_uint256_from(20U), a_ledger); + dap_hash_fast_t l_cond_tx_hash = {}; + dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash); + int err_code = dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false); + printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code)); + dap_assert(!err_code, "Adding of stake cond transaction to ledger is"); + + dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of stake conditional transaction removing from ledger:"); + l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating stake transactions and after removing them. Must be equal:") + } + + // check stake and unstake adding and removing + { + // Create stake lock tx + dap_chain_datum_tx_t *l_stake_cond_tx = dap_ledger_test_create_stake_tx_cond(a_from_key, a_prev_hash, dap_chain_uint256_from(20U), a_ledger); + dap_hash_fast_t l_stake_cond_tx_hash = {}; + dap_hash_fast(l_stake_cond_tx, dap_chain_datum_tx_get_size(l_stake_cond_tx), &l_stake_cond_tx_hash); + int err_code = dap_ledger_tx_add(a_ledger, l_stake_cond_tx, &l_stake_cond_tx_hash, false); + printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code)); + dap_assert(!err_code, "Adding of stake cond transaction to ledger is"); + sleep(3); + // Create stake unlock tx + uint256_t l_balance_before_unstaking = dap_ledger_test_print_balance(a_ledger, &l_addr); + uint256_t l_balance_delegated_before_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_delegated_before_unstaking, dap_chain_uint256_from(2U)), "Compare delegated token balance before creating unstake transactions:") + + dap_chain_datum_tx_t *l_unstake_cond_tx = dap_ledger_test_create_unstake_tx_cond(a_from_key, &l_stake_cond_tx_hash, dap_chain_uint256_from(20U), a_ledger); + dap_hash_fast_t l_unstake_cond_tx_hash = {}; + dap_hash_fast(l_unstake_cond_tx, dap_chain_datum_tx_get_size(l_stake_cond_tx), &l_unstake_cond_tx_hash); + err_code = dap_ledger_tx_add(a_ledger, l_unstake_cond_tx, &l_unstake_cond_tx_hash, false); + printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code)); + dap_assert(!err_code, "Adding of unstake cond transaction to ledger is"); + uint256_t l_balance_delegated_after_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_delegated_after_unstaking, uint256_0), "Compare delegated token balance after creating unstake transactions:") + + err_code = dap_ledger_tx_remove(a_ledger, l_unstake_cond_tx, &l_unstake_cond_tx_hash); + printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code)); + dap_assert(!err_code, "Test of unstake conditional transaction removing from ledger:"); + l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_delegated_after_unstaking, uint256_0), "Compare delegated token balance after removing unstake transaction:") + uint256_t l_balance_delegated_after_removing_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr); + dap_assert(!compare256(l_balance_before_unstaking, l_balance_after), "Compare balance after creating unstake transactions and after removing them. Must be equal:") + + // Check delegation + + + + + // Check rewards + + + } + + // Check vote removing + { + + } + + // Check voting removing + { + + } + + // Check exchanger + { + + } + + +} + +dap_hash_fast_t dap_ledger_test_double_spending( + dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t *a_from_key, dap_chain_addr_t a_addr_to, dap_chain_net_id_t a_net_id) { + dap_print_module_name("dap_ledger_double_spending"); dap_chain_datum_tx_t *l_first_tx = dap_ledger_test_create_tx(a_from_key, a_prev_hash, - &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee)); + &a_addr_to, dap_chain_uint256_from(s_standard_value_tx - s_fee)); dap_assert_PIF(l_first_tx, "Can't creating base transaction."); dap_chain_hash_fast_t l_first_tx_hash = {0}; dap_hash_fast(l_first_tx, dap_chain_datum_tx_get_size(l_first_tx), &l_first_tx_hash); - dap_assert_PIF(!dap_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false), "Can't added first transaction on ledger"); + dap_assert_PIF(!dap_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false), "Can't add first transaction on ledger"); //uint256_t l_balance = dap_ledger_calc_balance(a_ledger, &l_addr_first, s_token_ticker); // Second tx dap_chain_datum_tx_t *l_second_tx = dap_ledger_test_create_tx(a_from_key, a_prev_hash, - &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee)); + &a_addr_to, dap_chain_uint256_from(s_standard_value_tx - s_fee)); dap_chain_hash_fast_t l_second_tx_hash = {0}; dap_hash_fast(l_second_tx, dap_chain_datum_tx_get_size(l_second_tx), &l_second_tx_hash); dap_assert_PIF(dap_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false), "Added second transaction on ledger"); dap_pass_msg("The verification test is not able to make two normal transactions per one basic transaction."); + return l_first_tx_hash; } void dap_ledger_test_excess_supply(dap_ledger_t *a_ledger, dap_cert_t *a_cert, dap_chain_addr_t *a_addr){ @@ -366,20 +963,43 @@ void dap_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a_cert, } void dap_ledger_test_run(void){ + dap_set_appname("cellframe-node"); + dap_assert_PIF(dap_chain_cs_blocks_init() == 0, "Initialization of dap consensus block: "); + dap_assert_PIF(dap_chain_cs_esbocs_init() == 0, "Initialization of esbocs: "); + dap_assert_PIF(dap_chain_cs_dag_init() == 0, "Initialization of esbocs: "); + dap_assert_PIF(dap_chain_cs_dag_poa_init() == 0, "Initialization of esbocs: "); + dap_chain_net_srv_stake_lock_init(); dap_chain_net_srv_stake_pos_delegate_init(); - dap_chain_net_id_t l_iddn = {0}; - sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64); + dap_assert_PIF(!dap_chain_net_srv_init(), "Srv initializstion"); + dap_print_module_name("dap_ledger"); uint16_t l_flags = 0; l_flags |= DAP_LEDGER_CHECK_TOKEN_EMISSION; - dap_chain_net_t *l_net = DAP_NEW_Z(dap_chain_net_t); - l_net->pub.id = l_iddn; - l_net->pub.native_ticker = s_token_ticker; - l_net->pub.name = "Snet"; + dap_chain_net_test_init(); + dap_chain_net_id_t l_iddn = {.uint64 = 0}; + sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64); + dap_chain_net_t *l_net = dap_chain_net_by_id(l_iddn); dap_ledger_t *l_ledger = dap_ledger_create(l_net, l_flags); + l_net->pub.ledger = l_ledger; + + dap_chain_t *l_chain_zero = dap_chain_create(l_net->pub.name, "test_chain_zerochain", l_net->pub.id, (dap_chain_id_t){.uint64 = 0}); + dap_config_t l_cfg = {}; + dap_assert_PIF(dap_chain_cs_create(l_chain_zero, &l_cfg) == 0, "Chain cs dag_poa creating: "); + DL_APPEND(l_net->pub.chains, l_chain_zero); + + dap_chain_t *l_chain_main = dap_chain_create(l_net->pub.name, "test_chain_main", l_net->pub.id, (dap_chain_id_t){.uint64 = 1}); + dap_assert_PIF(dap_chain_cs_create(l_chain_main, &l_cfg) == 0, "Chain esbocs cs creating: "); + DL_APPEND(l_net->pub.chains, l_chain_main); + + dap_assert_PIF(!dap_chain_net_decree_init(l_net), "Decree initialization:"); + char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf"; size_t l_seed_ph_size = strlen(l_seed_ph); dap_cert_t *l_cert = dap_cert_generate_mem_with_seed("testCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, l_seed_ph, l_seed_ph_size); + + dap_assert_PIF(dap_ledger_test_create_reward_decree(l_chain_main, l_net->pub.id, dap_chain_uint256_from(2), l_cert)==0, "Reward decree creating:"); + + size_t l_token_decl_size = 0; dap_chain_datum_token_t *l_token_decl = dap_ledger_test_create_datum_decl(l_cert, &l_token_decl_size, s_token_ticker, @@ -401,6 +1021,20 @@ void dap_ledger_test_run(void){ int l_emi_check = dap_ledger_token_emission_add_check(l_ledger, (byte_t*)l_emi_sign, l_emi_size, &l_emi_hash); dap_assert_PIF(l_emi_check == 0, "check emission for add in ledger"); dap_assert_PIF(!dap_ledger_token_emission_add(l_ledger, (byte_t*)l_emi_sign, l_emi_size, &l_emi_hash, false), "Added emission in ledger"); + + // Declarate delegated token + dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section; + strcpy((char *)l_tsd_section.ticker_token_from, s_token_ticker); + l_tsd_section.emission_rate = dap_chain_coins_to_balance("0.1");// TODO: 'm' 1:10 tokens + dap_tsd_t * l_tsd = dap_tsd_create_scalar(DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK, l_tsd_section); + l_token_decl = dap_ledger_test_create_datum_decl(l_cert, &l_token_decl_size, s_delegated_token_ticker, + uint256_0, (byte_t*)l_tsd, dap_tsd_size(l_tsd), DAP_CHAIN_DATUM_TOKEN_FLAG_NONE); + dap_assert_PIF(l_token_decl || l_token_decl_size == 0, "Generate delegated token declaration."); + l_check_added_decl_token = 0; + l_check_added_decl_token = dap_ledger_token_decl_add_check(l_ledger, l_token_decl, l_token_decl_size); + dap_assert_PIF(l_check_added_decl_token == 0, "Checking whether it is possible to add a token declaration to ledger."); + dap_assert_PIF(!dap_ledger_token_add(l_ledger, l_token_decl, l_token_decl_size), "Adding token declaration to ledger."); + //first base tx dap_chain_datum_tx_t *l_base_tx = dap_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert); size_t l_base_tx_size = dap_chain_datum_tx_get_size(l_base_tx); @@ -414,7 +1048,7 @@ void dap_ledger_test_run(void){ SUM_256_256(l_balance,l_fee,&l_balance); dap_assert_PIF(!compare256(l_balance, l_balance_example), "Checking the availability of the necessary balance " "on the wallet after the first transaction."); - dap_pass_msg("Validation of the declaration of the tocen, creation of an emission and a basic transaction using this in the ledger."); + dap_pass_msg("Validation of the declaration of the token, creation of an emission and a basic transaction using this in the ledger."); //second base tx dap_chain_datum_tx_t *l_base_tx_second = dap_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert); size_t l_base_tx_size2 = dap_chain_datum_tx_get_size(l_base_tx_second); @@ -428,8 +1062,15 @@ void dap_ledger_test_run(void){ } else { dap_fail("Checking for a failure to add a second base transaction for the same issue to the ledger."); } - dap_ledger_test_double_spending(l_ledger, &l_hash_btx, l_cert->enc_key, l_iddn); + + dap_cert_t *l_first_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*L", 18); + dap_chain_addr_t l_addr_first = {0}; + dap_chain_addr_fill_from_key(&l_addr_first, l_first_cert->enc_key, l_iddn); + dap_hash_fast_t l_first_tx_hash = dap_ledger_test_double_spending(l_ledger, &l_hash_btx, l_cert->enc_key, l_addr_first, l_iddn); dap_ledger_test_excess_supply(l_ledger, l_cert, &l_addr); + //dap_ledger_test_datums_adding(l_ledger, &l_hash_btx, l_cert->enc_key, l_iddn);//check adding all types of datums into ledger + dap_ledger_test_datums_removing(l_ledger, &l_first_tx_hash, l_first_cert->enc_key, l_iddn);//check removing all types of datums from ledger dap_ledger_test_write_back_list(l_ledger, l_cert, l_iddn); - + + } diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c index ff58899f5bd79b9a33e03c6f4d39e9fecaaaba8b..86ad365619ef305be5fdf0db46b769d5c9e9fa2c 100644 --- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c +++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c @@ -38,7 +38,7 @@ along with any CellFrame SDK based project. If not, see <http://www.gnu.org/lic #include "dap_stream_ch_chain_net_srv.h" #include "dap_stream_ch_chain_net_srv_pkt.h" #include "dap_stream_ch_proc.h" -#include "dap_stream_ch_chain_net_srv.h" + #define LOG_TAG "dap_stream_ch_chain_net_srv" #define SRV_PAY_GDB_GROUP "local.srv_pay" @@ -273,11 +273,14 @@ char *dap_stream_ch_chain_net_srv_create_statistic_report() return dap_string_free(l_ret, false); } -void dap_stream_ch_chain_net_srv_tx_cond_added_cb(UNUSED_ARG void *a_arg, UNUSED_ARG dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx) +void dap_stream_ch_chain_net_srv_tx_cond_added_cb(UNUSED_ARG void *a_arg, UNUSED_ARG dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode) { // sanity check dap_return_if_pass(!a_tx); // func work + if(a_opcode != DAP_LEDGER_NOTIFY_OPCODE_ADDED) + return; + dap_chain_net_srv_grace_usage_t *l_item = NULL; dap_hash_fast_t l_tx_cond_hash = {0}; dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL); diff --git a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h index 7f1970fb4fecfd180da2186ab7d600deec7fab93..82bc5ee1acd098b474e675f1c4fa7a5a8d314422 100644 --- a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h +++ b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h @@ -58,5 +58,5 @@ typedef struct dap_stream_ch_chain_net_srv { int dap_stream_ch_chain_net_srv_init(dap_chain_net_srv_t *a_srv); -void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx); +void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode); char *dap_stream_ch_chain_net_srv_create_statistic_report(); diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index 882801198265c0f878af36cbcde027b0b27b8175..6f5b32842a2ad59997ee77c6532bf514e14674ae 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -272,7 +272,7 @@ dap_chain_tx_in_ems_t *dap_chain_datum_tx_item_in_ems_create(dap_chain_id_t a_id } l_item->header.type = TX_ITEM_TYPE_IN_EMS; l_item->header.token_emission_chain_id.uint64 = a_id.uint64; - l_item->header.token_emission_hash = *a_datum_token_hash;; + l_item->header.token_emission_hash = *a_datum_token_hash; strncpy(l_item->header.ticker, a_ticker, sizeof(l_item->header.ticker) - 1); return l_item; } diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c index 00edeaf8229419998365351c91a0f804e3eb8324..d8d9d41f1689f1344cf949be9f96d332152c5ffe 100644 --- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c +++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c @@ -363,6 +363,7 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg) dap_chain_cs_dag_poa_pvt_t *l_poa_pvt = PVT(l_poa); pthread_rwlock_init(&l_poa_pvt->rounds_rwlock, NULL); // PoA rounds +#ifndef DAP_LEDGER_TEST l_poa_pvt->confirmations_timeout = dap_config_get_item_uint32_default(a_chain_cfg,"dag-poa","confirmations_timeout",600); l_poa_pvt->auto_confirmation = dap_config_get_item_bool_default(a_chain_cfg,"dag-poa","auto_confirmation",true); l_poa_pvt->auto_round_complete = dap_config_get_item_bool_default(a_chain_cfg,"dag-poa","auto_round_complete",true); @@ -406,6 +407,15 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg) } } +#else + l_poa_pvt->auth_certs_count = 1; + l_poa_pvt->auth_certs = DAP_NEW_Z_SIZE ( dap_cert_t *, l_poa_pvt->auth_certs_count * sizeof(dap_cert_t *)); + char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf"; + size_t l_seed_ph_size = strlen(l_seed_ph); + dap_cert_t *l_cert = dap_cert_generate_mem_with_seed("testCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, l_seed_ph, l_seed_ph_size); + l_poa_pvt->auth_certs[0] = l_cert; +#endif + return 0; } @@ -620,7 +630,7 @@ static bool s_callback_round_event_to_chain_callback_get_round_item(dap_global_d l_dag->round_completed = dap_max(l_new_atom->header.round_id, l_dag->round_current); int l_verify_datum = dap_chain_net_verify_datum_for_add(l_dag->chain, l_datum, &l_chosen_item->round_info.datum_hash); if (!l_verify_datum) { - dap_chain_atom_verify_res_t l_res = l_dag->chain->callback_atom_add(l_dag->chain, l_new_atom, l_event_size); + dap_chain_atom_verify_res_t l_res = l_dag->chain->callback_atom_add(l_dag->chain, l_new_atom, l_event_size, &l_chosen_item->round_info.datum_hash); if (l_res == ATOM_ACCEPT) s_poa_round_clean(l_dag->chain); log_it(L_INFO, "Event %s from round %"DAP_UINT64_FORMAT_U" %s", diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index 948fe73c2f8f6237b3d57119795ed7758fef3a95..3be2d5eac35c7445781ffcfdcb8002bc58eb25ac 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -1588,7 +1588,7 @@ 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) == ATOM_ACCEPT) { + if (l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size, a_candidate_hash) == ATOM_ACCEPT) { // 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); @@ -1682,7 +1682,7 @@ static bool s_session_candidate_to_chain(dap_chain_esbocs_session_t *a_session, return false; } bool res = false; - dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, a_candidate, a_candidate_size); + dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, a_candidate, a_candidate_size, a_candidate_hash); const char *l_candidate_hash_str = dap_chain_hash_fast_to_str_static(a_candidate_hash); switch (l_res) { case ATOM_ACCEPT: diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index e0068e9e6ffa304996f2db05713322d9fd8eb46f..26c509a75ba995ee3ae9c84e97c7ce30d185f073 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -64,9 +64,14 @@ typedef struct dap_ledger_verificator { int subtype; // hash key dap_ledger_verificator_callback_t callback; dap_ledger_updater_callback_t callback_added; + dap_ledger_updater_callback_t callback_deleted; UT_hash_handle hh; } dap_ledger_verificator_t; +typedef struct dap_chain_ledger_votings_callbacks{ + dap_chain_ledger_voting_callback_t voting_callback; + dap_chain_ledger_voting_delete_callback_t voting_delete_callback; +} dap_chain_ledger_votings_callbacks_t; typedef struct dap_ledger_service_info { dap_chain_net_srv_uid_t service_uid; // hash key char tag_str[32]; // tag string name @@ -80,7 +85,7 @@ static dap_ledger_service_info_t *s_services; static pthread_rwlock_t s_verificators_rwlock; static pthread_rwlock_t s_services_rwlock; -static dap_chain_ledger_voting_callback_t s_voting_callback; +static dap_chain_ledger_votings_callbacks_t s_voting_callbacks; #define MAX_OUT_ITEMS 10 @@ -363,7 +368,7 @@ static int s_sort_ledger_tx_item(dap_ledger_tx_item_t* a, dap_ledger_tx_item_t* static size_t s_threshold_emissions_max = 1000; static size_t s_threshold_txs_max = 10000; -static bool s_debug_more = false; +static bool s_debug_more = true; static size_t s_threshold_free_timer_tick = 900000; // 900000 ms = 15 minutes. struct json_object *wallet_info_json_collect(dap_ledger_t *a_ledger, dap_ledger_wallet_balance_t* a_bal); @@ -1203,14 +1208,18 @@ static bool s_ledger_token_supply_check(dap_ledger_token_item_t *a_token_item, u return s_ledger_token_supply_check_unsafe(a_token_item, a_value); } -static bool s_ledger_token_supply_check_update(dap_ledger_t *a_ledger, dap_ledger_token_item_t *a_token_item, uint256_t a_value) +static bool s_ledger_token_supply_check_update(dap_ledger_t *a_ledger, dap_ledger_token_item_t *a_token_item, uint256_t a_value, bool a_for_removing) { assert(a_token_item); - if (IS_ZERO_256(a_token_item->total_supply) || IS_ZERO_256(a_value)) + if ((IS_ZERO_256(a_token_item->total_supply) || IS_ZERO_256(a_value))) return true; - if (!s_ledger_token_supply_check_unsafe(a_token_item, a_value)) + if (!s_ledger_token_supply_check_unsafe(a_token_item, a_value) && !a_for_removing) return false; - int l_overflow = SUBTRACT_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply); + int l_overflow = false; + if(a_for_removing) + l_overflow = SUM_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply); + else + l_overflow = SUBTRACT_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply); assert(!l_overflow); const char *l_balance; dap_uint256_to_char(a_token_item->current_supply, &l_balance); log_it(L_NOTICE, "New current supply %s for token %s", l_balance, a_token_item->ticker); @@ -3063,7 +3072,7 @@ int dap_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emissi } //Update value in ledger memory object if (!s_ledger_token_supply_check_update(a_ledger, l_token_item, - l_token_emission_item->datum_token_emission->hdr.value)) { + l_token_emission_item->datum_token_emission->hdr.value, false)) { DAP_DELETE(l_token_emission_item->datum_token_emission); DAP_DELETE(l_token_emission_item); return DAP_LEDGER_EMISSION_ADD_CHECK_VALUE_EXEEDS_CURRENT_SUPPLY; @@ -3502,7 +3511,6 @@ dap_hash_fast_t* dap_ledger_get_first_chain_tx_hash(dap_ledger_t *a_ledger, dap_ dap_chain_tx_out_cond_t *l_out_cond_temp = dap_chain_datum_tx_out_cond_get(l_prev_tx_temp, l_type, NULL); if (l_out_cond_temp){ l_item_idx = l_in_cond_temp->header.tx_out_prev_idx; - l_hash = l_in_cond_temp->header.tx_prev_hash; } l_prev_tx = l_prev_tx_temp; @@ -3825,13 +3833,14 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_list_t **a_list_tx_out, char **a_main_ticker, dap_chain_net_srv_uid_t *a_tag, - dap_chain_tx_tag_action_type_t *a_action) + dap_chain_tx_tag_action_type_t *a_action, + bool a_check_for_removing) { if (!a_tx) { log_it(L_DEBUG, "NULL transaction, check broken"); return DAP_LEDGER_TX_CHECK_NULL_TX; } - if (!dap_chain_net_get_load_mode(a_ledger->net) && !a_from_threshold) { + if (!dap_chain_net_get_load_mode(a_ledger->net) && !a_from_threshold && !a_check_for_removing) { dap_ledger_tx_item_t *l_ledger_item; pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock); HASH_FIND(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_ledger_item); @@ -3926,7 +3935,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_tx_in_ems_t *l_in_ems_check = l_iter->data; if (l_tx_in_ems != l_in_ems_check && l_in_ems_check->header.type == TX_ITEM_TYPE_IN_EMS && - dap_hash_fast_compare(&l_in_ems_check->header.token_emission_hash, l_emission_hash)) { + dap_hash_fast_compare(&l_in_ems_check->header.token_emission_hash, l_emission_hash) && !a_check_for_removing) { debug_if(s_debug_more, L_ERROR, "Emission output already used in current tx"); l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX; break; @@ -3941,7 +3950,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, if (!dap_hash_fast_is_blank(l_emission_hash)) { dap_hash_fast_t cur_tx_hash; dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &cur_tx_hash); - if (!dap_hash_fast_is_blank(&l_stake_lock_emission->tx_used_out)) { + if (!dap_hash_fast_is_blank(&l_stake_lock_emission->tx_used_out) && !a_check_for_removing) { if (!dap_hash_fast_compare(&cur_tx_hash, &l_stake_lock_emission->tx_used_out)) debug_if(s_debug_more, L_WARNING, "stake_lock_emission already present in cache for IN_EMS [%s]", l_token); else @@ -3952,7 +3961,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, l_tx_stake_lock = dap_ledger_tx_find_by_hash(a_ledger, l_emission_hash); } else { // 2. The only allowed item with girdled emission - if (l_girdled_ems_used) { + if (l_girdled_ems_used && !a_check_for_removing) { debug_if(s_debug_more, L_WARNING, "stake_lock_emission is used out for IN_EMS [%s]", l_token); l_err_num = DAP_LEDGER_TX_CHECK_STAKE_LOCK_IN_EMS_ALREADY_USED; break; @@ -4077,7 +4086,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, l_bound_item->type = TX_ITEM_TYPE_IN_EMS_LOCK; } else if ( (l_emission_item = s_emission_item_find(a_ledger, l_token, l_emission_hash, &l_bound_item->token_item)) ) { // 3. Check AUTH token emission - if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out)) { + if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out) && !a_check_for_removing) { debug_if(s_debug_more, L_WARNING, "Emission for IN_EMS [%s] is already used", l_tx_in_ems->header.ticker); l_err_num = DAP_LEDGER_TX_CHECK_IN_EMS_ALREADY_USED; break; @@ -4098,7 +4107,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_tx_in_reward_t *l_in_reward_check = l_iter->data; if (l_tx_in_reward != l_in_reward_check && l_in_reward_check->type == TX_ITEM_TYPE_IN_REWARD && - dap_hash_fast_compare(&l_in_reward_check->block_hash, l_block_hash)) { + dap_hash_fast_compare(&l_in_reward_check->block_hash, l_block_hash) && !a_check_for_removing) { debug_if(s_debug_more, L_ERROR, "Reward for this block sign already used in current tx"); l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX; break; @@ -4121,7 +4130,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, // 3. Check if already spent reward dap_ledger_reward_key_t l_search_key = { .block_hash = *l_block_hash, .sign_pkey_hash = l_tx_first_sign_pkey_hash }; dap_ledger_reward_item_t *l_reward_item = s_find_reward(a_ledger, &l_search_key); - if (l_reward_item) { + if (l_reward_item && !a_check_for_removing) { l_err_num = DAP_LEDGER_TX_CHECK_REWARD_ITEM_ALREADY_USED; char l_block_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE], l_sign_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE], @@ -4157,7 +4166,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, l_err_num = DAP_LEDGER_TX_CHECK_TICKER_NOT_FOUND; break; } - if (!s_ledger_token_supply_check(l_token_item, l_value)) { + if (!s_ledger_token_supply_check(l_token_item, l_value) && !a_check_for_removing) { l_err_num = DAP_LEDGER_TX_CHECK_TOKEN_EMS_VALUE_EXEEDS_CUR_SUPPLY; break; } @@ -4186,7 +4195,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, if (l_tx_in != l_in_check && l_in_check->header.type == TX_ITEM_TYPE_IN && l_in_check->header.tx_out_prev_idx == l_tx_prev_out_idx && - dap_hash_fast_compare(&l_in_check->header.tx_prev_hash, l_tx_prev_hash)) { + dap_hash_fast_compare(&l_in_check->header.tx_prev_hash, l_tx_prev_hash) && !a_check_for_removing) { debug_if(s_debug_more, L_ERROR, "This previous tx output already used in current tx"); l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX; break; @@ -4204,7 +4213,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, if (l_tx_in_cond != l_in_cond_check && l_in_cond_check->header.type == TX_ITEM_TYPE_IN_COND && l_in_cond_check->header.tx_out_prev_idx == l_tx_prev_out_idx && - dap_hash_fast_compare(&l_in_cond_check->header.tx_prev_hash, l_tx_prev_hash)) { + dap_hash_fast_compare(&l_in_cond_check->header.tx_prev_hash, l_tx_prev_hash) && !a_check_for_removing) { debug_if(s_debug_more, L_ERROR, "This previous tx output already used in current tx"); l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX; break; @@ -4218,11 +4227,11 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, l_tx_prev = s_find_datum_tx_by_hash(a_ledger, l_tx_prev_hash, &l_item_out, false); char l_tx_prev_hash_str[DAP_HASH_FAST_STR_SIZE]; dap_hash_fast_to_str(l_tx_prev_hash, l_tx_prev_hash_str, DAP_HASH_FAST_STR_SIZE); - if (!l_tx_prev) { // Unchained transaction or previous TX was already spent and removed from ledger + if (!l_tx_prev && !a_check_for_removing) { // Unchained transaction or previous TX was already spent and removed from ledger debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str); l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS; break; - } else if (l_item_out->cache_data.ts_spent) { + } else if (l_item_out->cache_data.ts_spent && !a_check_for_removing) { l_err_num = DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED; debug_if(s_debug_more, L_WARNING, "All 'out' items of previous tx %s were already spent", l_tx_prev_hash_str); break; @@ -4234,7 +4243,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, // 2. Check if out in previous transaction has spent dap_hash_fast_t l_spender = {}; - if (s_ledger_tx_hash_is_used_out_item(l_item_out, l_tx_prev_out_idx, &l_spender)) { + if (s_ledger_tx_hash_is_used_out_item(l_item_out, l_tx_prev_out_idx, &l_spender) && !a_check_for_removing) { l_err_num = DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED; char l_hash[DAP_CHAIN_HASH_FAST_STR_SIZE]; dap_chain_hash_fast_to_str(&l_spender, l_hash, sizeof(l_hash)); @@ -4648,10 +4657,11 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, } } + dap_list_t *l_items_voting; if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL))) { - if (s_voting_callback){ - if (!s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, false)){ + if (s_voting_callbacks.voting_callback){ + if (!s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, false)){ debug_if(s_debug_more, L_WARNING, "Verificator check error for voting."); l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE; } @@ -4661,8 +4671,8 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, } dap_list_free(l_items_voting); }else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL))) { - if (s_voting_callback){ - if (!s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, false)){ + if (s_voting_callbacks.voting_callback){ + if (!s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, false)){ debug_if(s_debug_more, L_WARNING, "Verificator check error for vote."); l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE; } @@ -4717,7 +4727,7 @@ int dap_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, } int l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_datum_hash, - false, NULL, NULL, NULL, NULL, NULL); + false, NULL, NULL, NULL, NULL, NULL, false); if(s_debug_more) { char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; dap_chain_hash_fast_to_str(a_datum_hash, l_tx_hash_str, sizeof(l_tx_hash_str)); @@ -4809,7 +4819,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha if( (l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_tx_hash, a_from_threshold, &l_list_bound_items, &l_list_tx_out, - &l_main_token_ticker, &l_tag, &l_action))) { + &l_main_token_ticker, &l_tag, &l_action, false))) { if (l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS || l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION) { if (!l_from_threshold) { @@ -4889,7 +4899,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha } if ((l_type == TX_ITEM_TYPE_IN_EMS_LOCK || l_type == TX_ITEM_TYPE_IN_REWARD) && - !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value)) + !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value, false)) log_it(L_ERROR, "Insufficient supply for token %s", l_bound_item->token_item->ticker); switch (l_type) { @@ -5078,17 +5088,15 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha } } dap_list_t *l_items_voting; - if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL)) && s_voting_callback) { + if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL)) && s_voting_callbacks.voting_callback) { dap_list_free(l_items_voting); - s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, true); + s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, true); } - else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL)) && s_voting_callback) { + else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL)) && s_voting_callbacks.voting_callback) { dap_list_free(l_items_voting); - s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, true); + s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, true); } - - // add transaction to the cache list dap_ledger_tx_item_t *l_tx_item = DAP_NEW_Z(dap_ledger_tx_item_t); if ( !l_tx_item ) { @@ -5121,13 +5129,13 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha dap_list_t *l_notifier; DL_FOREACH(PVT(a_ledger)->tx_add_notifiers, l_notifier) { dap_ledger_tx_notifier_t *l_notify = (dap_ledger_tx_notifier_t*)l_notifier->data; - l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx); + l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx, DAP_LEDGER_NOTIFY_OPCODE_ADDED); } if (l_cross_network) { dap_list_t *l_notifier; DL_FOREACH(PVT(a_ledger)->bridged_tx_notifiers, l_notifier) { dap_ledger_bridged_tx_notifier_t *l_notify = l_notifier->data; - l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg); + l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg, DAP_LEDGER_NOTIFY_OPCODE_ADDED); } } // Count TPS @@ -5169,6 +5177,298 @@ FIN: return l_ret; } +/** + * @brief Remove transaction from the cache list + * @param a_ledger + * @param a_tx + * @param a_tx_hash + * @param a_from_threshold + * @return return 1 OK, -1 error + */ +int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash) +{ + int l_ret = 0; + dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); + dap_list_t *l_list_bound_items = NULL; + dap_list_t *l_list_tx_out = NULL; + char *l_main_token_ticker = NULL; + + char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_chain_hash_fast_to_str(a_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str)); + + // Get boundary items list into l_list_bound_items + // Get tx outs list into l_list_tx_out + int l_ret_check; + if( (l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_tx_hash, false, + &l_list_bound_items, &l_list_tx_out, + &l_main_token_ticker, NULL, NULL, true))) { + debug_if(s_debug_more, L_WARNING, "dap_ledger_tx_remove() tx %s not passed the check: %s ", l_tx_hash_str, + dap_ledger_tx_check_err_str(l_ret_check)); + return l_ret_check; + } + + dap_ledger_tx_item_t *l_ledger_item; + pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock); + HASH_FIND(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_ledger_item); + pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock); + if (l_ledger_item && l_ledger_item->cache_data.n_outs_used != 0) { // transaction already present in the cache list + return DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED; + } + + // find all bound pairs 'in' and 'out' + size_t l_outs_used = dap_list_length(l_list_bound_items); + + dap_store_obj_t *l_cache_used_outs = NULL; + char *l_ledger_cache_group = NULL; + if (PVT(a_ledger)->cached) { + dap_store_obj_t *l_cache_used_outs = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * (l_outs_used)); + if ( !l_cache_used_outs ) { + log_it(L_CRITICAL, "Memory allocation error"); + l_ret = -1; + goto FIN; + } + l_ledger_cache_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TXS_STR); + } + const char *l_cur_token_ticker = NULL; + + // Update balance : raise all bound items to balances + int l_spent_idx = 0; + for (dap_list_t *it = l_list_bound_items; it; it = it->next) { + dap_ledger_tx_bound_t *l_bound_item = it->data; + dap_chain_tx_item_type_t l_type = l_bound_item->type; + if ((l_type == TX_ITEM_TYPE_IN_EMS_LOCK || l_type == TX_ITEM_TYPE_IN_REWARD) && + !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value, true)) + log_it(L_ERROR, "Insufficient supply for token %s", l_bound_item->token_item->ticker); + + switch (l_type) { + case TX_ITEM_TYPE_IN_EMS: + // Mark it as unused + memset(&(l_bound_item->emission_item->tx_used_out), 0, sizeof(dap_hash_fast_t)); + s_ledger_emission_cache_update(a_ledger, l_bound_item->emission_item); + l_outs_used--; // Do not calc this output with tx used items + continue; + + case TX_ITEM_TYPE_IN_EMS_LOCK: + if (l_bound_item->stake_lock_item) { // Legacy stake lock emission + // Mark it as used with current tx hash + memset(&(l_bound_item->stake_lock_item->tx_used_out), 0, sizeof(dap_hash_fast_t)); + s_ledger_stake_lock_cache_update(a_ledger, l_bound_item->stake_lock_item); + } + l_outs_used--; // Do not calc this output with tx used items + continue; + + case TX_ITEM_TYPE_IN_REWARD: { + dap_ledger_reward_item_t *l_item = NULL; + pthread_rwlock_wrlock(&l_ledger_pvt->rewards_rwlock); + HASH_FIND(hh, l_ledger_pvt->rewards, &l_bound_item->reward_key, sizeof(l_bound_item->reward_key), l_item); + if(l_item){ + HASH_DEL(l_ledger_pvt->rewards, l_item); + DAP_DEL_Z(l_item); + } + + pthread_rwlock_unlock(&l_ledger_pvt->rewards_rwlock); + } + l_outs_used--; // Do not calc this output with tx used items + continue; + + case TX_ITEM_TYPE_IN: { + dap_ledger_wallet_balance_t *wallet_balance = NULL; + l_cur_token_ticker = l_bound_item->in.token_ticker; + char *l_addr_str = dap_chain_addr_to_str(&l_bound_item->in.addr_from); + char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL); + pthread_rwlock_rdlock(&PVT(a_ledger)->balance_accounts_rwlock); + HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance); + pthread_rwlock_unlock(&PVT(a_ledger)->balance_accounts_rwlock); + if (wallet_balance) { + if(s_debug_more) { + char *l_balance = dap_chain_balance_print(l_bound_item->value); + log_it(L_DEBUG,"REFUND %s from addr: %s because tx was removed.", l_balance, l_wallet_balance_key); + DAP_DELETE(l_balance); + } + SUM_256_256(wallet_balance->balance, l_bound_item->value, &wallet_balance->balance); + // Update the cache + s_balance_cache_update(a_ledger, wallet_balance); + } else { + if(s_debug_more) + log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_cur_token_ticker); + } + DAP_DELETE(l_wallet_balance_key); + } break; + + case TX_ITEM_TYPE_IN_COND: { // all balance deducts performed with previous conditional transaction + // Update service items if any + dap_ledger_verificator_t *l_verificator; + int l_tmp = l_bound_item->cond->header.subtype; + pthread_rwlock_rdlock(&s_verificators_rwlock); + HASH_FIND_INT(s_verificators, &l_tmp, l_verificator); + pthread_rwlock_unlock(&s_verificators_rwlock); + if (l_verificator && l_verificator->callback_deleted) + l_verificator->callback_deleted(a_ledger, a_tx, l_bound_item->cond); + } break; + + default: + log_it(L_ERROR, "Unknown item type %d in ledger TX bound for IN part", l_type); + break; + } + + // add a used output memset(&(l_bound_item->stake_lock_item->tx_used_out), 0, sizeof(dap_hash_fast_t)); + dap_ledger_tx_item_t *l_prev_item_out = l_bound_item->prev_item; + memset(&(l_prev_item_out->cache_data.tx_hash_spent_fast[l_bound_item->prev_out_idx]), 0, sizeof(dap_hash_fast_t)); + l_prev_item_out->cache_data.n_outs_used--; + if (PVT(a_ledger)->cached) { + // mirror it in the cache + size_t l_tx_size = dap_chain_datum_tx_get_size(l_prev_item_out->tx); + size_t l_tx_cache_sz = l_tx_size + sizeof(l_prev_item_out->cache_data); + byte_t *l_tx_cache = DAP_NEW_Z_SIZE(byte_t, l_tx_cache_sz); + memcpy(l_tx_cache, &l_prev_item_out->cache_data, sizeof(l_prev_item_out->cache_data)); + memcpy(l_tx_cache + sizeof(l_prev_item_out->cache_data), l_prev_item_out->tx, l_tx_size); + char *l_tx_i_hash = dap_chain_hash_fast_to_str_new(&l_prev_item_out->tx_hash_fast); + l_cache_used_outs[l_spent_idx] = (dap_store_obj_t) { + .key = l_tx_i_hash, + .value = l_tx_cache, + .value_len = l_tx_cache_sz, + .group = l_ledger_cache_group + }; + l_cache_used_outs[l_spent_idx].timestamp = 0; + } + // mark previous transactions as used with the extra timestamp + if(l_prev_item_out->cache_data.n_outs_used != l_prev_item_out->cache_data.n_outs) + l_prev_item_out->cache_data.ts_spent = 0; + + if (l_type == TX_ITEM_TYPE_IN || l_type == TX_ITEM_TYPE_IN_COND) { + l_spent_idx++; + } + } + + // Update balance: deducts all outs from balances + bool l_multichannel = false; + bool l_cross_network = false; + for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) { + if (!l_tx_out->data) { + debug_if(s_debug_more, L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache"); + continue; + } + dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data; + if (l_type == TX_ITEM_TYPE_OUT_COND) { + // Update service items if any + dap_chain_tx_out_cond_t *l_cond = (dap_chain_tx_out_cond_t *)l_tx_out->data; + dap_ledger_verificator_t *l_verificator; + int l_tmp = l_cond->header.subtype; + pthread_rwlock_rdlock(&s_verificators_rwlock); + HASH_FIND_INT(s_verificators, &l_tmp, l_verificator); + pthread_rwlock_unlock(&s_verificators_rwlock); + if (l_verificator && l_verificator->callback_deleted) + l_verificator->callback_deleted(a_ledger, a_tx, NULL); + continue; // balance raise will be with next conditional transaction + } + + dap_chain_addr_t *l_addr = NULL; + uint256_t l_value = {}; + switch (l_type) { + case TX_ITEM_TYPE_OUT: { + dap_chain_tx_out_t *l_out_item_256 = (dap_chain_tx_out_t *)l_tx_out->data; + l_addr = &l_out_item_256->addr; + l_value = l_out_item_256->header.value; + l_cur_token_ticker = l_main_token_ticker; + } break; + case TX_ITEM_TYPE_OUT_OLD: { + dap_chain_tx_out_old_t *l_out_item = (dap_chain_tx_out_old_t *)l_tx_out->data; + l_addr = &l_out_item->addr; + l_value = GET_256_FROM_64(l_out_item->header.value); + l_cur_token_ticker = l_main_token_ticker; + } break; + case TX_ITEM_TYPE_OUT_EXT: { + dap_chain_tx_out_ext_t *l_out_item_ext_256 = (dap_chain_tx_out_ext_t *)l_tx_out->data; + l_addr = &l_out_item_ext_256->addr; + l_value = l_out_item_ext_256->header.value; + l_cur_token_ticker = l_out_item_ext_256->token; + l_multichannel = true; + } break; + default: + log_it(L_DEBUG, "Unknown item type %d", l_type); + break; + } + if (!l_addr) + continue; + else if (l_addr->net_id.uint64 != a_ledger->net->pub.id.uint64 && + !dap_chain_addr_is_blank(l_addr)) + l_cross_network = true; + char *l_addr_str = dap_chain_addr_to_str(l_addr); + dap_ledger_wallet_balance_t *wallet_balance = NULL; + char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL); + if(s_debug_more) { + char *l_balance = dap_chain_balance_print(l_value); + log_it(L_DEBUG, "GOT %s to addr: %s", l_balance, l_wallet_balance_key); + DAP_DELETE(l_balance); + } + pthread_rwlock_rdlock(&l_ledger_pvt->balance_accounts_rwlock); + HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance); + pthread_rwlock_unlock(&l_ledger_pvt->balance_accounts_rwlock); + if (wallet_balance) { + //if(s_debug_more) + // log_it(L_DEBUG, "Balance item is present in cache"); + SUBTRACT_256_256(wallet_balance->balance, l_value, &wallet_balance->balance); + DAP_DELETE (l_wallet_balance_key); + // Update the cache + s_balance_cache_update(a_ledger, wallet_balance); + } else { + log_it(L_CRITICAL, "Wallet is not presented in cache. Can't substract out value from balance."); + } + } + + if (dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL) && s_voting_callbacks.voting_delete_callback) + s_voting_callbacks.voting_delete_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx); + else if (dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL) && s_voting_callbacks.voting_delete_callback) + s_voting_callbacks.voting_delete_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx); + + + // remove transaction from ledger + dap_ledger_tx_item_t *l_tx_item = NULL; + pthread_rwlock_wrlock(&l_ledger_pvt->ledger_rwlock); + HASH_FIND(hh, l_ledger_pvt->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_item); + if (l_tx_item) + HASH_DEL(l_ledger_pvt->ledger_items, l_tx_item); + pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock); + + // Callable callback + dap_list_t *l_notifier; + DL_FOREACH(PVT(a_ledger)->tx_add_notifiers, l_notifier) { + dap_ledger_tx_notifier_t *l_notify = (dap_ledger_tx_notifier_t*)l_notifier->data; + l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx, DAP_LEDGER_NOTIFY_OPCODE_DELETED); + } + if (l_cross_network) { + dap_list_t *l_notifier; + DL_FOREACH(PVT(a_ledger)->bridged_tx_notifiers, l_notifier) { + dap_ledger_bridged_tx_notifier_t *l_notify = l_notifier->data; + l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg, DAP_LEDGER_NOTIFY_OPCODE_DELETED); + } + } + + if (PVT(a_ledger)->cached) { + // Add it to cache + dap_global_db_del_sync(l_ledger_cache_group, l_tx_hash_str); + // Apply it with single DB transaction + if (dap_global_db_set_raw(l_cache_used_outs, l_outs_used, NULL, NULL)) + debug_if(s_debug_more, L_WARNING, "Ledger cache mismatch"); + } +FIN: + if (l_list_bound_items) + dap_list_free_full(l_list_bound_items, NULL); + if (l_list_tx_out) + dap_list_free(l_list_tx_out); + DAP_DEL_Z(l_main_token_ticker); + if (PVT(a_ledger)->cached) { + for (size_t i = 1; i < l_outs_used; i++) { + DAP_DEL_Z(l_cache_used_outs[i].key); + DAP_DEL_Z(l_cache_used_outs[i].value); + } + DAP_DEL_Z(l_cache_used_outs); + DAP_DEL_Z(l_ledger_cache_group); + } + return l_ret; +} + + static bool s_ledger_tps_callback(void *a_arg) { dap_ledger_private_t *l_ledger_pvt = (dap_ledger_private_t *)a_arg; @@ -5184,6 +5484,7 @@ static bool s_ledger_tps_callback(void *a_arg) int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash) { +#ifndef DAP_LEDGER_TEST if (dap_chain_net_get_load_mode(a_ledger->net)) { if (PVT(a_ledger)->cache_tx_check_callback) PVT(a_ledger)->cache_tx_check_callback(a_ledger, a_tx_hash); @@ -5201,6 +5502,7 @@ int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_c if (l_tx_item) return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS; } +#endif return dap_ledger_tx_add(a_ledger, a_tx, a_tx_hash, false); } @@ -5973,7 +6275,7 @@ dap_list_t *dap_ledger_get_list_tx_outs(dap_ledger_t *a_ledger, const char *a_to // Add new verificator callback with associated subtype. Returns 1 if callback replaced, -1 error, overwise returns 0 -int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, dap_ledger_updater_callback_t a_callback_added) +int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, dap_ledger_updater_callback_t a_callback_added, dap_ledger_updater_callback_t a_callback_deleted) { dap_ledger_verificator_t *l_new_verificator; int l_tmp = (int)a_subtype; @@ -5992,23 +6294,26 @@ int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_le l_new_verificator->subtype = (int)a_subtype; l_new_verificator->callback = a_callback; l_new_verificator->callback_added = a_callback_added; + l_new_verificator->callback_deleted = a_callback_deleted; pthread_rwlock_wrlock(&s_verificators_rwlock); HASH_ADD_INT(s_verificators, subtype, l_new_verificator); pthread_rwlock_unlock(&s_verificators_rwlock); return 0; } -int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback) +int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback, dap_chain_ledger_voting_delete_callback_t a_callback_delete) { if (!a_callback) return -1; - if (s_voting_callback){ - s_voting_callback = a_callback; + if (!s_voting_callbacks.voting_callback || !s_voting_callbacks.voting_delete_callback){ + s_voting_callbacks.voting_callback = a_callback; + s_voting_callbacks.voting_delete_callback = a_callback_delete; return 1; } - s_voting_callback = a_callback; + s_voting_callbacks.voting_callback = a_callback; + s_voting_callbacks.voting_delete_callback = a_callback_delete; return 0; } @@ -6286,7 +6591,7 @@ const char *dap_ledger_tx_calculate_main_ticker(dap_ledger_t *a_ledger, dap_chai { char *l_main_ticker = NULL; dap_chain_hash_fast_t *l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx); - int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, &l_main_ticker, NULL, NULL); + int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, &l_main_ticker, NULL, NULL, false); if (l_rc == DAP_LEDGER_TX_ALREADY_CACHED) l_main_ticker = (char *)dap_ledger_tx_get_token_ticker_by_hash(a_ledger, l_tx_hash); DAP_DEL_Z(l_tx_hash); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index c2648d9ae3faa9d8eff2251fb146a786d3149d33..2e6da3ae0d3e9f765b288e583824552f458438f6 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -1831,6 +1831,30 @@ void dap_chain_net_delete(dap_chain_net_t *a_net) DAP_DELETE(a_net); } +#ifdef DAP_LEDGER_TEST +int dap_chain_net_test_init() +{ + dap_chain_net_id_t l_iddn = {0}; + sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64); + dap_chain_net_t *l_net = s_net_new(&l_iddn, "Snet", "TestCoin", "root"); + + + // l_net->pub.id.uint64 = l_iddn.uint64; + // l_net->pub.native_ticker = "TestCoin"; + // l_net->pub.name = "Snet"; + + dap_chain_net_item_t *l_net_item = DAP_NEW_Z(dap_chain_net_item_t); + dap_strncpy(l_net_item->name, "Snet", DAP_CHAIN_NET_NAME_MAX); + l_net_item->chain_net = l_net; + l_net_item->net_id.uint64 = l_net->pub.id.uint64; + + HASH_ADD(hh2, s_net_ids, net_id, sizeof(l_net_item->net_id), l_net_item); + + return 0; +} +#endif + + /** * @brief load network config settings from cellframe-node.cfg file * @@ -2120,7 +2144,6 @@ int s_net_init(const char *a_net_name, uint16_t a_acl_idx) dap_chain_net_decree_init(l_net); l_net->pub.config = l_cfg; - return 0; } @@ -3214,6 +3237,68 @@ int dap_chain_datum_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t return 0; } +/** + * @brief Add datum to the ledger or smth else + * @param a_chain + * @param a_datum + * @param a_datum_size + * @return + */ +int dap_chain_datum_remove(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash) +{ + size_t l_datum_data_size = a_datum->header.data_size; + if (a_datum_size < l_datum_data_size + sizeof(a_datum->header)) { + log_it(L_INFO,"Corrupted datum rejected: wrong size %zd not equal or less than datum size %zd",a_datum->header.data_size+ sizeof (a_datum->header), + a_datum_size ); + return -101; + } + dap_ledger_t *l_ledger = dap_chain_net_by_id(a_chain->net_id)->pub.ledger; + switch (a_datum->header.type_id) { + case DAP_CHAIN_DATUM_DECREE: { + /*dap_chain_datum_decree_t *l_decree = (dap_chain_datum_decree_t *)a_datum->data; + size_t l_decree_size = dap_chain_datum_decree_get_size(l_decree); + if (l_decree_size != l_datum_data_size) { + log_it(L_WARNING, "Corrupted decree, datum size %zd is not equal to size of decree %zd", l_datum_data_size, l_decree_size); + return -102; + }*/ + return 0; //dap_chain_net_decree_load(l_decree, a_chain, a_datum_hash); + } + case DAP_CHAIN_DATUM_ANCHOR: { + dap_chain_datum_anchor_t *l_anchor = (dap_chain_datum_anchor_t *)a_datum->data; + size_t l_anchor_size = dap_chain_datum_anchor_get_size(l_anchor); + if (l_anchor_size != l_datum_data_size) { + log_it(L_WARNING, "Corrupted anchor, datum size %zd is not equal to size of anchor %zd", l_datum_data_size, l_anchor_size); + return -102; + } + return dap_chain_net_anchor_unload(l_anchor, a_chain); + } + case DAP_CHAIN_DATUM_TOKEN_DECL: + return 0;//dap_ledger_token_load(l_ledger, a_datum->data, a_datum->header.data_size); + + case DAP_CHAIN_DATUM_TOKEN_EMISSION: + return 0;//dap_ledger_token_emission_load(l_ledger, a_datum->data, a_datum->header.data_size, a_datum_hash); + + case DAP_CHAIN_DATUM_TX: { + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data; + size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); + if (l_tx_size != l_datum_data_size) { + log_it(L_WARNING, "Corrupted trnsaction, datum size %zd is not equal to size of TX %zd", l_datum_data_size, l_tx_size); + return -102; + } + return dap_ledger_tx_remove(l_ledger, l_tx, a_datum_hash); + } + case DAP_CHAIN_DATUM_CA: + return 0;//dap_cert_chain_file_save(a_datum, a_chain->net_name); + + case DAP_CHAIN_DATUM_SIGNER: + case DAP_CHAIN_DATUM_CUSTOM: + break; + default: + return -666; + } + return 0; +} + bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net) { return PVT(a_net)->load_mode; @@ -3238,6 +3323,11 @@ int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_ return 0; } +void dap_chain_net_remove_last_reward(dap_chain_net_t *a_net) +{ + DL_DELETE(PVT(a_net)->rewards, PVT(a_net)->rewards); +} + uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num) { struct block_reward *l_reward; diff --git a/modules/net/dap_chain_net_anchor.c b/modules/net/dap_chain_net_anchor.c index 50c9024ad925a43e1fdac60f9ea1265080ffb7d4..e51977539f5a02d1da142b607e63d645261fd1c7 100644 --- a/modules/net/dap_chain_net_anchor.c +++ b/modules/net/dap_chain_net_anchor.c @@ -26,11 +26,15 @@ #include "dap_common.h" #include "dap_sign.h" #include "dap_pkey.h" +#include "dap_chain.h" +#include "dap_chain_cell.h" #include "dap_chain_common.h" #include "dap_chain_ledger.h" +#include "dap_chain_datum_decree.h" +#include "dap_chain_net_srv_stake_pos_delegate.h" #include "dap_chain_net.h" +#include "dap_chain_net_tx.h" #include "dap_chain_net_decree.h" -#include "dap_chain_datum_decree.h" #include "dap_chain_datum_anchor.h" #define LOG_TAG "chain_net_anchor" @@ -165,6 +169,222 @@ int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t * return ret_val; } +dap_chain_datum_anchor_t * s_find_previous_anchor(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain) +{ + if (!a_anchor || !a_chain){ + log_it(L_ERROR,"Params are NULL"); + return NULL; + } + + dap_chain_datum_anchor_t * l_ret_anchor = NULL; + + dap_hash_fast_t l_old_decrere_hash = {}; + if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_old_decrere_hash) != 0) + return NULL; + dap_chain_datum_decree_t *l_old_decree = dap_chain_net_decree_get_by_hash(&l_old_decrere_hash, NULL); + uint16_t l_old_decree_type = l_old_decree->header.type; + uint16_t l_old_decree_subtype = l_old_decree->header.sub_type; + + dap_chain_cell_t *l_cell = a_chain->cells; + size_t l_atom_size = 0; + dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, l_cell->id, 0); + dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_LAST, &l_atom_size); + while(l_atom && l_atom_size){ + size_t l_datums_count = 0; + dap_chain_datum_t **l_datums = a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count); + dap_chain_datum_t *l_datum, *l_datum2; + for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) { + if ( ! (l_datum = l_datums[l_datum_n]) ) + continue; + + if (l_datum->header.type_id != DAP_CHAIN_DATUM_ANCHOR || a_anchor == (dap_chain_datum_anchor_t *)l_datum->data) + continue; + + dap_chain_datum_anchor_t *l_curr_anchor = (dap_chain_datum_anchor_t *)l_datum->data; + dap_hash_fast_t l_hash = {}; + if (dap_chain_datum_anchor_get_hash_from_data(l_curr_anchor, &l_hash) != 0) + continue; + + bool l_is_applied = false; + dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, &l_is_applied); + if (!l_decree) + continue; + + if (l_decree->header.type == l_old_decree_type && l_old_decree_type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON && + l_old_decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE && + l_decree->header.sub_type == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE){ + + dap_chain_addr_t l_addr_old, l_addr_new = {}; + if (dap_chain_datum_decree_get_stake_signing_addr(l_old_decree, &l_addr_old)){ + continue; + } + + if (dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_addr_new)){ + continue; + } + + if(dap_chain_addr_compare(&l_addr_old, &l_addr_new)){ + l_ret_anchor = l_curr_anchor; + dap_chain_net_decree_reset_applied(a_chain, &l_hash); + break; + } + } else if (l_decree->header.type == l_old_decree_type && l_decree->header.sub_type == l_old_decree_subtype){ + // check addr if l_decree type is stake approve + l_ret_anchor = l_curr_anchor; + dap_chain_net_decree_reset_applied(a_chain, &l_hash); + break; + } + } + DAP_DEL_Z(l_datums); + if (l_ret_anchor) + break; + // go to previous atom + l_atom = a_chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_PREV, &l_atom_size); + } + a_chain->callback_atom_iter_delete(l_atom_iter); + + return l_ret_anchor; +} + +int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain) +{ + int ret_val = 0; + + if (!a_anchor || !a_chain) + { + log_it(L_WARNING,"Invalid arguments. a_decree and a_chain must be not NULL"); + return -107; + } + + dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id); + + if (!l_net->pub.decree) + { + log_it(L_WARNING,"Decree is not inited!"); + return -108; + } + + if ((ret_val = dap_chain_net_anchor_verify(l_net, a_anchor, dap_chain_datum_anchor_get_size(a_anchor))) != 0) + { + log_it(L_WARNING,"Decree is not pass verification!"); + return ret_val; + } + + dap_hash_fast_t l_hash = {}; + if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_hash) != 0) + return -110; + + dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, NULL); + if (!l_decree) + return -111; + + if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON){ + switch (l_decree->header.sub_type) + { + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_FEE:{ + dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain); + if (l_new_anchor){// if previous anchor is founded apply it + dap_chain_hash_fast_t l_hash = {0}; + if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){ + log_it(L_WARNING,"Can not find datum hash in anchor data"); + return -109; + } + + if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){ + log_it(L_WARNING,"Decree applying failed"); + return ret_val; + } + } else { + dap_chain_addr_t a_addr = c_dap_chain_addr_blank; + if (!dap_chain_net_tx_set_fee(a_chain->net_id, uint256_0, a_addr)){ + log_it(L_ERROR, "Can't set fee value for network %s", dap_chain_net_by_id(a_chain->net_id)->pub.name); + ret_val = -100; + } + } + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE:{ + // Invalidate canceled stake + dap_chain_addr_t l_signing_addr = {}; + if ((ret_val = dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_signing_addr)) != 0){ + log_it(L_WARNING,"Can't get signing address from decree."); + return -105; + } + dap_chain_net_srv_stake_key_invalidate(&l_signing_addr); + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE:{ + // Find previous anchor with this stake approve and apply it + dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain); + if (l_new_anchor){// if previous anchor is founded apply it + dap_chain_hash_fast_t l_hash = {0}; + if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){ + log_it(L_WARNING,"Can not find datum hash in anchor data"); + return -109; + } + if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){ + log_it(L_WARNING,"Decree applying failed"); + return ret_val; + } + } + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALUE:{ + dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain); + if (l_new_anchor){// if previous anchor is founded apply it + dap_chain_hash_fast_t l_hash = {0}; + if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){ + log_it(L_WARNING,"Can not find datum hash in anchor data"); + return -109; + } + if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){ + log_it(L_WARNING,"Decree applying failed"); + return ret_val; + } + } else { + dap_chain_addr_t a_addr = {}; + dap_chain_net_srv_stake_set_allowed_min_value(a_chain->net_id, dap_chain_coins_to_balance("1.0")); + } + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALIDATORS_COUNT:{ + dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain); + if (l_new_anchor){// if previous anchor is founded apply it + dap_chain_hash_fast_t l_hash = {0}; + if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){ + log_it(L_WARNING,"Can not find datum hash in anchor data"); + return -109; + } + + if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){ + log_it(L_WARNING,"Decree applying failed"); + return ret_val; + } + } else { + dap_chain_esbocs_set_min_validators_count(a_chain, 0); + } + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_REWARD:{ + // find previous anchor with rewarrd and apply it + dap_chain_net_remove_last_reward(dap_chain_net_by_id(a_chain->net_id)); + } + break; + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS: + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS_MIN: + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN: + case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN: + ret_val = -1; + default: + break; + } + } else if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE){ + + } + + return ret_val; +} + // Private functions static bool s_verify_pubkeys (dap_sign_t *a_sign, dap_sign_t **a_decree_signs, size_t a_num_of_decree_sign) { diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c index 2e717d59e0afadd6c4f7b4edfd04c14962ff87b7..e30a3d28afb38a121c7ea93c79a36b73bb2fda0d 100644 --- a/modules/net/dap_chain_net_decree.c +++ b/modules/net/dap_chain_net_decree.c @@ -239,7 +239,7 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d l_net = dap_chain_net_by_id(a_chain->net_id); - if (!l_net->pub.decree) + if (!l_net || !l_net->pub.decree) { log_it(L_WARNING,"Decree is not inited!"); return -108; @@ -326,6 +326,20 @@ int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t * return dap_chain_net_decree_apply(a_decree_hash, a_decree, a_chain); } +int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash) +{ + if (!a_chain || !a_decree_hash) + return -1; + struct decree_hh* l_decree_hh = NULL; + HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh); + if (!l_decree_hh) + return -2; + + l_decree_hh->is_applied = false; + + return 0; +} + dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied) { struct decree_hh* l_decree_hh = NULL; diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 1e668e7933db5c50f5d9ea57c75046885b2f206d..6080007ce9f25eb9300a2a57e284e7144d11c7e9 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -3702,7 +3702,11 @@ int com_mempool(int a_argc, char **a_argv, void **a_str_reply) return -2; } } - dap_chain_node_cli_cmd_values_parse_net_chain_for_json(&arg_index, a_argc, a_argv, &l_chain, &l_net, CHAIN_TYPE_INVALID); + int cmd_parse_status = dap_chain_node_cli_cmd_values_parse_net_chain_for_json(&arg_index, a_argc, a_argv, &l_chain, &l_net, CHAIN_TYPE_INVALID); + if (cmd_parse_status != 0){ + dap_json_rpc_error_add(cmd_parse_status, "Request parsing error (code: %d)", cmd_parse_status); + return cmd_parse_status; + } const char *l_hash_out_type = "hex"; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type); const char *l_datum_hash_in = NULL; diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h index ab4105e834b18fa98dffadeb9f289ab9a66579a6..f39bee757e3a0be0ab49769d084d9b8c848bed22 100644 --- a/modules/net/include/dap_chain_ledger.h +++ b/modules/net/include/dap_chain_ledger.h @@ -117,6 +117,10 @@ typedef enum dap_ledger_token_decl_add_err{ DAP_LEDGER_TOKEN_DECL_ADD_UNKNOWN /* MAX */ } dap_ledger_token_decl_add_err_t; +typedef enum dap_chan_ledger_notify_opcodes{ + DAP_LEDGER_NOTIFY_OPCODE_ADDED = 'a', // 0x61 + DAP_LEDGER_NOTIFY_OPCODE_DELETED = 'd', // 0x64 +} dap_chan_ledger_notify_opcodes_t; typedef enum dap_chain_tx_tag_action_type { //subtags, till 32 @@ -149,13 +153,15 @@ typedef struct dap_ledger_datum_iter { typedef bool (*dap_ledger_verificator_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_tx_out_cond, dap_chain_datum_tx_t *a_tx_in, bool a_owner); typedef void (*dap_ledger_updater_callback_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_prev_cond); -typedef void (* dap_ledger_tx_add_notify_t)(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx); -typedef void (* dap_ledger_bridged_tx_notify_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, void *a_arg); +typedef void (* dap_ledger_tx_add_notify_t)(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode); +typedef void (* dap_ledger_bridged_tx_notify_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, void *a_arg, dap_chan_ledger_notify_opcodes_t a_opcode); typedef bool (*dap_ledger_cache_tx_check_callback_t)(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash); typedef struct dap_chain_net dap_chain_net_t; typedef bool (*dap_chain_ledger_voting_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx, bool a_apply); +typedef bool (*dap_chain_ledger_voting_delete_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx); typedef bool (*dap_ledger_tag_check_callback_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_datum_tx_item_groups_t *a_items_grp, dap_chain_tx_tag_action_type_t *a_action); + //Change this UUID to automatically reload ledger cache on next node startup #define DAP_LEDGER_CACHE_RELOAD_ONCE_UUID "0c92b759-a565-448f-b8bd-99103dacf7fc" @@ -226,7 +232,7 @@ DAP_STATIC_INLINE char *dap_ledger_get_gdb_group(dap_ledger_t *a_ledger, const c */ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, bool a_from_threshold); int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash); - +int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash); int dap_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, size_t a_datum_size, dap_hash_fast_t *a_datum_hash); @@ -317,7 +323,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_list_t **a_list_tx_out, char **a_main_ticker, dap_chain_net_srv_uid_t *a_tag, - dap_chain_tx_tag_action_type_t *a_action); + dap_chain_tx_tag_action_type_t *a_action, bool a_check_for_removing); const char *dap_ledger_tx_calculate_main_ticker(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, int *a_ledger_rc); @@ -400,9 +406,9 @@ dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer); // Add new verificator callback with associated subtype. Returns 1 if callback replaced, overwise returns 0 int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, - dap_ledger_updater_callback_t a_callback_added); + dap_ledger_updater_callback_t a_callback_added, dap_ledger_updater_callback_t a_callback_deleted); // Add new verificator callback for voting. Returns 1 if callback replaced, overwise returns 0 -int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback); +int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback, dap_chain_ledger_voting_delete_callback_t a_callback_delete); // Getting a list of transactions from the ledger. dap_list_t * dap_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page, bool a_reverse, bool a_unspent_only); diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h index e30e47952cee2a47c4dde36cf4b1750b42c8ff88..e98b723bd74d11e90d4d6e61d30046c14c02fb25 100644 --- a/modules/net/include/dap_chain_net.h +++ b/modules/net/include/dap_chain_net.h @@ -91,6 +91,9 @@ typedef bool (dap_chain_datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_cha int dap_chain_net_init(void); void dap_chain_net_deinit(void); +#ifdef DAP_LEDGER_TEST +int dap_chain_net_test_init(); +#endif DAP_STATIC_INLINE uint64_t dap_chain_net_get_cur_addr_int(dap_chain_net_t *a_net) { return g_node_addr.uint64; } @@ -146,6 +149,7 @@ bool dap_chain_net_remove_validator_from_clusters(dap_chain_t *a_chain, dap_stre dap_global_db_cluster_t *dap_chain_net_get_mempool_cluster(dap_chain_t *a_chain); int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_t a_block_num); +void dap_chain_net_remove_last_reward(dap_chain_net_t *a_net); uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num); int dap_chain_net_link_add(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_addr, const char *a_host, uint16_t a_port); @@ -197,6 +201,7 @@ void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_sto dap_list_t *dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, dap_chain_datum_filter_func_t *a_filter_func, void *a_filter_func_param); int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash); +int dap_chain_datum_remove(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash); bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net); void dap_chain_net_announce_addrs(dap_chain_net_t *a_net); diff --git a/modules/net/include/dap_chain_net_anchor.h b/modules/net/include/dap_chain_net_anchor.h index 34f8f084a86b86d66a48d5371cad83d5c52cac0f..1a44cab2a1f10439cd03d4c91b355c78d3380355 100644 --- a/modules/net/include/dap_chain_net_anchor.h +++ b/modules/net/include/dap_chain_net_anchor.h @@ -26,3 +26,4 @@ int dap_chain_net_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t * a_anchor, size_t a_data_size); int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain); +int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain); \ No newline at end of file diff --git a/modules/net/include/dap_chain_net_decree.h b/modules/net/include/dap_chain_net_decree.h index c8dc68956cb65e7b7f58f711bea6744ee4901eb2..95b035c5650e961a774ba519e5672cf793716442 100644 --- a/modules/net/include/dap_chain_net_decree.h +++ b/modules/net/include/dap_chain_net_decree.h @@ -39,5 +39,7 @@ void dap_chain_net_decree_purge(dap_chain_net_t *a_net); int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain); int dap_chain_net_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_decree, size_t a_data_size, dap_chain_hash_fast_t *a_decree_hash); int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash); +int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash); + dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied); diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index 1b08433f5e70f07a7feb0a7edf6545b41de06a27..48365bb435d8f1e803857650f3fdaa6177b834d6 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -90,8 +90,8 @@ static int s_str_to_price_unit(const char *a_price_unit_str, dap_chain_net_srv_p */ int dap_chain_net_srv_init() { - dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL); - dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL, NULL); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL, NULL); dap_cli_server_cmd_add ("net_srv", s_cli_net_srv, "Network services managment", "net_srv -net <net_name> order find [-direction {sell | buy}] [-srv_uid <service_UID>] [-price_unit <price_unit>]" @@ -108,13 +108,6 @@ int dap_chain_net_srv_init() "net_srv get_limits -net <net_name> -srv_uid <Service_UID> -provider_pkey_hash <Service_provider_public_key_hash> -client_pkey_hash <Client_public_key_hash>\n" "net_srv report\n" "\tGet report about srv usage" -#ifdef DAP_MODULES_DYNAMIC - "\tOrder create\n" - "net_srv -net <net_name> order static [save | delete]\n" - "\tStatic nodelist create/delete\n" - "net_srv -net <net_name> order recheck\n" - "\tCheck the availability of orders\n" -#endif ); s_load_all(); diff --git a/modules/service/stake/dap_chain_net_srv_stake_lock.c b/modules/service/stake/dap_chain_net_srv_stake_lock.c index 71bca901ff808d3fc143445313443af895af4bda..47f2127497a39564490e96e82f2ac9e4919232f7 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_lock.c +++ b/modules/service/stake/dap_chain_net_srv_stake_lock.c @@ -249,7 +249,7 @@ static bool s_tag_check_staking(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_ */ int dap_chain_net_srv_stake_lock_init() { - dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_stake_lock_callback_verificator, s_stake_lock_callback_updater); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_stake_lock_callback_verificator, s_stake_lock_callback_updater, NULL); dap_cli_server_cmd_add("stake_lock", s_cli_stake_lock, "Stake lock service commands", "Command:" "stake_lock hold\n" 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 e09ab6159f91eb2590ba1d82c817eacc2b36d0fe..6531e9f550dd2d0311dc98dbf878928aafe8bd9e 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 @@ -52,7 +52,10 @@ static bool s_stake_verificator_callback(dap_ledger_t *a_ledger, dap_chain_tx_ou dap_chain_datum_tx_t *a_tx_in, bool a_owner); static void s_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond); +static void s_stake_deleted_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond); + static void s_cache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr); +static void s_uncache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr); static dap_list_t *s_srv_stake_list = NULL; @@ -88,7 +91,7 @@ static bool s_tag_check_key_delegation(dap_ledger_t *a_ledger, dap_chain_datum_t */ int dap_chain_net_srv_stake_pos_delegate_init() { - dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_stake_verificator_callback, s_stake_updater_callback); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_stake_verificator_callback, s_stake_updater_callback, s_stake_deleted_callback); dap_cli_server_cmd_add("srv_stake", s_cli_srv_stake, "Delegated stake service commands", "\t\t=== Commands for work with orders ===\n" "srv_stake order create [fee] -net <net_name> -value <value> -cert <priv_cert_name> [-H {hex(default) | base58}]\n" @@ -291,6 +294,15 @@ static void s_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_ s_cache_data(a_ledger, a_tx, l_signing_addr); } +static void s_stake_deleted_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond) +{ + if (!a_cond) + return; + dap_chain_addr_t *l_signing_addr = &a_cond->subtype.srv_stake_pos_delegate.signing_addr; + dap_chain_net_srv_stake_key_invalidate(l_signing_addr); + s_uncache_data(a_ledger, a_tx, l_signing_addr); +} + static bool s_srv_stake_is_poa_cert(dap_chain_net_t *a_net, dap_enc_key_t *a_key) { bool l_is_poa_cert = false; @@ -2908,6 +2920,19 @@ static void s_cache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap log_it(L_WARNING, "Stake service cache mismatch"); } +static void s_uncache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr) +{ + if (!dap_ledger_cache_enabled(a_ledger)) + return; + dap_chain_hash_fast_t l_hash = {}; + dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_hash); + char l_data_key[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_chain_hash_fast_to_str(&l_hash, l_data_key, sizeof(l_data_key)); + char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_GDB_GROUP); + if (dap_global_db_del_sync(l_gdb_group, l_data_key)) + log_it(L_WARNING, "Stake service cache mismatch"); +} + dap_chain_net_srv_stake_item_t *dap_chain_net_srv_stake_check_pkey_hash(dap_chain_net_id_t a_net_id, dap_hash_fast_t *a_pkey_hash) { dap_chain_net_srv_stake_t *l_srv_stake = s_srv_stake_by_net_id(a_net_id); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 5cff28c80877efea6e445d05a7b5ea28f99033ad..ffecdaf7cf139585cbbdf1fed9db023c86084722 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -95,6 +95,7 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has /// -1 error, 0 - unspent, 1 - spent static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx); static bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, bool a_apply); +static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in); static int s_cli_voting(int argc, char **argv, void **a_str_reply); static bool s_tag_check_voting(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_datum_tx_item_groups_t *a_items_grp, dap_chain_tx_tag_action_type_t *a_action) @@ -117,7 +118,7 @@ static bool s_tag_check_voting(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_t int dap_chain_net_srv_voting_init() { pthread_rwlock_init(&s_votings_rwlock, NULL); - dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback); + dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback); dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", "" "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>] [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name>\n" "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n" @@ -492,6 +493,76 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t return false; } +static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in) +{ + dap_hash_fast_t l_hash = {}; + dap_hash_fast(a_tx_in, dap_chain_datum_tx_get_size(a_tx_in), &l_hash); + + if (a_type == TX_ITEM_TYPE_VOTING){ + dap_chain_net_votings_t * l_voting = NULL; + pthread_rwlock_wrlock(&s_votings_rwlock); + HASH_FIND(hh, s_votings, &l_hash, sizeof(dap_hash_fast_t), l_voting); + if(!l_voting){ + char* l_hash_str = dap_hash_fast_to_str_new(&l_hash); + log_it(L_ERROR, "Can't find voting with hash %s in net %s", l_hash_str, a_ledger->net->pub.name); + DAP_DEL_Z(l_hash_str); + pthread_rwlock_unlock(&s_votings_rwlock); + return false; + } + HASH_DEL(s_votings, l_voting); + pthread_rwlock_unlock(&s_votings_rwlock); + + if (l_voting->voting_params.option_offsets_list) + dap_list_free_full(l_voting->voting_params.option_offsets_list, NULL); + + if(l_voting->votes) + dap_list_free_full(l_voting->votes, NULL); + + dap_chain_net_voting_cond_outs_t *l_el = NULL, *l_tmp = NULL; + if(l_voting->voting_spent_cond_outs && l_voting->voting_spent_cond_outs->hh.tbl->num_items){ + HASH_ITER(hh, l_voting->voting_spent_cond_outs, l_el, l_tmp){ + if (l_el){ + HASH_DEL(l_voting->voting_spent_cond_outs, l_el); + DAP_DELETE(l_el); + } + } + } + + DAP_DELETE(l_voting); + + return true; + } else if (a_type == TX_ITEM_TYPE_VOTE){ + dap_chain_tx_vote_t *l_vote_tx_item = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_VOTE, NULL); + if(!l_vote_tx_item){ + log_it(L_ERROR, "Can't find vote item"); + return false; + } + + dap_chain_net_votings_t * l_voting = NULL; + pthread_rwlock_wrlock(&s_votings_rwlock); + HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting); + pthread_rwlock_unlock(&s_votings_rwlock); + if(!l_voting || l_voting->net_id.uint64 != a_ledger->net->pub.id.uint64) { + char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_hash); + log_it(L_ERROR, "Can't find voting with hash %s in net %s", l_hash_str, a_ledger->net->pub.name); + DAP_DELETE(l_hash_str); + return false; + } + + dap_list_t *l_vote = l_voting->votes; + while(l_vote){ + if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)l_vote->data)->vote_hash, &l_hash)){ + // Delete vote + l_voting->votes = dap_list_remove(l_voting->votes, l_vote->data); + break; + } + l_vote = l_vote->next; + } + } + + return true; +} + static dap_list_t* s_get_options_list_from_str(const char* a_str) { dap_list_t* l_ret = NULL; diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index 4b6423062287fda667929c1351a82d331e246aa0..071532d299e54b1bc5df121e883d92cab7c7d771 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -143,7 +143,7 @@ static bool s_tag_check_xchange(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_ */ int dap_chain_net_srv_xchange_init() { - dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, s_xchange_verificator_callback, NULL); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, s_xchange_verificator_callback, NULL, NULL); dap_cli_server_cmd_add("srv_xchange", s_cli_srv_xchange, "eXchange service commands", "srv_xchange order create -net <net_name> -token_sell <token_ticker> -token_buy <token_ticker> -w <wallet_name>" diff --git a/modules/type/blocks/CMakeLists.txt b/modules/type/blocks/CMakeLists.txt index 32900e1ceca6f6b3b31c58ea195193eabb766f9b..3770f285fde25cf498200ae5b8af9f18757fcdd1 100644 --- a/modules/type/blocks/CMakeLists.txt +++ b/modules/type/blocks/CMakeLists.txt @@ -6,6 +6,10 @@ file(GLOB DAP_CHAIN_BLOCK_HEADERS include/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_SRCS} ${DAP_CHAIN_BLOCK_HEADERS}) +if(BUILD_CELLFRAME_SDK_TESTS) + add_subdirectory(tests) +endif() + target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_cli_server dap_chain_net) target_include_directories(${PROJECT_NAME} INTERFACE .) target_include_directories(${PROJECT_NAME} PUBLIC include) diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 07b1d8375b5e63c17b30078213fb66a534dd41ae..931f8f326b3b0a397a1fd26a04e54f54e358adbd 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -60,6 +60,9 @@ typedef struct dap_chain_cs_blocks_pvt // All the blocks are here. In feature should be limited with 1000 when the rest would be loaded from file when needs them dap_chain_block_cache_t * blocks; + size_t forked_br_cnt; + dap_chain_block_forked_branch_t **forked_branches; // list of lists with atoms in side branches + // Chunks treshold dap_chain_block_chunks_t * chunks; dap_chain_block_datum_index_t *datum_index; // To find datum in blocks @@ -88,12 +91,14 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply); // Setup BFT consensus and select the longest chunk static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks); +static bool s_chain_find_atom(dap_chain_block_cache_t* a_blocks, dap_chain_hash_fast_t* a_atom_hash); + // Callbacks static void s_callback_delete(dap_chain_t * a_chain); // Accept new block -static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t); +static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t * a_atom_hash); // Verify new block -static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t); +static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t * a_atom_hash); // Get block header size static size_t s_callback_atom_get_static_hdr_size(void); @@ -1415,6 +1420,35 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca } +static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache) +{ + if (! a_block_cache->datum_count){ + log_it(L_WARNING,"Block %s has no datums at all, can't remove anything from ledger", a_block_cache->block_hash_str); + return 1; // No errors just empty block + } + int l_ret = 0; + + size_t l_block_offset = 0; + size_t l_datum_size = 0; + for(size_t i=0; i<a_block_cache->datum_count && l_block_offset +sizeof(a_block_cache->block->hdr) < a_block_cache->block_size; + i++, l_block_offset += l_datum_size){ + dap_hash_fast_t *l_datum_hash = a_block_cache->datum_hash + i; + dap_chain_datum_t *l_datum = a_block_cache->datum[i]; + int l_res = dap_chain_datum_remove(a_blocks->chain, l_datum, l_datum_size, l_datum_hash); + l_ret++; + + pthread_rwlock_wrlock(&PVT(a_blocks)->datums_rwlock); + dap_chain_block_datum_index_t *l_datum_index = NULL; + HASH_FIND(hh, PVT(a_blocks)->datum_index, l_datum_hash, sizeof(dap_hash_fast_t), l_datum_index); + if (l_datum_index) + HASH_DEL(PVT(a_blocks)->datum_index, l_datum_index); + pthread_rwlock_unlock(&PVT(a_blocks)->datums_rwlock); + } + debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str, + l_ret == (int)a_block_cache->datum_count ? "all correct" : "there are rejected datums"); + return l_ret; +} + /** * @brief s_add_atom_to_blocks * @param a_blocks @@ -1495,6 +1529,69 @@ 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) +{ + dap_chain_cs_blocks_t * l_blocks = a_blocks; + if (!a_blocks){ + log_it(L_ERROR,"a_blocks is NULL"); + return; + } + + if (!a_bcache){ + log_it(L_ERROR,"a_bcache is NULL"); + return; + } + + if (!a_bcache->forked_branches){ + log_it(L_ERROR,"This block is not a forked."); + return; + } + + // 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; + while (l_branch){ + uint64_t l_branch_length = dap_list_length(((dap_chain_block_forked_branch_t*)l_branch->data)->forked_branch_atoms); + 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; + } + l_branch = l_branch->next; + } + + if (current_block_idx < l_longest_branch_length){ + // 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; + 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); + } + + // 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); + ++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; + } + dap_list_free(l_longest_branch_cache_ptr->forked_branch_atoms); + l_longest_branch_cache_ptr->forked_branch_atoms = l_new_forked_branch; + } +} + /** * @brief s_callback_atom_add * @details Accept new atom in blockchain @@ -1503,26 +1600,23 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks) * @param a_atom_size * @return */ -static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size) +static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size, dap_hash_fast_t *a_atom_hash) { dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain); dap_chain_block_t * l_block = (dap_chain_block_t *) a_atom; - dap_chain_hash_fast_t l_block_hash; - dap_hash_fast(l_block, a_atom_size, &l_block_hash); + dap_chain_hash_fast_t l_block_hash = *a_atom_hash; dap_chain_block_cache_t * l_block_cache = NULL; - pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock); - HASH_FIND(hh, PVT(l_blocks)->blocks, &l_block_hash, sizeof(l_block_hash), l_block_cache); - if (l_block_cache) { - debug_if(s_debug_more, L_DEBUG, "... %s is already present", l_block_cache->block_hash_str); - pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); - return ATOM_PASS; - } - dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size); + + dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size, &l_block_hash); + 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){}; + switch (ret) { - case ATOM_ACCEPT: { + case ATOM_ACCEPT:{ dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id); +#ifndef DAP_CHAIN_BLOCKS_TEST if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) { if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) { log_it(L_ERROR, "Can't save atom to file, code %d", ret); @@ -1533,22 +1627,66 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da l_cell->map_pos += a_atom_size; } ret = ATOM_PASS; - } - if ( !(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)) ) - { - log_it(L_DEBUG, "... corrupted block"); + } +#endif + 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"); pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); return ATOM_REJECT; } debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str); - HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache); - ++PVT(l_blocks)->blocks_count; - 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); - break; + + 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(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; + } + } + } + } else { + HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache); + ++PVT(l_blocks)->blocks_count; + pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + 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); + return ret; + } + pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom); + return ATOM_REJECT; } case ATOM_MOVE_TO_THRESHOLD: // TODO: reimplement and enable threshold for blocks @@ -1561,6 +1699,52 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da case ATOM_REJECT: debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom); break; + case ATOM_FORK:{ + dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id); +#ifndef DAP_CHAIN_BLOCKS_TEST + if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) { + if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) { + log_it(L_ERROR, "Can't save atom to file, code %d", ret); + pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + 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 + l_cell->map_pos += a_atom_size; + } + ret = ATOM_PASS; + } +#endif + 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"); + pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + return ATOM_REJECT; + } + 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); + 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; + 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; + 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."); + return ATOM_FORK; + } + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + 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; default: debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret); break; @@ -1576,14 +1760,14 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da * @param a_atom_size * @return */ -static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size) +static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size, dap_chain_hash_fast_t * a_atom_hash) { dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain); assert(l_blocks); dap_chain_cs_blocks_pvt_t * l_blocks_pvt = PVT(l_blocks); assert(l_blocks_pvt); dap_chain_block_t * l_block = (dap_chain_block_t *) a_atom; - dap_chain_hash_fast_t l_block_hash; + dap_chain_hash_fast_t l_block_hash = *a_atom_hash; if(sizeof (l_block->hdr) >= a_atom_size){ log_it(L_WARNING,"Size of block is %zd that is equal or less then block's header size %zd",a_atom_size,sizeof (l_block->hdr)); @@ -1592,7 +1776,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, // Hard accept list if (l_blocks_pvt->hal) { - dap_hash_fast(l_block, a_atom_size, &l_block_hash); struct cs_blocks_hal_item *l_hash_found = NULL; HASH_FIND(hh, l_blocks_pvt->hal, &l_block_hash, sizeof(l_block_hash), l_hash_found); if (l_hash_found) { @@ -1605,25 +1788,25 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, 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){}; - // 2nd level consensus if(l_blocks->callback_block_verify) if (l_blocks->callback_block_verify(l_blocks, l_block, a_atom_size)) 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){}; + // genesis or seed mode if (l_is_genesis) { - if (!l_blocks_pvt->blocks) { - dap_hash_fast(l_block, a_atom_size, &l_block_hash); + if (!PVT(l_blocks)->blocks) { +#ifndef DAP_CHAIN_BLOCKS_TEST if (s_seed_mode) log_it(L_NOTICE, "Accepting new genesis block"); - else if(dap_hash_fast_compare(&l_block_hash,&l_blocks_pvt->static_genesis_block_hash) - &&!dap_hash_fast_is_blank(&l_block_hash)) + else if(dap_hash_fast_compare(&l_block_hash,&PVT(l_blocks)->static_genesis_block_hash) + && !dap_hash_fast_is_blank(&l_block_hash)) log_it(L_NOTICE, "Accepting static genesis block"); else{ char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' }; @@ -1631,6 +1814,9 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, log_it(L_WARNING,"Cant accept genesis block: seed mode not enabled or hash mismatch with static genesis block %s in configuration", l_hash_str); return ATOM_REJECT; } +#else + PVT(l_blocks)->genesis_block_hash = *a_atom_hash; +#endif } else { log_it(L_WARNING,"Cant accept genesis block: already present data in blockchain"); return ATOM_REJECT; @@ -1638,9 +1824,41 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, } else { dap_chain_block_cache_t *l_bcache_last = PVT(l_blocks)->blocks ? PVT(l_blocks)->blocks->hh.tbl->tail->prev : NULL; l_bcache_last = l_bcache_last ? l_bcache_last->hh.next : PVT(l_blocks)->blocks; - if (!l_bcache_last || !dap_hash_fast_compare(&l_bcache_last->block_hash, &l_block_prev_hash)) - return ATOM_MOVE_TO_THRESHOLD; + + 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; + 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)){ + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + return ATOM_PASS; + } + + if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){ + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + return ATOM_FORK; + } + + 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; + } + } + } + pthread_rwlock_unlock(& PVT(l_blocks)->rwlock); + return ATOM_MOVE_TO_THRESHOLD; } + return ATOM_ACCEPT; } @@ -1789,6 +2007,7 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get(dap_chain_atom_iter_t *a_at dap_return_val_if_fail(a_atom_iter, NULL); dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain); dap_chain_cs_blocks_pvt_t *l_blocks_pvt = l_blocks ? PVT(l_blocks) : NULL; + dap_chain_atom_ptr_t l_ret = NULL; assert(l_blocks_pvt); pthread_rwlock_rdlock(&l_blocks_pvt->rwlock); switch (a_operation) { @@ -1813,7 +2032,7 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get(dap_chain_atom_iter_t *a_at a_atom_iter->cur_size = l_item->block_size; a_atom_iter->cur_hash = &l_item->block_hash; a_atom_iter->cur_num = l_item->block_number; - } else + } else *a_atom_iter = (dap_chain_atom_iter_t) { .chain = a_atom_iter->chain, .cell_id = a_atom_iter->cell_id }; pthread_rwlock_unlock(&l_blocks_pvt->rwlock); diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h index d69e2e652778d4a44dbc6576d31106ba6bdbd6ba..27dfe470955c5a810400118a42885c55c646b4ca 100644 --- a/modules/type/blocks/include/dap_chain_block_cache.h +++ b/modules/type/blocks/include/dap_chain_block_cache.h @@ -60,6 +60,9 @@ typedef struct dap_chain_block_cache { // Pointer to block itself dap_chain_block_t * block; + // List for keeping pointers to list of atoms in side branches + dap_list_t *forked_branches; + // Links to prev and next block struct dap_chain_block_cache * prev; struct dap_chain_block_cache * next; @@ -68,6 +71,12 @@ typedef struct dap_chain_block_cache { UT_hash_handle hh; } dap_chain_block_cache_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_t; + int dap_chain_block_cache_init(); void dap_chain_block_cache_deinit(); @@ -79,6 +88,6 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has void dap_chain_block_cache_delete(dap_chain_block_cache_t *a_block_cache); // Get the list of 'out_cond' items from previous transactions with summary out value. Put this summary value to a_value_out -dap_list_t * dap_chain_block_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger,dap_chain_block_cache_t * a_block_cache,uint256_t *a_value_out); +dap_list_t * dap_chain_block_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, dap_chain_block_cache_t * a_block_cache, uint256_t *a_value_out); diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h index 2c2e7de3952fbd60505ca000a57a708bbc44d3cc..bb40da5a247e6a4fbb0adf662dd5650a6deaf976 100644 --- a/modules/type/blocks/include/dap_chain_cs_blocks.h +++ b/modules/type/blocks/include/dap_chain_cs_blocks.h @@ -32,6 +32,8 @@ #define DAP_CHAIN_CS_BLOCKS_MAX_BLOCK_SIZE (256 * 1024) // 256 KB #endif +#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/CMakeLists.txt b/modules/type/blocks/tests/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..fe565847877a0886ef0f82c49241269a20af7376 --- /dev/null +++ b/modules/type/blocks/tests/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.10) + +project(blocks-test) + +file(GLOB DAP_CHAIN_TESTS_HEADERS include/*.h) +file(GLOB DAP_CHAIN_TESTS_SRC *.c) + +add_executable(${PROJECT_NAME} ${DAP_CHAIN_TESTS_SRC} ${DAP_CHAIN_TESTS_HEADERS}) + +target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_cs_blocks ) + +if (DARWIN) + target_link_libraries(${PROJECT_NAME} bz2) +endif() + +target_include_directories(${PROJECT_NAME} PUBLIC include) + +add_test( + NAME blocks-test + COMMAND blocks-test +) diff --git a/modules/type/blocks/tests/dap_chain_blocks_test.c b/modules/type/blocks/tests/dap_chain_blocks_test.c new file mode 100644 index 0000000000000000000000000000000000000000..15c84870405a35e8f2e80f8f7fdda696e8c76f4e --- /dev/null +++ b/modules/type/blocks/tests/dap_chain_blocks_test.c @@ -0,0 +1,152 @@ +#include "dap_test.h" +#include "dap_config.h" +#include "dap_chain_net.h" +#include "dap_chain_common.h" +#include "dap_chain_block.h" +#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 dap_chain_block_test_add_new_block (dap_hash_fast_t *a_prev_block_hash, dap_chain_t *a_chain) +{ + 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: "); + + return l_block_hash; +} + +bool dap_chain_block_test_compare_chain_hash_lists(dap_chain_t* a_chain, dap_list_t* a_atoms_hash_list) +{ + dap_chain_cell_id_t l_cell_id = {.uint64 = 1}; + size_t l_atom_size_from_iter = 0; + dap_chain_atom_iter_t *l_iter = a_chain->callback_atom_iter_create(a_chain, l_cell_id, NULL); + dap_list_t *l_branch_temp = NULL; + 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_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); + return false; + } + + } + a_chain->callback_atom_iter_delete(l_iter); + return true; +} + +void dap_chain_blocks_test() +{ + dap_test_msg("Start of cs block testing..."); + dap_assert_PIF(dap_chain_cs_blocks_init() == 0, "Initialization of dap consensus block: "); + + dap_assert_PIF(dap_chain_cs_esbocs_init() == 0, "Initialization of esbocs: "); + + const char *l_chain_net_name = "testnet"; + const char *l_chain_name = "testchain"; + dap_chain_net_id_t l_chain_net_id = {.uint64 = 1}; + dap_chain_id_t l_chain_id = {.uint64 = 1}; + + dap_chain_t *l_chain = dap_chain_create(l_chain_net_name, l_chain_name, l_chain_net_id, l_chain_id); + dap_config_t l_cfg = {}; + dap_assert_PIF(dap_chain_cs_create(l_chain, &l_cfg) == 0, "Chain cs creating: "); + + dap_hash_fast_t l_forked_block_hash = {}; + dap_hash_fast_t l_block_hash = {}; + 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); + 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_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); + 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); + } + + 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_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); + 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: "); + + 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_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_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(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_second_branch_atoms_list), "Check branches is not switched: "); + + + 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_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(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is switched: "); + + + /* ========================== 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_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_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_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_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: "); + + dap_pass_msg("Fork handling test: ") +} \ No newline at end of file diff --git a/modules/type/blocks/tests/include/dap_chain_blocks_test.h b/modules/type/blocks/tests/include/dap_chain_blocks_test.h new file mode 100644 index 0000000000000000000000000000000000000000..093ee4fc158f6c9de7a584e46e4a2fc294ef2d2c --- /dev/null +++ b/modules/type/blocks/tests/include/dap_chain_blocks_test.h @@ -0,0 +1,3 @@ +#include "dap_chain_cs_blocks.h" + +void dap_chain_blocks_test(); \ No newline at end of file diff --git a/modules/type/blocks/tests/main.c b/modules/type/blocks/tests/main.c new file mode 100644 index 0000000000000000000000000000000000000000..26e8ea5b328105c9e5aa0a7519c5843e7ac2b257 --- /dev/null +++ b/modules/type/blocks/tests/main.c @@ -0,0 +1,8 @@ +#include "dap_chain_blocks_test.h" + +int main() +{ + dap_chain_blocks_test(); + + return 0; +} \ No newline at end of file diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c index 0d34f54c50eb43739c1017bd50337b1c997d0bf1..5b047189d38d65ad49d8f9b5b7c9af2f6a034dd9 100644 --- a/modules/type/dag/dap_chain_cs_dag.c +++ b/modules/type/dag/dap_chain_cs_dag.c @@ -96,9 +96,9 @@ static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag); static dap_chain_cs_dag_event_item_t *s_dag_proc_treshold(dap_chain_cs_dag_t *a_dag); // Atomic element organization callbacks -static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t); // Accept new event in dag +static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash); // Accept new event in dag static dap_chain_atom_ptr_t s_chain_callback_atom_add_from_treshold(dap_chain_t * a_chain, size_t *a_event_size_out); // Accept new event in dag from treshold -static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t); // Verify new event in dag +static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash); // Verify new event in dag static size_t s_chain_callback_atom_get_static_hdr_size(void); // Get dag event header size static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from); @@ -278,9 +278,13 @@ static int s_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg) l_dag->is_add_directly = dap_config_get_item_bool_default(a_chain_cfg,"dag","is_add_directly",false); l_dag->datum_add_hashes_count = dap_config_get_item_uint16_default(a_chain_cfg,"dag","datum_add_hashes_count",1); dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id); +#ifndef DAP_LEDGER_TEST l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new", l_net->pub.gdb_groups_prefix, a_chain->name, 0LLU); - +#else + l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new", + "Snet", a_chain->name, 0LLU); +#endif PVT(l_dag)->treshold_fee_timer = dap_interval_timer_create(900000, (dap_timer_callback_t)s_dap_chain_cs_dag_threshold_free, l_dag); log_it (L_NOTICE, "DAG chain initialized (%s)", l_dag->is_single_line ? "single line" : "multichain"); @@ -443,15 +447,25 @@ static int s_sort_event_item(dap_chain_cs_dag_event_item_t* a, dap_chain_cs_dag_ * @param a_atom_size * @return 0 if verified and added well, otherwise if not */ -static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size) +static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash) { dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain); dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom; - dap_chain_cs_dag_event_item_t *l_event_item = NULL; - dap_chain_hash_fast_t l_event_hash; - dap_chain_cs_dag_event_calc_hash(l_event, a_atom_size, &l_event_hash); - if (s_debug_more) { + dap_chain_cs_dag_event_item_t * l_event_item = DAP_NEW_Z(dap_chain_cs_dag_event_item_t); + if (!l_event_item) { + log_it(L_CRITICAL, "Memory allocation error"); + return ATOM_REJECT; + } + pthread_mutex_t *l_events_mutex = &PVT(l_dag)->events_mutex; + l_event_item->event = l_event; + l_event_item->event_size = a_atom_size; + l_event_item->ts_added = dap_time_now(); + + dap_chain_hash_fast_t l_event_hash = *a_atom_hash; + l_event_item->hash = l_event_hash; + + if(s_debug_more) { char l_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' }; dap_chain_hash_fast_to_str(&l_event_hash, l_event_hash_str, sizeof(l_event_hash_str)); log_it(L_DEBUG, "Processing event: %s ... (size %zd)", l_event_hash_str,a_atom_size); @@ -464,7 +478,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha // verify hashes and consensus switch (ret) { case ATOM_ACCEPT: - ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size); + ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size, &l_event_hash); if (ret == ATOM_MOVE_TO_THRESHOLD) { if (!s_threshold_enabled /*&& !dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id))*/) ret = ATOM_REJECT; @@ -694,7 +708,7 @@ static bool s_chain_callback_datums_pool_proc(dap_chain_t *a_chain, dap_chain_da dap_hash_fast(l_event, l_event_size, &l_event_hash); bool l_res = false; if (l_dag->is_add_directly) { - dap_chain_atom_verify_res_t l_verify_res = s_chain_callback_atom_add(a_chain, l_event, l_event_size); + dap_chain_atom_verify_res_t l_verify_res = s_chain_callback_atom_add(a_chain, l_event, l_event_size, &l_event_hash); DAP_DELETE(l_event); if (l_verify_res != ATOM_ACCEPT) { log_it(L_ERROR, "Can't add new event to the file, atom verification result %d", l_verify_res); @@ -763,7 +777,7 @@ static bool s_event_verify_size(dap_chain_cs_dag_event_t *a_event, size_t a_even * @param a_atom * @return */ -static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom,size_t a_atom_size) +static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom,size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash) { dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain); dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom; @@ -777,11 +791,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_ debug_if(s_debug_more, L_WARNING, "Event from another chain, possible corrupted event"); return ATOM_REJECT; } - + dap_chain_hash_fast_t l_event_hash = *a_atom_hash; // Hard accept list if (l_dag->hal) { - dap_chain_hash_fast_t l_event_hash = { }; - dap_chain_cs_dag_event_calc_hash(l_event,a_atom_size, &l_event_hash); dap_chain_cs_dag_hal_item_t *l_hash_found = NULL; pthread_mutex_lock(l_events_mutex); HASH_FIND(hh, l_dag->hal, &l_event_hash, sizeof(l_event_hash), l_hash_found); @@ -806,8 +818,6 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_ } if (l_dag->is_static_genesis_event ){ - dap_chain_hash_fast_t l_event_hash; - dap_chain_cs_dag_event_calc_hash(l_event,a_atom_size, &l_event_hash); if ( memcmp( &l_event_hash, &l_dag->static_genesis_event_hash, sizeof(l_event_hash) ) != 0 ){ char l_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE], l_genesis_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; dap_chain_hash_fast_to_str(&l_event_hash, l_event_hash_str, sizeof(l_event_hash_str)); @@ -1398,7 +1408,9 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply) continue; dap_chain_cs_dag_event_round_item_t *l_round_item = (dap_chain_cs_dag_event_round_item_t *)l_objs[i].value; dap_chain_cs_dag_event_t *l_event = (dap_chain_cs_dag_event_t *)l_round_item->event_n_signs; + dap_hash_fast_t l_event_hash = {}; size_t l_event_size = l_round_item->event_size; + dap_hash_fast(l_event, l_event_size, &l_event_hash); int l_ret_event_verify; if ( ( l_ret_event_verify = l_dag->callback_cs_verify (l_dag,l_event,l_event_size) ) !=0 ){// if consensus accept the event dap_string_append_printf( l_str_ret_tmp, @@ -1410,7 +1422,7 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply) dap_string_append_printf( l_str_ret_tmp, "Event %s verification passed\n", l_objs[i].key); // If not verify only mode we add if ( ! l_verify_only ){ - if (s_chain_callback_atom_add(l_chain, l_event, l_event_size) != ATOM_ACCEPT) { // Add new atom in chain + if (s_chain_callback_atom_add(l_chain, l_event, l_event_size, &l_event_hash) != ATOM_ACCEPT) { // Add new atom in chain dap_string_append_printf(l_str_ret_tmp, "Event %s not added in chain\n", l_objs[i].key); } else { // add event to delete diff --git a/modules/type/none/dap_chain_cs_none.c b/modules/type/none/dap_chain_cs_none.c index f76440baafe884c0dce476b4d306219004df105a..78e2681936c66295956f14250f693a08ab139ee9 100644 --- a/modules/type/none/dap_chain_cs_none.c +++ b/modules/type/none/dap_chain_cs_none.c @@ -60,8 +60,8 @@ typedef struct dap_nonconsensus_private { #define PVT(a) ((a) ? (dap_nonconsensus_private_t *)(a)->_internal : NULL) // Atomic element organization callbacks -static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); // Accept new event in gdb -static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); // Verify new event in gdb +static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t *a_atom_hash); // Accept new event in gdb +static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t *a_atom_hash); // Verify new event in gdb static size_t s_nonconsensus_callback_atom_get_static_hdr_size(void); // Get gdb event header size static dap_chain_atom_iter_t* s_nonconsensus_callback_atom_iter_create(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from); @@ -127,7 +127,9 @@ static void s_changes_callback_notify(dap_store_obj_t *a_obj, void *a_arg) dap_chain_t *l_chain = a_arg; if (dap_store_obj_get_type(a_obj) == DAP_GLOBAL_DB_OPTYPE_DEL) return; - s_nonconsensus_callback_atom_add(l_chain, (dap_chain_datum_t *)a_obj->value, a_obj->value_len); + dap_hash_fast_t l_hash = {}; + dap_hash_fast(a_obj->value, a_obj->value_len, &l_hash); + s_nonconsensus_callback_atom_add(l_chain, (dap_chain_datum_t *)a_obj->value, a_obj->value_len, &l_hash); } int s_nonconsensus_callback_created(dap_chain_t *a_chain, dap_config_t UNUSED_ARG *a_chain_cfg) @@ -261,7 +263,9 @@ static void s_nonconsensus_ledger_load(dap_chain_t *a_chain) for (size_t i = 0; l_values && i < l_values_count; i++) { dap_global_db_obj_t *it = l_values + i; // load ledger - s_nonconsensus_callback_atom_add(a_chain, it->value, it->value_len); + dap_hash_fast_t l_hash = {}; + dap_hash_fast(it->value, it->value_len, &l_hash); + s_nonconsensus_callback_atom_add(a_chain, it->value, it->value_len, &l_hash); log_it(L_DEBUG,"Load mode, doesn't save item %s:%s", it->key, l_nochain_pvt->group_datums); } dap_global_db_objs_delete(l_values, l_values_count); @@ -303,7 +307,7 @@ static size_t s_nonconsensus_callback_datums_pool_proc(dap_chain_t * a_chain, da * @param a_atom_size atom size * @return dap_chain_atom_verify_res_t */ -static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size) +static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash) { if (NULL == a_chain) { log_it(L_WARNING, "Arguments is NULL for s_nonconsensus_callback_atom_add"); @@ -312,9 +316,8 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t dap_nonconsensus_t * l_nochain = DAP_NONCONSENSUS(a_chain); dap_nonconsensus_private_t *l_nochain_priv = PVT(l_nochain); dap_chain_datum_t *l_datum = (dap_chain_datum_t*) a_atom; - dap_hash_fast_t l_datum_hash; - dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_datum_hash); - if (dap_chain_datum_add(a_chain, l_datum, a_atom_size, &l_datum_hash)) + dap_hash_fast_t l_datum_hash = *a_atom_hash; + if(dap_chain_datum_add(a_chain, l_datum, a_atom_size, &l_datum_hash)) return ATOM_REJECT; dap_nonconsensus_datum_hash_item_t * l_hash_item = DAP_NEW_Z(dap_nonconsensus_datum_hash_item_t); @@ -323,7 +326,7 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t return ATOM_REJECT; } size_t l_datum_size = dap_chain_datum_size(l_datum); - dap_hash_fast(l_datum->data,l_datum->header.data_size,&l_hash_item->datum_data_hash ); + l_hash_item->datum_data_hash = l_datum_hash; dap_chain_hash_fast_to_str(&l_hash_item->datum_data_hash, l_hash_item->key, sizeof(l_hash_item->key)); DL_APPEND(l_nochain_priv->hash_items, l_hash_item); if (!l_nochain_priv->is_load_mode && a_chain->atom_notifiers) { @@ -345,7 +348,7 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * @param a_atom_size size of atom * @return dap_chain_atom_verify_res_t */ -static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size) +static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash) { (void) a_chain; (void) a_atom;