diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index 69875f0ac83b975ae49b2e2e21de3eac12af2f69..c651d94e9841b5abb7844ec696c0134d0e4308de 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -56,6 +56,7 @@ #include "dap_chain_mempool.h" #include "dap_chain_global_db.h" #include "dap_chain_ledger.h" +#include "dap_chain_pvt.h" #define LOG_TAG "dap_chain_ledger" @@ -223,6 +224,7 @@ static bool s_ledger_tps_callback(void *a_arg); static size_t s_treshold_emissions_max = 1000; static size_t s_treshold_txs_max = 10000; static bool s_debug_more = false; +static bool s_token_supply_limit_disable = false; /** * @brief dap_chain_ledger_init @@ -232,6 +234,7 @@ static bool s_debug_more = false; int dap_chain_ledger_init() { s_debug_more = dap_config_get_item_bool_default(g_config,"ledger","debug_more",false); + s_token_supply_limit_disable = dap_config_get_item_bool_default(g_config,"ledger","token_supply_limit_disable",false); return 0; } @@ -370,14 +373,29 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t * dap_snprintf(l_token_item->ticker,sizeof (l_token_item->ticker), "%s", a_token->ticker); pthread_rwlock_init(&l_token_item->token_emissions_rwlock,NULL); l_token_item->datum_token = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, a_token_size); + + // + // init current_supply value in token_declaration procedure (ledger cache and ledger memory object) + // + + l_token_item->datum_token->header_private.current_supply = a_token->header_private.total_supply; + l_token_item->total_supply = a_token->header_private.total_supply_256; + + l_token_item->current_supply = l_token_item->total_supply; + memcpy(l_token_item->datum_token, a_token, a_token_size); + + dap_chain_datum_token_t *l_token_cache = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, a_token_size); + memcpy(l_token_cache, a_token, a_token_size); + l_token_cache->header_private.current_supply_256 = l_token_item->total_supply; + pthread_rwlock_wrlock(&PVT(a_ledger)->tokens_rwlock); HASH_ADD_STR(PVT(a_ledger)->tokens, ticker, l_token_item); pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock); // Add it to cache char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR); - if (!dap_chain_global_db_gr_set( a_token->ticker, a_token, a_token_size, l_gdb_group)) { + if (!dap_chain_global_db_gr_set( a_token->ticker, l_token_cache, a_token_size, l_gdb_group)) { if(s_debug_more) log_it(L_WARNING, "Ledger cache mismatch"); } @@ -387,6 +405,7 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t * switch(a_token->type){ case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: {// 256 l_token_item->total_supply = a_token->header_private.total_supply_256; + l_token_item->current_supply = l_token_item->total_supply; l_token_item->auth_signs= dap_chain_datum_token_simple_signs_parse(a_token,a_token_size, &l_token_item->auth_signs_total, &l_token_item->auth_signs_valid ); @@ -403,7 +422,8 @@ int dap_chain_ledger_token_add(dap_ledger_t *a_ledger, dap_chain_datum_token_t * break; } case DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE: { - l_token_item->total_supply = GET_256_FROM_64(a_token->header_private.total_supply); + l_token_item->total_supply = a_token->header_private.total_supply_256; + l_token_item->current_supply = l_token_item->total_supply; l_token_item->auth_signs= dap_chain_datum_token_simple_signs_parse(a_token,a_token_size, &l_token_item->auth_signs_total, &l_token_item->auth_signs_valid ); @@ -952,6 +972,62 @@ dap_list_t *dap_chain_ledger_token_info(dap_ledger_t *a_ledger) return l_ret_list; } +/** + * @brief update current_supply in token cache + * + * @param a_ledger ledger object + * @param l_token_item token item object + * @param l_emission_value size of emission + * @return true + * @return false + */ +bool s_update_token_cache(dap_ledger_t *a_ledger, dap_chain_ledger_token_item_t * l_token_item, uint256_t l_emission_value) +{ + dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger); + + char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR); + size_t l_obj_length = 0; + + // + // Get dap_chain_datum_token_t token object from GDB, key is token name + // + + dap_chain_datum_token_t *l_token_for_update = (dap_chain_datum_token_t *) dap_chain_global_db_gr_get(l_token_item->ticker, &l_obj_length, l_gdb_group); + dap_chain_datum_token_t *l_token_cache = DAP_NEW_Z_SIZE(dap_chain_datum_token_t, l_obj_length); + + memcpy(l_token_cache, l_token_for_update, sizeof(dap_chain_datum_token_t)); + + if (compare256(l_token_cache->header_private.current_supply_256, l_emission_value) >= 0) + { + SUBTRACT_256_256(l_token_cache->header_private.current_supply_256, l_emission_value, &l_token_cache->header_private.current_supply_256); + log_it(L_DEBUG,"New current supply %s for token %s", dap_chain_balance_print(l_token_cache->header_private.current_supply_256), l_token_item->ticker); + + //Update value in ledger memory object + + l_token_item->current_supply = l_token_cache->header_private.current_supply_256; + } + else + { + log_it(L_WARNING,"Token current supply %s lower, than emission value = %s", dap_chain_balance_print(l_token_cache->header_private.current_supply_256), + dap_chain_balance_print(l_emission_value)); + + DAP_DELETE(l_gdb_group); + DAP_DELETE(l_token_cache); + return false; + } + + if (!dap_chain_global_db_gr_set(dap_strdup(l_token_item->ticker), l_token_cache, l_obj_length, l_gdb_group)) + { + if(s_debug_more) + log_it(L_WARNING, "Ledger cache mismatch"); + DAP_DELETE(l_token_cache); + } + + DAP_DELETE(l_gdb_group); + + return true; +} + /** * @brief s_treshold_emissions_proc * @param a_ledger @@ -1024,6 +1100,7 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger) size_t l_token_size = l_objs[i].value_len; l_token_item->datum_token = dap_chain_datum_token_read(l_objs[i].value, &l_token_size); pthread_rwlock_init(&l_token_item->token_emissions_rwlock, NULL); + l_token_item->type = l_token_item->datum_token->type; // test tsd // size_t signs_total = 0, signs_valid = 0, l_token_size_test = l_token_size - sizeof(dap_chain_datum_token_t) + sizeof(dap_chain_datum_token_old_t); // dap_sign_t **sign = dap_chain_datum_token_simple_signs_parse( l_token_item->datum_token, l_token_size_test, &signs_total, &signs_valid); @@ -1031,6 +1108,7 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger) if (l_token_item->datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_OLD_SIMPLE) { l_token_item->total_supply = GET_256_FROM_64(l_token_item->datum_token->header_private.total_supply); + l_token_item->current_supply = l_token_item->total_supply; } else if (l_token_item->datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE) { l_token_item->total_supply = l_token_item->datum_token->header_private.total_supply_256; if (l_token_item->auth_signs_total) { @@ -1061,8 +1139,13 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger) // l_emission_item->datum_token_emission = l_token_item // ? dap_chain_datum_emission_read(l_objs[i].value, &l_emission_size) // : DAP_DUP_SIZE(l_objs[i].value, l_objs[i].value_len); + l_emission_item->datum_token_emission = dap_chain_datum_emission_read(l_objs[i].value, &l_emission_size); l_emission_item->datum_token_emission_size = l_emission_size; + + // need to check after token emission will be working in develop build + //log_it(L_WARNING,"Ledger cache datum_token_emission %lld, ticker: %s", l_emission_item->datum_token_emission->hdr.value, c_token_ticker); + if (l_token_item) { HASH_ADD(hh, l_token_item->token_emissions, datum_token_emission_hash, sizeof(dap_chain_hash_fast_t), l_emission_item); @@ -1125,6 +1208,7 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger) DAP_DELETE(l_gdb_group); } + /** * @brief * create ledger for specific net @@ -1155,6 +1239,7 @@ dap_ledger_t* dap_chain_ledger_create(uint16_t a_check_flags, char *a_net_name) // load ledger cache from GDB dap_chain_ledger_load_cache(l_ledger); } + return l_ledger; } @@ -1297,6 +1382,22 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_ : DAP_DUP_SIZE(a_token_emission, a_token_emission_size); memcpy(&l_token_emission_item->datum_token_emission_hash, &l_token_emission_hash, sizeof(l_token_emission_hash)); l_token_emission_item->datum_token_emission_size = l_emission_size; + + // + // update current_supply in ledger cache and ledger memory object + // + + if (!PVT(a_ledger)->load_mode && l_token_item && !s_token_supply_limit_disable) + { + if (!s_update_token_cache(a_ledger, l_token_item, l_token_emission_item->datum_token_emission->hdr.value_256)) + return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION; + } + + if (s_token_supply_limit_disable) + { + log_it(L_WARNING,"s_token_supply_limit_disable is enabled in config, please fix it and disable"); + } + if (l_token_item) { pthread_rwlock_wrlock(&l_token_item->token_emissions_rwlock); HASH_ADD(hh, l_token_item->token_emissions, datum_token_emission_hash, diff --git a/modules/common/include/dap_chain_datum_token.h b/modules/common/include/dap_chain_datum_token.h index a0c717d0ced770686f6768d0d193243bf8deb4ae..6ddb5f88422ffe4cb2d35dfe04af98f79c74a2db 100644 --- a/modules/common/include/dap_chain_datum_token.h +++ b/modules/common/include/dap_chain_datum_token.h @@ -72,6 +72,10 @@ typedef struct dap_chain_datum_token{ uint64_t total_supply; // Could be zero if unlimited uint256_t total_supply_256; }; + union { + uint64_t current_supply; // Could be zero if unlimited + uint256_t current_supply_256; + }; uint16_t signs_valid; // Emission auth signs uint16_t signs_total; // Emission auth signs } DAP_ALIGN_PACKED header_private; diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c index a87f43fed0b743b11f79747cc2547f2b42d851c3..6f9f8025be5f1a7331740f41585a93a3e3b4203e 100644 --- a/modules/global-db/dap_chain_global_db.c +++ b/modules/global-db/dap_chain_global_db.c @@ -300,13 +300,14 @@ dap_store_obj_t* dap_chain_global_db_obj_gr_get(const char *a_key, size_t *a_dat return l_store_data; } + /** * @brief Gets an object value from database by a_key and a_group. + * * @param a_key an object key string - * @param a_data_out[in] a number of objects to be gotten, if NULL - no limits - * @param a_data_out[out] a length of values that were gotten + * @param a_data_len_out a length of values that were gotten * @param a_group a group name string - * @return If successful, returns a pointer to the object value. + * @return If successful, returns a pointer to the object value. */ uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group) { diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index 391962d4fe420231224307621f4006e27dd0d375..a465def44f361b21b7bfd244232c7466c979a30e 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -1444,6 +1444,107 @@ void s_set_reply_text_node_status(char **a_str_reply, dap_chain_net_t * a_net){ DAP_DELETE(l_node_address_text_block); } +/** + * @brief reload ledger + * command cellframe-node-cli net -net <network_name> ledger reload + * @param l_net + * @return true + * @return false + */ +bool s_chain_net_ledger_cache_reload(dap_chain_net_t *l_net) +{ + dap_chain_ledger_purge(l_net->pub.ledger, false); + dap_chain_t *l_chain = NULL; + DL_FOREACH(l_net->pub.chains, l_chain) + { + if (l_chain->callback_purge) + l_chain->callback_purge(l_chain); + + if (!strcmp(DAP_CHAIN_PVT(l_chain)->cs_name, "none")) + dap_chain_gdb_ledger_load((char *)dap_chain_gdb_get_group(l_chain), l_chain); + else + dap_chain_load_all(l_chain); + } + bool l_processed; + do { + l_processed = false; + DL_FOREACH(l_net->pub.chains, l_chain) { + if (l_chain->callback_atom_add_from_treshold) { + while (l_chain->callback_atom_add_from_treshold(l_chain, NULL)) { + log_it(L_DEBUG, "Added atom from treshold"); + l_processed = true; + } + } + } + } while (l_processed); +} + +/** + * @brief update ledger cache at once + * if you node build need ledger cache one time reload, uncomment this function + * iat the end of s_net_load + * @param l_net network object + * @return true + * @return false + */ +bool s_chain_net_reload_ledger_cache_once(dap_chain_net_t *l_net) +{ + if (!l_net) + return false; + + log_it(L_WARNING,"Start one time ledger cache reloading"); + + // + // create directory for cache checking file (cellframe-node/cache) + // + + char *l_cache_dir = dap_strdup_printf( "%s/%s", g_sys_dir_path, "cache"); + + if (dap_mkdir_with_parents(l_cache_dir) != 0) + { + log_it(L_WARNING,"Error during disposable cache check file creation"); + return false; + } + + // + // create file, if it not presented. If file exists, ledger cache operation is stopped + // + + char *l_cache_file = dap_strdup_printf( "%s/%s.cache", l_cache_dir, "4CFB3928-1A9A-467D-BB5E-3FDB35014E8A"); + + if (dap_file_simple_test(l_cache_file)) + { + log_it(L_DEBUG,"Ledger cache was already reloaded"); + return false; + } + + static FILE *s_cache_file = NULL; + + s_cache_file = fopen(l_cache_file, "a"); + + if(!s_cache_file) + { + s_cache_file = fopen(l_cache_file, "w"); + + if (!s_cache_file) + { + dap_fprintf(stderr, "Can't open cache file %s for one time ledger cache reloading.\ + Please, do it manually using command\ + cellframe-node-cli net -net <network_name>> ledger reload'\n", l_cache_file); + return -1; + } + } + + // + // reload ledger cache (same as net -net <network_name>> ledger reload command) + // + + if (dap_file_simple_test(l_cache_file)) + s_chain_net_ledger_cache_reload(l_net); + + return true; +} + /** * @brief * register net* command in cellframe-node-cli interface @@ -1819,31 +1920,12 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply) "Subcommand 'ca' requires one of parameter: add, list, del\n"); ret = -5; } - } else if (l_ledger_str && !strcmp(l_ledger_str, "reload")) { - dap_chain_ledger_purge(l_net->pub.ledger, false); - dap_chain_t *l_chain; - DL_FOREACH(l_net->pub.chains, l_chain) { - if (l_chain->callback_purge) { - l_chain->callback_purge(l_chain); - } - if (!strcmp(DAP_CHAIN_PVT(l_chain)->cs_name, "none")) { - dap_chain_gdb_ledger_load((char *)dap_chain_gdb_get_group(l_chain), l_chain); - } else { - dap_chain_load_all(l_chain); - } - } - bool l_processed; - do { - l_processed = false; - DL_FOREACH(l_net->pub.chains, l_chain) { - if (l_chain->callback_atom_add_from_treshold) { - while (l_chain->callback_atom_add_from_treshold(l_chain, NULL)) { - log_it(L_DEBUG, "Added atom from treshold"); - } - } - } - } while (l_processed); - } else { + } else if (l_ledger_str && !strcmp(l_ledger_str, "reload")) + { + s_chain_net_ledger_cache_reload(l_net); + } + else + { dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'net' requires one of subcomands: sync, link, go, get, stats, ca, ledger"); ret = -1; @@ -2388,6 +2470,10 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx) } l_net_pvt->load_mode = false; dap_chain_ledger_load_end(l_net->pub.ledger); + + // reload ledger cache at once + s_chain_net_reload_ledger_cache_once(l_net); + dap_chain_net_add_notify_callback(l_net, dap_chain_net_sync_gdb_broadcast); if (l_target_state != l_net_pvt->state_target) dap_chain_net_state_go_to(l_net, l_target_state);