-
Constantin Papizh authored5dda118b
/*
* Authors:
* Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
* DeM Labs Inc. https://demlabs.net
* Kelvin Project https://github.com/kelvinblockchain
* Copyright (c) 2017-2018
* All rights reserved.
This file is part of DAP (Deus Applications Prototypes) the open source project
DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DAP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with any DAP based project. If not, see <http://www.gnu.org/licenses/>.
*/
#include <dap_chain_ledger.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include "dap_common.h"
#include "dap_strfuncs.h"
#include "dap_config.h"
#include "dap_chain_pvt.h"
#include "dap_chain.h"
#include "dap_chain_cert.h"
#include "dap_chain_cs.h"
#include <uthash.h>
#include <pthread.h>
#define LOG_TAG "chain"
typedef struct dap_chain_item_id {
dap_chain_id_t id;
dap_chain_net_id_t net_id;
} dap_chain_item_id_t;
typedef struct dap_chain_item {
dap_chain_item_id_t item_id;
dap_chain_t * chain;
UT_hash_handle hh;
} dap_chain_item_t;
static pthread_rwlock_t s_chain_items_rwlock = PTHREAD_RWLOCK_INITIALIZER;
static dap_chain_item_t * s_chain_items = NULL;
int s_prepare_env();
/**
* @brief dap_chain_init
* @return
*/
int dap_chain_init(void)
{
/*if (dap_chain_cert_init() != 0) {
log_it(L_CRITICAL,"Can't chain certificate storage module");
return -4;
}*/
uint16_t l_ca_folders_size = 0;
char ** l_ca_folders;
l_ca_folders = dap_config_get_array_str(g_config, "resources", "ca_folders", &l_ca_folders_size);
for (uint16_t i=0; i < l_ca_folders_size; i++){
#ifdef _WIN32
char l_temp[MAX_PATH] = {'\0'};
memcpy(l_temp, s_sys_dir_path, l_sys_dir_path_len);
memcpy(l_temp + l_sys_dir_path_len, l_ca_folders[i], strlen(l_ca_folders[i]));
//dap_sprintf(l_temp, "%s/%s", l_sys_dir_path, l_ca_folders[i]);
dap_chain_cert_add_folder(l_temp);
#else
dap_chain_cert_add_folder(l_ca_folders[i]);
#endif
}
// Cell sharding init
dap_chain_cell_init();
dap_chain_cs_init();
//dap_chain_show_hash_blocks_file(g_gold_hash_blocks_file);
//dap_chain_show_hash_blocks_file(g_silver_hash_blocks_file);
return 0;
}
/**
* @brief dap_chain_deinit
*/
void dap_chain_deinit(void)
{
dap_chain_item_t * l_item = NULL, *l_tmp = NULL;
pthread_rwlock_wrlock(&s_chain_items_rwlock);
HASH_ITER(hh, s_chain_items, l_item, l_tmp) {
dap_chain_delete(s_chain_items->chain);
DAP_DELETE(l_item);
}
pthread_rwlock_unlock(&s_chain_items_rwlock);
}
/**
* @brief dap_chain_load_net_cfg_name
* @param a_chan_net_cfg_name
* @return
*/
dap_chain_t * dap_chain_load_net_cfg_name(const char * a_chan_net_cfg_name)
{
}
/**
* @brief dap_chain_create
* @param a_chain_net_name
* @param a_chain_name
* @param a_chain_net_id
* @param a_chain_id
* @return
*/
dap_chain_t * dap_chain_create(dap_ledger_t* a_ledger, const char * a_chain_net_name, const char * a_chain_name, dap_chain_net_id_t a_chain_net_id, dap_chain_id_t a_chain_id )
{
dap_chain_t * l_ret = DAP_NEW_Z(dap_chain_t);
DAP_CHAIN_PVT_LOCAL_NEW(l_ret);
memcpy(l_ret->id.raw,a_chain_id.raw,sizeof(a_chain_id));
memcpy(l_ret->net_id.raw,a_chain_net_id.raw,sizeof(a_chain_net_id));
l_ret->name = strdup (a_chain_name);
l_ret->net_name = strdup (a_chain_net_name);
l_ret->ledger = a_ledger;
dap_chain_item_t * l_ret_item = DAP_NEW_Z(dap_chain_item_t);
l_ret_item->chain = l_ret;
memcpy(l_ret_item->item_id.id.raw ,a_chain_id.raw,sizeof(a_chain_id));
memcpy(l_ret_item->item_id.net_id.raw ,a_chain_net_id.raw,sizeof(a_chain_net_id));
pthread_rwlock_wrlock(&s_chain_items_rwlock);
HASH_ADD(hh,s_chain_items,item_id,sizeof(dap_chain_item_id_t),l_ret_item);
pthread_rwlock_unlock(&s_chain_items_rwlock);
return l_ret;
}
/**
* @brief dap_chain_delete
* @param a_chain
*/
void dap_chain_delete(dap_chain_t * a_chain)
{
dap_chain_item_t * l_item = NULL;
dap_chain_item_id_t l_chain_item_id = {
.id = a_chain->id,
.net_id = a_chain->net_id,
};
pthread_rwlock_wrlock(&s_chain_items_rwlock);
HASH_FIND(hh,s_chain_items,&l_chain_item_id,sizeof(dap_chain_item_id_t),l_item);
if( l_item){
HASH_DEL(s_chain_items, l_item);
if (a_chain->callback_delete )
a_chain->callback_delete(a_chain);
if ( a_chain->name)
DAP_DELETE (a_chain->name);
if ( a_chain->net_name)
DAP_DELETE (a_chain->net_name);
if (a_chain->_pvt ){
DAP_DELETE(DAP_CHAIN_PVT(a_chain)->file_storage_dir);
DAP_DELETE(a_chain->_pvt);
}
if (a_chain->_inheritor )
DAP_DELETE(a_chain->_inheritor);
DAP_DELETE(l_item);
}else
log_it(L_WARNING,"Trying to remove non-existent 0x%16llX:0x%16llX chain",a_chain->id.uint64,
a_chain->net_id.uint64);
a_chain->datum_types_count = 0;
DAP_DELETE (a_chain->datum_types);
pthread_rwlock_unlock(&s_chain_items_rwlock);
}
/**
* @brief dap_chain_find_by_id
* @param a_chain_net_id
* @param a_chain_id
* @param a_cell_id
* @return
*/
dap_chain_t * dap_chain_find_by_id(dap_chain_net_id_t a_chain_net_id,dap_chain_id_t a_chain_id)
{
dap_chain_item_id_t l_chain_item_id = {
.id = a_chain_id,
.net_id = a_chain_net_id,
};
dap_chain_item_t * l_ret_item = NULL;
pthread_rwlock_rdlock(&s_chain_items_rwlock);
HASH_FIND(hh,s_chain_items,&l_chain_item_id,sizeof(dap_chain_item_id_t),l_ret_item);
pthread_rwlock_unlock(&s_chain_items_rwlock);
if ( l_ret_item ){
return l_ret_item->chain;
}else
return NULL;
}
/**
* @brief dap_chain_load_from_cfg
* @param a_chain_net_name
* @param a_chain_net_id
* @param a_chain_cfg_path
* @return
*/
dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_chain_net_name,dap_chain_net_id_t a_chain_net_id, const char * a_chain_cfg_name)
{
log_it (L_DEBUG, "Loading chain from config \"%s\"", a_chain_cfg_name);
if ( a_chain_net_name){
dap_config_t * l_cfg = dap_config_open(a_chain_cfg_name);
if (l_cfg) {
dap_chain_t * l_chain = NULL;
dap_chain_id_t l_chain_id = {{0}};
const char * l_chain_id_str = NULL;
const char * l_chain_name = NULL;
// Recognize chains id
if ( l_chain_id_str = dap_config_get_item_str(l_cfg,"chain","id") ){
if ( sscanf(l_chain_id_str,"0x%016llX",&l_chain_id.uint64) !=1 ){
if ( sscanf(l_chain_id_str,"0x%016llx",&l_chain_id.uint64) !=1 ) {
if ( sscanf(l_chain_id_str,"%llu",&l_chain_id.uint64) !=1 ){
log_it (L_ERROR,"Can't recognize '%s' string as chain net id, hex or dec",l_chain_id_str);
dap_config_close(l_cfg);
return NULL;
}
}
}
}
if (l_chain_id_str ) {
log_it (L_NOTICE, "Chain id 0x%016lX ( \"%s\" )",l_chain_id.uint64 , l_chain_id_str) ;
}else {
log_it (L_ERROR,"Wasn't recognized '%s' string as chain net id, hex or dec",l_chain_id_str);
dap_config_close(l_cfg);
return NULL;
}
// Read chain name
if ( ( l_chain_name = dap_config_get_item_str(l_cfg,"chain","name") ) == NULL ){
log_it (L_ERROR,"Can't read chain net name ",l_chain_id_str);
dap_config_close(l_cfg);
return NULL;
}
// Read chain datum types
char** l_datum_types = NULL;
uint16_t l_datum_types_count = 0;
if((l_datum_types = dap_config_get_array_str(l_cfg, "chain", "datum_types", &l_datum_types_count)) == NULL) {
log_it(L_WARNING, "Can't read chain datum types ", l_chain_id_str);
//dap_config_close(l_cfg);
//return NULL;
}
l_chain = dap_chain_create(a_ledger,a_chain_net_name,l_chain_name, a_chain_net_id,l_chain_id);
if ( dap_chain_cs_create(l_chain, l_cfg) == 0 ) {
log_it (L_NOTICE,"Consensus initialized for chain id 0x%016llX",
l_chain_id.uint64 );
if ( dap_config_get_item_str_default(l_cfg , "files","storage_dir",NULL ) ) {
DAP_CHAIN_PVT ( l_chain)->file_storage_dir = strdup (
dap_config_get_item_str( l_cfg , "files","storage_dir" ) ) ;
if ( dap_chain_load_all( l_chain ) != 0 ){
dap_chain_save_all( l_chain );
log_it (L_NOTICE, "Loaded chain files");
}else {
dap_chain_save_all( l_chain );
log_it (L_NOTICE, "Initialized chain files");
}
} else{
log_it (L_INFO, "Not set file storage path, will not stored in files");
//dap_chain_delete(l_chain);
//l_chain = NULL;
}
}else{
log_it (L_ERROR, "Can't init consensus \"%s\"",dap_config_get_item_str_default( l_cfg , "chain","consensus","NULL"));
dap_chain_delete(l_chain);
l_chain = NULL;
}
// add datum types
if(l_chain && l_datum_types_count > 0) {
l_chain->datum_types = DAP_NEW_SIZE(dap_chain_type_t, l_datum_types_count * sizeof(dap_chain_type_t));
uint16_t l_count_recognized = 0;
for(uint16_t i = 0; i < l_datum_types_count; i++) {
if(!dap_strcmp(l_datum_types[i], "token")) {
l_chain->datum_types[l_count_recognized] = CHAIN_TYPE_TOKEN;
l_count_recognized++;
}
else if(!dap_strcmp(l_datum_types[i], "emission")) {
l_chain->datum_types[l_count_recognized] = CHAIN_TYPE_EMISSION;
l_count_recognized++;
}
else if(!dap_strcmp(l_datum_types[i], "transaction")) {
l_chain->datum_types[l_count_recognized] = CHAIN_TYPE_TX;
l_count_recognized++;
}
}
l_chain->datum_types_count = l_count_recognized;
}
dap_config_close(l_cfg);
return l_chain;
}else
return NULL;
} else {
log_it (L_WARNING, "NULL net_id string");
return NULL;
}
}
/**
* @brief dap_chain_has_file_store
* @param a_chain
* @return
*/
bool dap_chain_has_file_store(dap_chain_t * a_chain)
{
return DAP_CHAIN_PVT(a_chain)->file_storage_dir != NULL;
}
/**
* @brief dap_chain_save_all
* @param l_chain
* @return
*/
int dap_chain_save_all (dap_chain_t * l_chain)
{
int ret = -1;
dap_chain_cell_t * l_item, *l_item_tmp = NULL;
HASH_ITER(hh,l_chain->cells,l_item,l_item_tmp){
dap_chain_cell_file_update(l_item);
if (ret <0 )
ret++;
}
return ret;
}
/**
* @brief dap_chain_load_all
* @param l_chain
* @return
*/
int dap_chain_load_all (dap_chain_t * l_chain)
{
int l_ret = -2;
if(!l_chain)
return l_ret;
DIR * l_dir = opendir(DAP_CHAIN_PVT(l_chain)->file_storage_dir);
if( l_dir ) {
struct dirent * l_dir_entry;
l_ret = -1;
while((l_dir_entry=readdir(l_dir))!=NULL){
const char * l_filename = l_dir_entry->d_name;
size_t l_filename_len = strlen (l_filename);
// Check if its not special dir entries . or ..
if( strcmp(l_filename,".") && strcmp(l_filename,"..") ){
// If not check the file's suffix
const char l_suffix[]=".dchaincell";
size_t l_suffix_len = strlen(l_suffix);
if (strncmp(l_filename+ l_filename_len-l_suffix_len,l_suffix,l_suffix_len) == 0 ){
if ( dap_chain_cell_load(l_chain,l_filename) == 0 )
l_ret = 0;
}
}
}
closedir(l_dir);
}
return l_ret;
}
/**
* @brief dap_chain_init_net_cfg_name
* @param a_chain_net_cfg_name
* @return
*/
dap_chain_t * dap_chain_init_net_cfg_name(const char * a_chain_net_cfg_name)
{
return NULL;
}
/**
* @brief dap_chain_close
* @param a_chain
*/
void dap_chain_close(dap_chain_t * a_chain)
{
if(a_chain){
if(a_chain->callback_delete)
a_chain->callback_delete(a_chain);
}else
log_it(L_WARNING,"Tried to close null pointer");
}
/**
* @brief dap_chain_info_dump_log
* @param a_chain
*/
void dap_chain_info_dump_log(dap_chain_t * a_chain)
{
}