diff --git a/CMakeLists.txt b/CMakeLists.txt index 532b88b29ee1886559b374466fbbe17c89d3f0be..098d030f2bcc0af1067033c017b606ef48d36f16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ project(cellframe-sdk C) cmake_minimum_required(VERSION 2.8) set(CMAKE_C_STANDARD 11) -set(CELLFRAME_SDK_NATIVE_VERSION "2.6-15") +set(CELLFRAME_SDK_NATIVE_VERSION "2.6-16") add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"") set(DAPSDK_MODULES "") diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index 0a6d53a743aca82a316b4bbbc01ce682074672e3..dc6b2a9c7a861f0111980087604faa117e757e57 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -961,7 +961,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t bound_item->item_out = l_item_out; if(!l_tx_prev) { // First transaction log_it(L_DEBUG,"No previous transaction was found for hash %s",l_tx_prev_hash_str); - l_err_num = DAP_CHAIN_LEDGER_TX_NO_PREVIOUS; + l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS; break; } //log_it(L_INFO,"Previous transaction was found for hash %s",l_tx_prev_hash_str); @@ -1290,7 +1290,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, l_item_tmp = NULL; if( (l_ret_check = dap_chain_ledger_tx_cache_check( a_ledger, a_tx, &l_list_bound_items, &l_list_tx_out)) < 0) { - if (l_ret_check == DAP_CHAIN_LEDGER_TX_NO_PREVIOUS) { + if (l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS) { HASH_FIND(hh, l_ledger_priv->treshold_txs, l_tx_hash, sizeof(*l_tx_hash), l_item_tmp); if (!l_item_tmp) { if (HASH_COUNT(l_ledger_priv->treshold_txs) >= s_treshold_txs_max) { diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h index 81f182638b8cdf3581775219eb4f94f0949c8f77..41834c2073bc8f39d37b091226fb4bdc732bc4a5 100644 --- a/modules/chain/include/dap_chain_ledger.h +++ b/modules/chain/include/dap_chain_ledger.h @@ -54,7 +54,7 @@ typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t #define DAP_CHAIN_LEDGER_CHECK_CELLS_DS 0x0100 // Error code for no previous transaction (candidate to threshold) -#define DAP_CHAIN_LEDGER_TX_NO_PREVIOUS -5 +#define DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS -5 #define DAP_CHAIN_LEDGER_TOKENS_STR "tokens" #define DAP_CHAIN_LEDGER_EMISSIONS_STR "emissions" diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c index d8515e87228b90c82e41026dae4efc0968cc664b..0768ef82f4b955c51d1115430dd950d5de0753a7 100644 --- a/modules/common/dap_chain_datum.c +++ b/modules/common/dap_chain_datum.c @@ -42,6 +42,7 @@ const char * c_datum_type_str[]={ [DAP_CHAIN_DATUM_CUSTOM]="DATUM_CUSTOM", [DAP_CHAIN_DATUM_TOKEN_DECL]="DATUM_TOKEN_DECL", [DAP_CHAIN_DATUM_TOKEN_EMISSION]="DATUM_TOKEN_EMISSION", + [DAP_CHAIN_DATUM_CUSTOM] = "DAP_CHAIN_DATUM_CUSTOM" }; /** diff --git a/modules/common/include/dap_chain_datum.h b/modules/common/include/dap_chain_datum.h index 3293a2c3720093431032dccdb5101f03458e6839..d5232c9ff64ea771f446a702fb47d10af3d4b594 100644 --- a/modules/common/include/dap_chain_datum.h +++ b/modules/common/include/dap_chain_datum.h @@ -65,11 +65,12 @@ extern const char * c_datum_type_str[]; -#define DAP_CHAIN_DATUM_ID_SIZE 4 +#define DAP_CHAIN_DATUM_ID_SIZE 2 // Datum subchain type id typedef union dap_chain_datum_typeid{ uint8_t data[DAP_CHAIN_DATUM_ID_SIZE]; + uint16_t uint16; } DAP_ALIGN_PACKED dap_chain_datum_typeid_t; @@ -81,7 +82,7 @@ typedef struct dap_chain_datum{ struct{ /// Datum version uint8_t version_id; - /// Section type id + /// Datum type id uint16_t type_id; /// Data section size uint32_t data_size; @@ -107,7 +108,34 @@ typedef dap_chain_datum_t* (*dap_chain_datum_callback_iter_get_first_t)(dap_chai typedef dap_chain_datum_t* (*dap_chain_datum_callback_iter_get_next_t)(dap_chain_datum_iter_t * ); typedef void (*dap_chain_datum_callback_iter_delete_t)(dap_chain_datum_iter_t * ); +/** + * @brief dap_chain_datum_typeid_to_str + * @param a_type_id + * @return + */ +static inline const char * dap_chain_datum_type_id_to_str(uint16_t a_type_id){ + switch ( a_type_id ){ + case DAP_CHAIN_DATUM_TX: + case DAP_CHAIN_DATUM_TX_REQUEST: + case DAP_CHAIN_DATUM_WASM_CODE: + case DAP_CHAIN_DATUM_WASM_DATA: + case DAP_CHAIN_DATUM_EVM_CODE: + case DAP_CHAIN_DATUM_EVM_DATA: + case DAP_CHAIN_DATUM_CA: + case DAP_CHAIN_DATUM_TOKEN_DECL: + case DAP_CHAIN_DATUM_TOKEN_EMISSION: + case DAP_CHAIN_DATUM_CUSTOM: + return c_datum_type_str[a_type_id]; + default: + return "(wrong datum type id)"; + } +} +/** + * @brief dap_chain_datum_size + * @param a_datum + * @return + */ static inline size_t dap_chain_datum_size(dap_chain_datum_t * a_datum) { if(!a_datum) diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c index daee181c47d5df5cd523fd53a34bc77176c9ea57..f4c204bd8b52de360855cb2a0a5290d4102adb82 100644 --- a/modules/type/blocks/dap_chain_block.c +++ b/modules/type/blocks/dap_chain_block.c @@ -23,6 +23,7 @@ #include <stddef.h> #include "string.h" #include "dap_common.h" +#include "dap_config.h" #include "dap_hash.h" #include "dap_chain_block.h" @@ -30,12 +31,16 @@ #define LOG_TAG "dap_chain_block" +bool s_seed_mode = false; + /** * @brief dap_chain_block_init * @return */ int dap_chain_block_init() { + s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false); + return 0; } diff --git a/modules/type/blocks/dap_chain_block_cache.c b/modules/type/blocks/dap_chain_block_cache.c index cf55de237f9d06df99bf004acd6d4d90800b9a0c..2d4defa28ea640aeb96ff1d48c6a209aa88b550d 100644 --- a/modules/type/blocks/dap_chain_block_cache.c +++ b/modules/type/blocks/dap_chain_block_cache.c @@ -67,6 +67,19 @@ dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block, return l_block_cache; } +/** + * @brief dap_chain_block_cache_dup + * @param a_block + * @return + */ +dap_chain_block_cache_t * dap_chain_block_cache_dup(dap_chain_block_cache_t * a_block) +{ + dap_chain_block_cache_t * l_ret = DAP_NEW_Z(dap_chain_block_cache_t); + memcpy(l_ret,a_block, sizeof (*a_block)); + memset(&l_ret->hh,0, sizeof (l_ret->hh)); // Drop hash handle to prevent its usage + return l_ret; +} + /** * @brief dap_chain_block_cache_get_by_hash * @param a_block_hash diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 62869d706cd5e3053c59c592977dd143dd11ef8c..4553ae187ee45e7e9b883466cb1eeafc5a13cd47 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -34,18 +34,37 @@ #include "dap_chain_node_cli_cmd.h" #define LOG_TAG "dap_chain_cs_blocks" +typedef struct dap_chain_tx_block_index +{ + time_t ts_added; + dap_chain_hash_fast_t tx_hash; + dap_chain_hash_fast_t block_hash; + UT_hash_handle hh; +} dap_chain_tx_block_index_t; + typedef struct dap_chain_cs_blocks_pvt { pthread_rwlock_t rwlock; - dap_chain_cs_blocks_t * blocks; + // Parent link + dap_chain_cs_blocks_t * cs_blocks; + + // 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; + dap_chain_block_cache_t * blocks_tx_treshold; + dap_chain_tx_block_index_t * tx_block_index; // To find block hash by tx hash + + // General lins dap_chain_block_cache_t * block_cache_first; // Mapped area start dap_chain_block_cache_t * block_cache_last; // Last block in mapped area - + dap_chain_hash_fast_t genesis_block_hash; uint64_t blocks_count; uint64_t difficulty; + bool is_celled; + + // For new block creating dap_chain_block_t * block_new; size_t block_new_size; } dap_chain_cs_blocks_pvt_t; @@ -178,6 +197,14 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config a_chain->_pvt = l_cs_blocks_pvt; pthread_rwlock_init(&l_cs_blocks_pvt->rwlock,NULL); + const char * l_genesis_blocks_hash_str = dap_config_get_item_str_default(a_chain_config,"blocks","genesis_block",NULL); + if ( l_genesis_blocks_hash_str ){ + int lhr; + if ( (lhr= dap_chain_hash_fast_from_str(l_genesis_blocks_hash_str,&l_cs_blocks_pvt->genesis_block_hash) )!= 0 ){ + log_it( L_ERROR, "Can't read hash from genesis_block \"%s\", ret code %d ", l_genesis_blocks_hash_str, lhr); + } + } + l_cs_blocks_pvt->is_celled = dap_config_get_item_bool_default(a_chain_config,"blocks","is_celled",false); // dap_chain_node_role_t l_net_role= dap_chain_net_get_role( dap_chain_net_by_id(a_chain->net_id) ); // Datum operations callbacks @@ -323,17 +350,21 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s switch ( l_subcmd ){ // Flush memory for the new block case SUBCMD_NEW_FLUSH:{ + pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock ); if ( PVT(l_blocks)->block_new ) DAP_DELETE( PVT(l_blocks)->block_new ); PVT(l_blocks)->block_new = dap_chain_block_new( PVT(l_blocks)->block_cache_last? &PVT(l_blocks)->block_cache_last->block_hash: NULL ); PVT(l_blocks)->block_new_size = sizeof (PVT(l_blocks)->block_new->hdr); + pthread_rwlock_unlock( &PVT(l_blocks)->rwlock ); } break; // Add datum to the forming new block case SUBCMD_NEW_DATUM_LIST:{ - + pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock ); + pthread_rwlock_unlock( &PVT(l_blocks)->rwlock ); }break; case SUBCMD_NEW_DATUM_DEL:{ + pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock ); if ( PVT(l_blocks)->block_new ){ dap_chain_hash_fast_t l_datum_hash; s_cli_parse_cmd_hash(a_argv,arg_index,a_argc,a_str_reply,"-datum", &l_datum_hash ); @@ -343,6 +374,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s "Error! Can't delete datum from hash because no forming new block! Check pls you role, it must be MASTER NODE or greater"); ret = -12; } + pthread_rwlock_unlock( &PVT(l_blocks)->rwlock ); }break; case SUBCMD_NEW_DATUM_ADD:{ size_t l_datums_count=1; @@ -482,12 +514,12 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s }break; case SUBCMD_LIST:{ + pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock); dap_string_t * l_str_tmp = dap_string_new(NULL); dap_string_append_printf(l_str_tmp,"%s.%s: Have %u blocks :\n", l_net->pub.name,l_chain->name,PVT(l_blocks)->blocks_count); dap_chain_block_cache_t * l_block_cache = NULL,*l_block_cache_tmp = NULL; - pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock); HASH_ITER(hh,PVT(l_blocks)->block_cache_first,l_block_cache, l_block_cache_tmp ) { char l_buf[50]; dap_string_append_printf(l_str_tmp,"\t%s: ts_create=%s", @@ -519,14 +551,110 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s static void s_callback_delete(dap_chain_t * a_chain) { dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS ( a_chain ); + pthread_rwlock_wrlock(&PVT(l_blocks)->rwlock); if(l_blocks->callback_delete ) l_blocks->callback_delete(l_blocks); if(l_blocks->_inheritor) DAP_DELETE(l_blocks->_inheritor); if(l_blocks->_pvt) DAP_DELETE(l_blocks->_pvt); + pthread_rwlock_unlock(&PVT(l_blocks)->rwlock); + pthread_rwlock_destroy(&PVT(l_blocks)->rwlock); + log_it(L_INFO,"callback_delete() called"); +} + +/** + * @brief s_add_atom_to_ledger + * @param a_blocks + * @param a_ledger + * @param a_block_cache + * @return + */ +static int s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t * a_ledger, 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 add anything to ledger", a_block_cache->block_hash_str); + return 1; // No errors just empty block + } + int l_ret=-1; + + for(size_t i=0; i<a_block_cache->datum_count; i++){ + dap_chain_datum_t *l_datum = a_block_cache->datum[i]; + switch (l_datum->header.type_id) { + case DAP_CHAIN_DATUM_TOKEN_DECL: { + dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data; + l_ret=dap_chain_ledger_token_load(a_ledger, l_token, l_datum->header.data_size); + } break; + case DAP_CHAIN_DATUM_TOKEN_EMISSION: { + dap_chain_datum_token_emission_t *l_token_emission = (dap_chain_datum_token_emission_t*) l_datum->data; + l_ret=dap_chain_ledger_token_emission_load(a_ledger, l_token_emission, l_datum->header.data_size); + } break; + case DAP_CHAIN_DATUM_TX: { + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data; + // Check tx correcntess + size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); + if (l_tx_size + sizeof (a_block_cache->block->hdr) > a_block_cache->block_size){ + log_it(L_WARNING, "Corrupted transaction in block, size %zd is greater than block's size %zd", l_tx_size, a_block_cache->block_size); + l_ret = -1; + break; + } + // don't save bad transactions to base + int l_ret = dap_chain_ledger_tx_load(a_ledger, l_tx); + if( l_ret != 1 ) + break; + + // Save tx hash -> block_hash link in hash table + dap_chain_tx_block_index_t * l_tx_block= DAP_NEW_Z(dap_chain_tx_block_index_t); + l_tx_block->ts_added = time(NULL); + memcpy(&l_tx_block->block_hash, &a_block_cache->block_hash, sizeof ( l_tx_block->block_hash)); + dap_hash_fast(l_tx, l_tx_size, &l_tx_block->tx_hash); + pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock ); + HASH_ADD(hh, PVT(a_blocks)->tx_block_index, tx_hash, sizeof(l_tx_block->tx_hash), l_tx_block); + pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); + } break; + default: + l_ret=-1; + } + if (l_ret != 0 ){ + log_it(L_WARNING, "Can't load datum #%d (%s) from block %s to ledger: code %d", i, dap_chain_datum_type_id_to_str(l_datum->header.type_id), + a_block_cache->block_hash_str, l_ret); + break; + } + + } + return l_ret; } +/** + * @brief s_add_atom_to_blocks + * @param a_blocks + * @param a_ledger + * @param a_block_cache + * @return + */ +static int s_add_atom_to_blocks(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t * a_ledger, dap_chain_block_cache_t * a_block_cache ) +{ + pthread_rwlock_rdlock( &PVT(a_blocks)->rwlock ); + int res = a_blocks->callback_block_verify(a_blocks,a_block_cache->block, a_block_cache->block_size); + if (res == 0 || memcmp( &a_block_cache->block_hash, &PVT(a_blocks)->genesis_block_hash, sizeof(a_block_cache->block_hash) ) == 0) { + log_it(L_DEBUG,"Dag event %s checked, add it to ledger", a_block_cache->block_hash_str ); + pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); + res = s_add_atom_to_ledger(a_blocks, a_ledger, a_block_cache); + if (res) { + pthread_rwlock_rdlock( &PVT(a_blocks)->rwlock ); + log_it(L_INFO,"Dag event %s checked, but ledger declined", a_block_cache->block_hash_str ); + pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); + return res; + } + //All correct, no matter for result + pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock ); + HASH_ADD(hh, PVT(a_blocks)->blocks,block_hash,sizeof (a_block_cache->block_hash), a_block_cache); + } else { + log_it(L_WARNING,"Dag event %s check failed: code %d", a_block_cache->block_hash_str, res ); + } + pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); + return res; +} /** * @brief s_callback_atom_add * @details Accept new atom in blockchain @@ -537,7 +665,50 @@ static void s_callback_delete(dap_chain_t * a_chain) */ 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_chain_atom_verify_res_t ret = ATOM_ACCEPT; + 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; + size_t l_block_size = a_atom_size; + dap_hash_fast(a_atom,a_atom_size, & l_block_hash); + dap_chain_block_cache_t * l_block_cache = dap_chain_block_cache_get_by_hash(l_block_hash); + if (l_block_cache ){ + ret = ATOM_PASS; + log_it(L_DEBUG, "... already present in blocks %s",l_block_cache->block_hash_str); + } else{ + l_block_cache = dap_chain_block_cache_new( l_block, l_block_size); + log_it(L_DEBUG, "... new block %s",l_block_cache->block_hash_str); + ret = ATOM_ACCEPT; + } + // verify hashes and consensus + if(ret == ATOM_ACCEPT){ + ret = s_callback_atom_verify (a_chain, a_atom, a_atom_size); + log_it(L_DEBUG, "Verified atom %p: code %d", a_atom, ret); + } + + if( ret == ATOM_ACCEPT){ + int l_consensus_check = s_add_atom_to_blocks(l_blocks, a_chain->ledger, l_block_cache); + if(!l_consensus_check){ + log_it(L_DEBUG, "... added"); + }else if (l_consensus_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS){ + pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock ); + HASH_ADD(hh, PVT(l_blocks)->blocks_tx_treshold, block_hash, sizeof(l_block_cache->block_hash), l_block_cache); + pthread_rwlock_unlock( &PVT(l_blocks)->rwlock ); + log_it(L_DEBUG, "... tresholded"); + ret = ATOM_MOVE_TO_THRESHOLD; + }else{ + log_it(L_DEBUG, "... error adding (code %d)", l_consensus_check); + ret = ATOM_REJECT; + } + } + // will added in callback s_chain_callback_atom_add_from_treshold() + //while(dap_chain_cs_dag_proc_treshold(l_dag, a_chain->ledger)); + + if(ret == ATOM_PASS){ + DAP_DELETE(l_block_cache); + } + return ret; } /** diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h index 35f115cdd34656b7c041077e80b42177a12fb8ea..d29cf3aaf45b35b76adc5d10be45a1b493e7e61a 100644 --- a/modules/type/blocks/include/dap_chain_block_cache.h +++ b/modules/type/blocks/include/dap_chain_block_cache.h @@ -62,5 +62,6 @@ void dap_chain_block_cache_deinit(); dap_chain_block_cache_t * dap_chain_block_cache_get_by_hash(dap_chain_hash_fast_t a_block_hash); dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block, size_t a_block_size); +dap_chain_block_cache_t * dap_chain_block_cache_dup(dap_chain_block_cache_t * a_block); void dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache); void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache); diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c index fb6f17b94b0e457e4eda14ecfdce6deceb252330..6823ea1c672472fa06ee5f846b266364830cde80 100644 --- a/modules/type/dag/dap_chain_cs_dag.c +++ b/modules/type/dag/dap_chain_cs_dag.c @@ -410,7 +410,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha int l_consensus_check = s_dap_chain_add_atom_to_events_table(l_dag, a_chain->ledger, l_event_item); if(!l_consensus_check){ log_it(L_DEBUG, "... added"); - }else if (l_consensus_check == DAP_CHAIN_LEDGER_TX_NO_PREVIOUS){ + }else if (l_consensus_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS){ HASH_ADD(hh, PVT(l_dag)->events_treshold, hash, sizeof(l_event_item->hash), l_event_item); log_it(L_DEBUG, "... tresholded"); ret = ATOM_MOVE_TO_THRESHOLD;