diff --git a/CMakeLists.txt b/CMakeLists.txt index 10e86caa95db39e8486166816f9f48ca91a389c8..270e002866420dfa5e44e1417093d0504f61ec10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,14 @@ add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"") set(DAPSDK_MODULES "") message("Cellframe modules: ${CELLFRAME_MODULES}") +if (CELLFRAME_MODULES MATCHES "modules-dynamic") + add_definitions("-DDAP_MODULES_DYNAMIC") +endif() + +if (CELLFRAME_MODULES MATCHES "srv-stake") + add_definitions("-DDAP_SRV_STAKE_USED") +endif() + if (CELLFRAME_MODULES MATCHES "core") SET(DAPSDK_MODULES "${DAPSDK_MODULES} core crypto") endif() @@ -138,45 +146,43 @@ endif() # Enable service Application if (CELLFRAME_MODULES MATCHES "srv-app") message("[+] Module 'srv-app'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app ) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app) endif() # Enable service Application DB if (CELLFRAME_MODULES MATCHES "srv-app-db") message("[+] Module 'srv-app-db'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app_db ) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app_db) endif() # Enable service datum process if (CELLFRAME_MODULES MATCHES "srv-datum") message("[+] Module 'srv-datum'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_datum ) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_datum) endif() # Enable service VPN if (CELLFRAME_MODULES MATCHES "srv-vpn") message("[+] Module 'srv-vpn'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_vpn ) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_vpn) endif() # Enable service eXchange if (CELLFRAME_MODULES MATCHES "srv-xchange") message("[+] Module 'srv-xchange'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_xchange ) + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_xchange) endif() # Enable service of delegated stake if (CELLFRAME_MODULES MATCHES "srv-stake") message("[+] Module 'srv-stake'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_stake ) - add_definitions("-DDAP_SRV_STAKE_USED") + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_stake) endif() # Enable service for dynamic modules if (CELLFRAME_MODULES MATCHES "modules-dynamic") message("[+] Module 'dap_modules_dynamic_cdb'") - set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_modules_dynamic_cdb ) - add_definitions("-DDAP_MODULES_DYNAMIC") + set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_modules_dynamic_cdb) endif() if (WIN32) diff --git a/dap-sdk/core/include/dap_module.h b/dap-sdk/core/include/dap_module.h index b3193c43dcfe9365439823c487542e61f4e56e97..bae7e6df32518e9fea7232bdf0f05fce6568f598 100755 --- a/dap-sdk/core/include/dap_module.h +++ b/dap-sdk/core/include/dap_module.h @@ -35,7 +35,7 @@ typedef struct dap_module { #define DAP_MODULE_ARGS_MAX 10 typedef struct dap_module_args { const char * name; - const char * args[DAP_MODULE_ARGS_MAX]; // ARGS could me not more than DAP_MODULE_ARGS_MAX define + const char * args[DAP_MODULE_ARGS_MAX]; // ARGS could be not more than DAP_MODULE_ARGS_MAX define } dap_module_args_t; int dap_module_add(const char * a_name, unsigned int a_version, const char * a_dependensies, diff --git a/dap-sdk/crypto/src/dap_hash.c b/dap-sdk/crypto/src/dap_hash.c index a826d81f6f468bd7d6301d41314484a47283b942..7a625746845f623133c80e41c4db00ea531f1cfc 100755 --- a/dap-sdk/crypto/src/dap_hash.c +++ b/dap-sdk/crypto/src/dap_hash.c @@ -54,7 +54,7 @@ int dap_chain_hash_fast_from_str( const char * a_hash_str, dap_chain_hash_fast_t *(a_hash->raw + l_offset / 2 - 1) = l_byte; } return 0; - }else // Wromg string len + }else // Wrong string len return -1; } diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index 3c6546b95cd26716903ee06a98d23c5d20b88109..cc0816448798cf2e034b5a6928766af4b9892312 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -1767,24 +1767,26 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t size_t l_pkey_ser_size = 0; const uint8_t *l_pkey_ser = dap_sign_get_pkey(l_sign, &l_pkey_ser_size); dap_chain_tx_out_cond_t *l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out; - if (l_pkey_ser_size != l_prev_pkey_ser_size || - memcmp(l_prev_pkey_ser, l_pkey_ser, l_prev_pkey_ser_size)) { - // 5b. Call verificator for conditional output - dap_chain_ledger_verificator_t *l_verificator; - int l_tmp = (int)l_tx_prev_out_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) { - if(s_debug_more) - log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp); - l_err_num = -13; - break; - } - if (l_verificator->callback(l_tx_prev_out_cond, a_tx) == false) { - l_err_num = -14; - break; - } + bool l_owner = false; + if (l_pkey_ser_size == l_prev_pkey_ser_size && + !memcmp(l_prev_pkey_ser, l_pkey_ser, l_prev_pkey_ser_size)) { + l_owner = true; + } + // 5b. Call verificator for conditional output + dap_chain_ledger_verificator_t *l_verificator; + int l_tmp = (int)l_tx_prev_out_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) { + if(s_debug_more) + log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp); + l_err_num = -13; + break; + } + if (l_verificator->callback(l_tx_prev_out_cond, a_tx, l_owner) == false) { + l_err_num = -14; + break; } bound_item->out.tx_prev_out_cond = l_tx_prev_out_cond; // calculate sum of values from previous transactions @@ -2170,6 +2172,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, // find all bound pairs 'in' and 'out' dap_list_t *l_list_tmp = l_list_bound_items; char *l_ticker_trl = NULL, *l_ticker_old_trl = NULL; + bool l_stake_updated = false; // Update balance: deducts while(l_list_tmp) { dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data; @@ -2220,6 +2223,19 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->in.tx_cur_in_cond; /// Mark 'out' item in cache because it used l_tx_prev_out_used_idx = l_tx_in_cond->header.tx_out_prev_idx; + // Update stakes if any + dap_chain_tx_out_cond_t *l_cond = bound_item->out.tx_prev_out_cond; + if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE) { + dap_chain_ledger_verificator_t *l_verificator; + int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE; + 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) { + l_verificator->callback(l_cond, a_tx, true); + } + l_stake_updated = true; + } } // add a used output memcpy(&(l_prev_item_out->cache_data.tx_hash_spent_fast[l_tx_prev_out_used_idx]), l_tx_hash, sizeof(dap_chain_hash_fast_t)); @@ -2274,16 +2290,28 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) { dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data; if (l_type == TX_ITEM_TYPE_OUT_COND) { + // Update stakes if any + dap_chain_tx_out_cond_t *l_cond = (dap_chain_tx_out_cond_t *)l_tx_out->data; + if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE && !l_stake_updated) { + dap_chain_ledger_verificator_t *l_verificator; + int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE; + 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) { + l_verificator->callback(NULL, a_tx, true); + } + } continue; // balance raise will be with next conditional transaction } dap_chain_tx_out_t *l_out_item = NULL; dap_chain_tx_out_ext_t *l_out_item_ext = NULL; if (l_type == TX_ITEM_TYPE_OUT) { - l_out_item = l_tx_out->data; + l_out_item = (dap_chain_tx_out_t *)l_tx_out->data; } else { - l_out_item_ext = l_tx_out->data; + l_out_item_ext = (dap_chain_tx_out_ext_t *)l_tx_out->data; } - if (l_out_item && l_ticker_trl) { + if ((l_out_item || l_out_item_ext) && l_ticker_trl) { dap_chain_addr_t *l_addr = (l_type == TX_ITEM_TYPE_OUT) ? &l_out_item->addr : &l_out_item_ext->addr; diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h index 31baa98f0f70fb9ccf3f3a8a963fb197c7e18c50..9dee8945dae21b46cb55060dba6c4979f7d51a81 100644 --- a/modules/chain/include/dap_chain_ledger.h +++ b/modules/chain/include/dap_chain_ledger.h @@ -42,7 +42,7 @@ typedef struct dap_ledger { void *_internal; } dap_ledger_t; -typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx); +typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner); // Checks the emission of the token, usualy on zero chain #define DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION 0x0001 diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index 96f0ae56df8970dd701729f088e9d0bcc0607efa..38cde942ce07b84b0891e1316f7e2965674507eb 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -277,7 +277,8 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap } dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value, long double a_fee_value, - dap_chain_addr_t *a_fee_addr, const void *a_params, uint32_t a_params_size) + dap_chain_addr_t *a_fee_addr, dap_chain_addr_t *a_hldr_addr, + const void *a_params, uint32_t a_params_size) { dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size); l_item->header.item_type = TX_ITEM_TYPE_OUT_COND; @@ -286,6 +287,7 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_c l_item->subtype.srv_stake.srv_uid = a_srv_uid; l_item->subtype.srv_stake.fee_value = a_fee_value; memcpy(&l_item->subtype.srv_stake.fee_addr, a_fee_addr, sizeof(dap_chain_addr_t)); + memcpy(&l_item->subtype.srv_stake.hldr_addr, a_hldr_addr, sizeof(dap_chain_addr_t)); l_item->params_size = a_params_size; if (a_params_size) { memcpy(l_item->params, a_params, a_params_size); diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h index e194c7c33645b132b9560410e9a07565af2f95a7..3b891bc45ca90e6ad24e0f375563c698a2de70cb 100644 --- a/modules/common/include/dap_chain_datum_tx_items.h +++ b/modules/common/include/dap_chain_datum_tx_items.h @@ -129,7 +129,8 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap * return item, NULL Error */ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value, long double a_fee_value, - dap_chain_addr_t *a_fee_addr, const void *a_params, uint32_t a_params_size); + dap_chain_addr_t *a_fee_addr, dap_chain_addr_t *a_hldr_addr, + const void *a_params, uint32_t a_params_size); /** * Create item dap_chain_tx_sig_t * diff --git a/modules/common/include/dap_chain_datum_tx_out_cond.h b/modules/common/include/dap_chain_datum_tx_out_cond.h index b0b099572a7b8eb95cd5dcdbb3a36c976b000415..3d96e7faf7f764e0020f5808048f57303c527630 100644 --- a/modules/common/include/dap_chain_datum_tx_out_cond.h +++ b/modules/common/include/dap_chain_datum_tx_out_cond.h @@ -32,7 +32,8 @@ typedef enum dap_chain_tx_out_cond_subtype { DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY = 0x01, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE = 0x02, - DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x03 + DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x13, + DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE = 0xFA // Virtual type for stake update verificator } dap_chain_tx_out_cond_subtype_t; DAP_STATIC_INLINE const char *dap_chain_tx_out_cond_subtype_to_str(dap_chain_tx_out_cond_subtype_t a_subtype){ @@ -85,6 +86,8 @@ typedef struct dap_chain_tx_out_cond { struct { // Service uid that only could be used for this outout dap_chain_net_srv_uid_t srv_uid; + // Stake holder address + dap_chain_addr_t hldr_addr; // Fee address dap_chain_addr_t fee_addr; // Fee value in percent diff --git a/modules/consensus/block-poa/dap_chain_cs_block_poa.c b/modules/consensus/block-poa/dap_chain_cs_block_poa.c index dc7f7b131ef93bb347507153e591afffa95427ad..aa93918c49be22d8232d0e8460ff6990e7c3ce4e 100644 --- a/modules/consensus/block-poa/dap_chain_cs_block_poa.c +++ b/modules/consensus/block-poa/dap_chain_cs_block_poa.c @@ -27,6 +27,7 @@ #include "dap_enc_base58.h" #include "dap_cert.h" #include "dap_chain.h" +#include "dap_chain_pvt.h" #include "dap_chain_block.h" #include "dap_chain_block_cache.h" #include "dap_chain_cs_blocks.h" @@ -340,3 +341,13 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t * a_blocks, dap_chain_b return l_signs_verified_count >= l_poa_pvt->auth_certs_count_verify ? 0 : -1; } +dap_cert_t **dap_chain_cs_block_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count) +{ + dap_chain_pvt_t *l_chain_pvt = DAP_CHAIN_PVT(a_chain); + if (strcmp(l_chain_pvt->cs_name, "block_poa")) + return NULL; + dap_chain_cs_block_poa_pvt_t *l_poa_pvt = PVT(DAP_CHAIN_CS_BLOCK_POA(DAP_CHAIN_CS_BLOCKS(a_chain))); + if (a_auth_certs_count) + *a_auth_certs_count = l_poa_pvt->auth_certs_count; + return l_poa_pvt->auth_certs; +} diff --git a/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h b/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h index e2bc7b718b3eea2011854a11178443a34b753024..2ccd4f70254ffd26a8b7da68560c2929d96e4db3 100644 --- a/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h +++ b/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h @@ -38,3 +38,4 @@ typedef struct dap_chain_cs_block_poa int dap_chain_cs_block_poa_init(void); void dap_chain_cs_block_poa_deinit(void); +dap_cert_t **dap_chain_cs_block_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count); diff --git a/modules/consensus/block-pos/dap_chain_cs_block_pos.c b/modules/consensus/block-pos/dap_chain_cs_block_pos.c index 7b6d0dfc3b70565d0f7606b784953e2c4e63d2f4..90ffe94de3f5e68243181e331605e6c71697be4d 100644 --- a/modules/consensus/block-pos/dap_chain_cs_block_pos.c +++ b/modules/consensus/block-pos/dap_chain_cs_block_pos.c @@ -252,44 +252,26 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl return -41; } - /*dap_chain_hash_fast_t l_pkey_hash; - if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) { - log_it(L_WARNING, "Block's sign has no any key"); - return -5; - } - dap_chain_addr_t l_addr = {}; - dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_blocks->chain->net_id); - if (l_sig_pos == 0) { + dap_chain_addr_t l_addr = {}; + dap_chain_hash_fast_t l_pkey_hash; + dap_sign_get_pkey_hash(l_sign, &l_pkey_hash); + dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_blocks->chain->net_id); size_t l_datums_count = 0; dap_chain_datum_t **l_datums = dap_chain_block_get_datums(a_block, a_block_size, &l_datums_count); - for (unsigned i = 0; i < l_datums_count; i++) { - if (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX) { - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data; - if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) { - log_it(L_WARNING,"Not passed stake validator with datum %u of block %p on chain %s", i, a_block, a_blocks->chain->name); - return -6; - } - } + if (!l_datums || !l_datums_count) { + log_it(L_WARNING, "No datums in block %p on chain %s", a_block, a_blocks->chain->name); + return -7; } - } - - bool l_is_enough_balance = false; - for (size_t i = 0; i < l_pos_pvt->tokens_hold_size; i++) { - uint128_t l_balance = dap_chain_ledger_calc_balance(a_blocks->chain->ledger, &l_addr, l_pos_pvt->tokens_hold[i]); - uint64_t l_value = dap_chain_uint128_to(l_balance); - if (l_value >= l_pos_pvt->tokens_hold_value[i]) { - l_verified_num++; - l_is_enough_balance = true; - break; + for (size_t i = 0; i < l_datums_count; i++) { + if (!dap_chain_net_srv_stake_validator(&l_addr, l_datums[i])) { + log_it(L_WARNING, "Not passed stake validator datum %zu with block %p on chain %s", i, a_block, a_blocks->chain->name); + DAP_DELETE(l_datums); + return -6; + } } + DAP_DELETE(l_datums); } - if (!l_is_enough_balance) { - char *l_addr_str = dap_chain_addr_to_str(&l_addr); - log_it(L_WARNING, "Verify of block is false, because balance is not enough for addr=%s", l_addr_str); - DAP_DELETE(l_addr_str); - return -1; - }*/ // TODO comlete stake validator for all datums in the block } // Check number 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 b759fddcec890219dc3ad34eea6f6d6456ee6760..ef2ef81218e97053e8e3bc658673289036518f8b 100644 --- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c +++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c @@ -36,6 +36,7 @@ #include "dap_common.h" #include "dap_strfuncs.h" #include "dap_enc_base58.h" +#include "dap_chain_pvt.h" #include "dap_chain_net.h" #include "dap_chain_node_cli.h" #include "dap_chain_node_cli_cmd.h" @@ -402,24 +403,6 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_ if (dap_cert_compare_with_sign ( l_poa_pvt->auth_certs[j], l_sign) == 0) l_verified++; } - if (i == 0) { - dap_chain_hash_fast_t l_pkey_hash; - if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) { - log_it(L_WARNING, "Event's sign has no any key"); - return -5; - } - dap_chain_addr_t l_addr = {}; - dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id); - dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event, a_dag_event_size); - if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) { - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data; - if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) { - log_it(L_WARNING,"Not passed stake validator event %p", a_dag_event); - return -6; - } - } - } - } return l_verified >= l_poa_pvt->auth_certs_count_verify ? 0 : -1; }else if (a_dag_event->header.hash_count == 0){ @@ -437,3 +420,13 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_ } } +dap_cert_t **dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count) +{ + dap_chain_pvt_t *l_chain_pvt = DAP_CHAIN_PVT(a_chain); + if (strcmp(l_chain_pvt->cs_name, "dag_poa")) + return NULL; + dap_chain_cs_dag_poa_pvt_t *l_poa_pvt = PVT(DAP_CHAIN_CS_DAG_POA(DAP_CHAIN_CS_DAG(a_chain))); + if (a_auth_certs_count) + *a_auth_certs_count = l_poa_pvt->auth_certs_count; + return l_poa_pvt->auth_certs; +} diff --git a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h index b6f05be8207df185de0af5d4ae8e09c884de3e18..c437ff91d2f0f6f47e969196bab192cff9697609 100644 --- a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h +++ b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h @@ -23,6 +23,7 @@ */ #pragma once #include "dap_chain_cs_dag.h" +#include "dap_cert.h" typedef struct dap_chain_cs_dag_poa { @@ -37,3 +38,4 @@ typedef struct dap_chain_cs_dag_poa int dap_chain_cs_dag_poa_init(void); void dap_chain_cs_dag_poa_deinit(void); +dap_cert_t **dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count); diff --git a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c index 2641129fd34e675312392d03f221b726879cd8ce..367d76b0e52d8c07af9b1d5c4b33fe2c5b9f5e04 100644 --- a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c +++ b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c @@ -234,7 +234,6 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_ } if ( a_dag_event->header.signs_count >= l_pos_pvt->confirmations_minimum ){ uint16_t l_verified_num = 0; - dap_chain_addr_t l_addr = { 0 }; for ( size_t l_sig_pos=0; l_sig_pos < a_dag_event->header.signs_count; l_sig_pos++ ){ dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event, a_dag_event_size,l_sig_pos); @@ -258,65 +257,18 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_ return -41; } - if (!l_dag_event_size_without_sign){ - log_it(L_WARNING,"Event has nothing except sign, nothing to verify so I pass it (who knows why we have it?)"); - return 0; - } - - dap_chain_hash_fast_t l_pkey_hash; - if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) { - log_it(L_WARNING, "Event's sign has no any key"); - return -5; - } - dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id); - - - if (l_sig_pos == 0) { - dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event,a_dag_event_size); - if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) { - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data; - if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) { - log_it(L_WARNING,"Not passed stake validator with event %p on chain %s", a_dag_event, a_dag->chain->name); - return -6; - } + dap_chain_addr_t l_addr = {}; + dap_chain_hash_fast_t l_pkey_hash; + dap_sign_get_pkey_hash(l_sign, &l_pkey_hash); + dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id); + dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event, a_dag_event_size); + if (!dap_chain_net_srv_stake_validator(&l_addr, l_datum)) { + log_it(L_WARNING, "Not passed stake validator with event %p on chain %s", a_dag_event, a_dag->chain->name); + return -6; } } - /* - dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(a_dag_event); - // transaction include emission? - bool l_is_emit = false; - if(l_datum && l_datum->header.type_id == DAP_CHAIN_DATUM_TX) { - // transaction - dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data; - // find Token items - dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL); - if(l_list_tx_token) - l_is_emit = true; - dap_list_free(l_list_tx_token); - } - // if emission then the wallet can be with zero balance - if(l_is_emit) - return 0;*/ - - bool l_is_enough_balance = false; - for (size_t i =0; i <l_pos_pvt->tokens_hold_size; i++){ - uint128_t l_balance = dap_chain_ledger_calc_balance ( a_dag->chain->ledger , &l_addr, l_pos_pvt->tokens_hold[i] ); - uint64_t l_value = dap_chain_uint128_to(l_balance); - if (l_value >= l_pos_pvt->tokens_hold_value[i]) { - l_verified_num++; - l_is_enough_balance = true; - break; - } - } - if (! l_is_enough_balance ){ - char *l_addr_str = dap_chain_addr_to_str(&l_addr); - log_it(L_WARNING, "Verify of event is false, because bal is not enough for addr=%s", l_addr_str); - DAP_DELETE(l_addr_str); - return -1; - } } - // Check number if ( l_verified_num >= l_pos_pvt->confirmations_minimum ){ // Passed all checks diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index b4a514402627a634fcdc4afbd7acd8532b09bbfc..de768f81210ee225b1748fe7341d27d10a9b7cf9 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -99,7 +99,6 @@ #include "dap_stream_ch.h" #include "dap_stream_ch_pkt.h" #include "dap_chain_node_dns_client.h" - #include "dap_module.h" #include <stdio.h> @@ -2865,11 +2864,14 @@ void dap_chain_net_dump_datum(dap_string_t * a_str_out, dap_chain_datum_t * a_da case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE:{ dap_string_append_printf(a_str_out,"\tsubtype: DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE\n"); }break; + default:{ + dap_string_append_printf(a_str_out,"\tsubtype: UNKNOWN\n"); + }break; } dap_string_append_printf(a_str_out,"\tparams_size : %u\n", l_out->params_size ); } break; - case TX_ITEM_TYPE_RECEIPT:{} break; - default:{} + case TX_ITEM_TYPE_RECEIPT: + default: break; } n++; } diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 8d4e8ed037ebba59a603ffc41b69e61867e8ec17..f6ec0d03f716cc22f3426cd96dab45b6e7ae936a 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -274,7 +274,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum, ((dap_chain_tx_out_cond_t*)item)->header.value, dap_chain_tx_out_cond_subtype_to_str(((dap_chain_tx_out_cond_t*)item)->header.subtype)); switch (((dap_chain_tx_out_cond_t*)item)->header.subtype) { - case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: l_hash_str_tmp = dap_chain_hash_fast_to_str_new(&((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.pkey_hash); dap_string_append_printf(a_str_out, "\t\t\t unit: 0x%08x\n" "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n" @@ -289,7 +289,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum, ((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.unit_price_max_datoshi); DAP_FREE(l_hash_str_tmp); break; - case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE: + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE: dap_string_append_printf(a_str_out, "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n" "\t\t\t addr: %s\n" "\t\t\t value: %Lf", @@ -299,7 +299,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum, ), ((dap_chain_tx_out_cond_t*)item)->subtype.srv_stake.fee_value); break; - case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: dap_string_append_printf(a_str_out, "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n" "\t\t\t net id: 0x%016"DAP_UINT64_FORMAT_x"\n" "\t\t\t token: %s\n" @@ -314,6 +314,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum, ), ((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.value); break; + default: break; } break; case TX_ITEM_TYPE_OUT_EXT: diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt index 25282398a7c21a93efeaa7679ba3afb0dcb5a976..b6661c7f1b94abb872d0e6f63babbdaa7a086a32 100644 --- a/modules/net/srv/CMakeLists.txt +++ b/modules/net/srv/CMakeLists.txt @@ -7,12 +7,17 @@ file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h libmaxminddb/*.h) add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS}) +set(NET_SRV_LIBS dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet) + if (CELLFRAME_MODULES MATCHES "modules-dynamic") - target_link_libraries(dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet dap_modules_dynamic_cdb) -else() - target_link_libraries(dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet) + set(NET_SRV_LIBS ${NET_SRV_LIBS} dap_modules_dynamic_cdb) endif() +#if (CELLFRAME_MODULES MATCHES "srv-stake") +# set(NET_SRV_LIBS ${NET_SRV_LIBS} dap_chain_net_srv_stake) +#endif() + +target_link_libraries(${NET_SRV_LIBS}) target_include_directories(dap_chain_net_srv INTERFACE .) target_include_directories(${PROJECT_NAME} PUBLIC include) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/uthash/src) diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c index b8d0e53fdbe66523ea9f90cac4cdf865886eba6b..21dcd4d34b4f260c8dcd8789f126596593b4ea79 100644 --- a/modules/net/srv/dap_chain_net_srv_order.c +++ b/modules/net/srv/dap_chain_net_srv_order.c @@ -30,12 +30,6 @@ #include "dap_enc_base58.h" #include "dap_chain_global_db.h" #include "dap_chain_net_srv_countries.h" -#if DAP_SRV_STAKE_USED -#include "dap_chain_net_srv_stake.h" -#else -static bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr) { UNUSED(a_addr); return false; } -#endif -//#include "dap_chain_net_srv_geoip.h" #define LOG_TAG "dap_chain_net_srv_order" @@ -544,7 +538,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const DAP_DELETE(l_gdb_group_str); return; } - dap_chain_hash_fast_t l_pkey_hash; + /*dap_chain_hash_fast_t l_pkey_hash; if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) { dap_chain_global_db_gr_del(dap_strdup(a_key), a_group); DAP_DELETE(l_gdb_group_str); @@ -556,7 +550,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const uint64_t l_solvency = dap_chain_uint128_to(l_balance); if (l_solvency < l_order->price && !dap_chain_net_srv_stake_key_delegated(&l_addr)) { dap_chain_global_db_gr_del(dap_strdup(a_key), a_group); - } + }*/ } DAP_DELETE(l_gdb_group_str); } diff --git a/modules/service/stake/CMakeLists.txt b/modules/service/stake/CMakeLists.txt index e50be120ada65584254d16bd4a764594052e0722..e6217cf00995e909380b99444018ef70a5235501 100644 --- a/modules/service/stake/CMakeLists.txt +++ b/modules/service/stake/CMakeLists.txt @@ -9,4 +9,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_SRV_STAKE_SRCS} ${DAP_SRV_STAKE_HEADERS target_include_directories(dap_chain_crypto INTERFACE .) target_include_directories(${PROJECT_NAME} PUBLIC include) -target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv) +target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv dap_chain_cs_dag_poa dap_chain_cs_block_poa) diff --git a/modules/service/stake/dap_chain_net_srv_stake.c b/modules/service/stake/dap_chain_net_srv_stake.c index 31a05d446cc7980f4aff9c7f2121cf544d53f7e1..ea3594eff8f126b8fa926597f550813b5053d332 100644 --- a/modules/service/stake/dap_chain_net_srv_stake.c +++ b/modules/service/stake/dap_chain_net_srv_stake.c @@ -29,13 +29,15 @@ #include "dap_chain_common.h" #include "dap_chain_mempool.h" #include "dap_chain_net_srv_common.h" +#include "dap_chain_cs_block_poa.h" +#include "dap_chain_cs_dag_poa.h" #include "dap_chain_net_srv_stake.h" #define LOG_TAG "dap_chain_net_srv_stake" static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply); -static dap_chain_net_srv_stake_t *s_srv_stake; +static dap_chain_net_srv_stake_t *s_srv_stake = NULL; /** * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel @@ -46,22 +48,27 @@ static dap_chain_net_srv_stake_t *s_srv_stake; int dap_chain_net_srv_stake_init() { dap_chain_node_cli_cmd_item_create("srv_stake", s_cli_srv_stake, "Delegated stake service commands", - "srv_stake order create -net <net name> -from_addr <addr> -token <ticker> -coins <value> -cert <name> -fee_percent <value>\n" - "\tCreate a new order with specified amount of datoshi to delegate it to the specified address." - "The fee with specified percent with this delagation will be returned to the fee address pointed by delegator\n" - "srv_stake order remove -net <net name> -order <order hash> [-H hex|base58(default)]\n" + "srv_stake order create -net <net name> -addr_hldr <addr> -token <ticker> -coins <value> -cert <name> -fee_percent <value>\n" + "\tCreate a new order with specified amount of datoshi to delegate specified cert from the specified address.\n" + "\tThe fee with specified percent with this delagation will be returned to the fee address pointed by delegator\n" + "srv_stake order declare -net <net name> -wallet <name> -token <ticker> -coins <value> -fee_percent <value>" + "\tCreate a new order with specified amount of datoshi and fee which holder is ready to stake.\n" + "srv_stake order remove -net <net name> -order <order hash> [-H <hex | base58(default)>]\n" "\tRemove order with specified hash\n" - "srv_stake order update -net <net name> -order <order hash> -cert <name> [-H hex|base58(default)]" - "{-from_addr <addr> | -token <ticker> -coins <value> | -fee_percent <value>}\n" + "srv_stake order update -net <net name> -order <order hash> {-cert <name> | -wallet <name>} [-H <hex | base58(default)>]" + "{[-addr_hldr <addr>] [-token <ticker>] [-coins <value>] [-fee_percent <value>] |" + " | [-token <ticker>] [-coins <value>] -fee_percent <value>]\n" "\tUpdate order with specified hash\n" "srv_stake order list -net <net name>\n" "\tGet the stake orders list within specified net name\n" - "srv_stake delegate -order <order hash> -net <net name> -wallet <wallet_name> -fee_addr <addr>\n" + "srv_stake delegate -order <order hash> -net <net name> -wallet <name> -fee_addr <addr>\n" "\tDelegate tokens with specified order within specified net name. Specify fee address\n" + "srv_stake approve -net <net name> -tx <transaction hash> -cert <root cert name>\n" + "\tApprove stake transaction by root node certificate within specified net name.\n" "srv_stake transactions -net <net name> {-addr <addr from>}\n" - "\tShow the list of active stake transactions (optional delegated from addr)\n" + "\tShow the list of requested, active and canceled stake transactions (optional delegated from addr)\n" "srv_stake invalidate -net <net name> -tx <transaction hash> -wallet <wallet name>\n" - "\tInvalidate stake transaction by hash within net name and return stake to specified wallet\n" + "\tInvalidate requested stake transaction by hash within net name and return stake to specified wallet\n" ); s_srv_stake = DAP_NEW_Z(dap_chain_net_srv_stake_t); uint16_t l_net_count; @@ -73,6 +80,16 @@ int dap_chain_net_srv_stake_init() dap_chain_tx_out_cond_t *l_out_cond; int l_out_cond_idx; char l_token[DAP_CHAIN_TICKER_SIZE_MAX]; + size_t l_auth_certs_count = 0; + dap_cert_t **l_auth_certs = NULL; + for (dap_chain_t *l_chain = l_net_list[i]->pub.chains; l_chain; l_chain = l_chain->next) { + l_auth_certs = dap_chain_cs_dag_poa_get_auth_certs(l_chain, &l_auth_certs_count); + if (l_auth_certs) + break; + l_auth_certs = dap_chain_cs_block_poa_get_auth_certs(l_chain, &l_auth_certs_count); + if (l_auth_certs) + break; + } // Find all stake transactions do { l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(l_ledger, &l_tx_cur_hash, &l_out_cond, &l_out_cond_idx, l_token); @@ -83,24 +100,36 @@ int dap_chain_net_srv_stake_init() continue; if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &l_tx_cur_hash, l_out_cond_idx)) continue; + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx_tmp, NULL, + TX_ITEM_TYPE_SIG, NULL); + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig); + if (!l_sign) { + continue; + } // Create the stake item - dap_chain_net_srv_stake_item_t *l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t); + dap_chain_net_srv_stake_item_t *l_stake; + bool l_is_new = false; + HASH_FIND(hh, s_srv_stake->itemlist, &l_out_cond->params, sizeof(dap_chain_addr_t), l_stake); + if (!l_stake) { + l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t); + l_is_new = true; + } l_stake->net = l_net_list[i]; dap_stpcpy(l_stake->token, l_token); l_stake->value = l_out_cond->header.value; - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx_tmp, NULL, - TX_ITEM_TYPE_SIG, NULL); - dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig); - dap_chain_hash_fast_t l_pkey_hash; - if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) { - continue; + for (size_t i = 0; i < l_auth_certs_count; i++) { + if (!dap_cert_compare_with_sign(l_auth_certs[i], l_sign)) { + l_stake->is_active = true; + break; + } } - dap_chain_addr_fill(&l_stake->addr_from, l_sign->header.type, &l_pkey_hash, l_net_list[i]->pub.id); - memcpy(&l_stake->addr_to, l_out_cond->params, sizeof(dap_chain_addr_t)); + memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t)); + memcpy(&l_stake->addr_hldr, &l_out_cond->subtype.srv_stake.hldr_addr, sizeof(dap_chain_addr_t)); memcpy(&l_stake->addr_fee, &l_out_cond->subtype.srv_stake.fee_addr, sizeof(dap_chain_addr_t)); l_stake->fee_value = l_out_cond->subtype.srv_stake.fee_value; memcpy(&l_stake->tx_hash, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t)); - HASH_ADD(hh, s_srv_stake->itemlist, tx_hash, sizeof(dap_chain_hash_fast_t), l_stake); + if (l_is_new) + HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake); } while (l_tx_tmp); } DAP_DELETE(l_net_list); @@ -115,20 +144,106 @@ void dap_chain_net_srv_stake_deinit() HASH_DEL(s_srv_stake->itemlist, l_stake); DAP_DELETE(l_stake); } - DAP_DELETE(s_srv_stake); + DAP_DEL_Z(s_srv_stake); +} + +static void s_stake_update(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_authorized) +{ + dap_chain_net_srv_stake_item_t *l_stake; + if (a_cond) + HASH_FIND(hh, s_srv_stake->itemlist, &a_cond->params, sizeof(dap_chain_addr_t), l_stake); + else + l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t); + assert(l_stake); + dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); + if (!l_out_cond || l_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE) { + // Stake tx is used out + HASH_DEL(s_srv_stake->itemlist, l_stake); + DAP_DELETE(l_stake); + return; + } + // Update stake parameters + if (!a_cond) { + // New stake transaction + memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t)); + HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake); + } else if (memcmp(&a_cond->params, &l_out_cond->params, sizeof(dap_chain_addr_t))) { + HASH_DEL(s_srv_stake->itemlist, l_stake); + dap_chain_net_srv_stake_item_t *l_stake_cur = NULL; + HASH_FIND(hh, s_srv_stake->itemlist, &l_out_cond->params, sizeof(dap_chain_addr_t), l_stake_cur); + if (l_stake_cur) { + DAP_DELETE(l_stake); + l_stake = l_stake_cur; + } + memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t)); + if (l_stake_cur) + HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake); + } + if (a_authorized) + l_stake->is_active = true; + memcpy(&l_stake->addr_hldr, &l_out_cond->subtype.srv_stake.hldr_addr, sizeof(dap_chain_addr_t)); + memcpy(&l_stake->addr_fee, &l_out_cond->subtype.srv_stake.fee_addr, sizeof(dap_chain_addr_t)); + l_stake->fee_value = l_out_cond->subtype.srv_stake.fee_value; + dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_stake->tx_hash); } -bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx) +static bool s_stake_conditions_calc(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner, bool a_update) { - UNUSED(a_cond); - UNUSED(a_tx); + dap_chain_tx_out_cond_t *l_out_cond = NULL; + if (!a_cond) { + // New stake tx + l_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); + } else + l_out_cond = a_cond; + dap_chain_net_id_t l_cur_net_id = l_out_cond->subtype.srv_stake.hldr_addr.net_id; + dap_chain_net_t *l_net = dap_chain_net_by_id(l_cur_net_id); + if (!l_net) + return false; + size_t l_auth_certs_count = 0; + dap_cert_t **l_auth_certs = NULL; + for (dap_chain_t *l_chain = l_net->pub.chains; l_chain; l_chain = l_chain->next) { + l_auth_certs = dap_chain_cs_dag_poa_get_auth_certs(l_chain, &l_auth_certs_count); + if (l_auth_certs) + break; + l_auth_certs = dap_chain_cs_block_poa_get_auth_certs(l_chain, &l_auth_certs_count); + if (l_auth_certs) + break; + } + if (!l_auth_certs || !l_auth_certs_count) // Can't validate stake tx authority for this net + return false; + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL); + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig); + if (!l_sign) + return false; + for (size_t i = 0; i < l_auth_certs_count; i++) { + if (!dap_cert_compare_with_sign(l_auth_certs[i], l_sign)) { + if (a_update) + s_stake_update(a_cond, a_tx, true); + return true; + } + } + if (a_owner) { + if (a_update) + s_stake_update(a_cond, a_tx, false); + return true; + } return false; } +bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner) +{ + return s_stake_conditions_calc(a_cond, a_tx, a_owner, false); +} + +bool dap_chain_net_srv_stake_updater(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner) +{ + return s_stake_conditions_calc(a_cond, a_tx, a_owner, true); +} + bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr) { if (!s_srv_stake) { - return true; + return false; } while (!s_srv_stake->initialized); @@ -137,35 +252,38 @@ bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr) } dap_chain_net_srv_stake_item_t *l_stake = NULL; HASH_FIND(hh, s_srv_stake->itemlist, a_addr, sizeof(dap_chain_addr_t), l_stake); - if (l_stake) { // public key delegated for this network + if (l_stake && l_stake->is_active) { // public key delegated for this network return true; } return false; } -bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx) +bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum) { - if (!s_srv_stake) { - return true; + if (!s_srv_stake) { // Drop all atoms if stake service inactivated + return false; } while (!s_srv_stake->initialized); - if (!a_addr || !a_tx) { + if (!a_addr || !a_datum) { return false; } dap_chain_net_srv_stake_item_t *l_stake = NULL; HASH_FIND(hh, s_srv_stake->itemlist, a_addr, sizeof(dap_chain_addr_t), l_stake); - if (l_stake == NULL) { // public key not delegated for this network - return true; + if (!l_stake || !l_stake->is_active) { // public key not delegated for this network + return false; } - dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL); + if (a_datum->header.type_id != DAP_CHAIN_DATUM_TX) + return true; + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data; + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx, NULL, TX_ITEM_TYPE_SIG, NULL); dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig); dap_chain_hash_fast_t l_pkey_hash = {}; dap_sign_get_pkey_hash(l_sign, &l_pkey_hash); dap_chain_addr_t l_owner_addr = {}; dap_chain_addr_fill(&l_owner_addr, l_sign->header.type, &l_pkey_hash, a_addr->net_id); uint64_t l_outs_sum = 0, l_fee_sum = 0; - dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL); + dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL); uint32_t l_out_idx_tmp = 0; // current index of 'out' item for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) { dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data; @@ -195,7 +313,7 @@ bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a_stake, dap_chain_wallet_t *a_wallet) { - if (!a_stake || !a_stake->net || !a_stake->addr_to.addr_ver || !a_stake->addr_from.addr_ver || + if (!a_stake || !a_stake->net || !a_stake->signing_addr.addr_ver || !a_stake->addr_hldr.addr_ver || !a_stake->addr_fee.addr_ver || !*a_stake->token || !a_wallet) { return NULL; } @@ -205,7 +323,7 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_stake->net->pub.name); dap_chain_addr_t *l_owner_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_stake->net->pub.id); - if (memcmp(l_owner_addr, &a_stake->addr_from, sizeof(dap_chain_addr_t))) { + if (memcmp(l_owner_addr, &a_stake->addr_hldr, sizeof(dap_chain_addr_t))) { log_it(L_WARNING, "Odrer and wallet address do not match"); return NULL; } @@ -233,8 +351,9 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a // add 'out_cond' & 'out' items { dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID }; - dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value, &a_stake->addr_fee, - (void *)&a_stake->addr_to, sizeof(dap_chain_addr_t)); + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value, + &a_stake->addr_fee, &a_stake->addr_hldr, + (void *)&a_stake->signing_addr, sizeof(dap_chain_addr_t)); if (!l_tx_out) { dap_chain_datum_tx_delete(l_tx); DAP_DELETE(l_owner_addr); @@ -285,6 +404,59 @@ static bool s_stake_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net) return true; } +static dap_chain_datum_tx_t *s_stake_tx_approve(dap_chain_net_srv_stake_item_t *a_stake, dap_cert_t *a_cert) +{ + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + + dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_stake->net->pub.name); + + // create and add reciept + dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED}; + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID }; + dap_chain_datum_tx_receipt_t *l_receipt = dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, a_stake->value, NULL, 0); + dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt); + DAP_DELETE(l_receipt); + + // add 'in' item to buy from conditional transaction + dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, &a_stake->tx_hash); + if (!l_cond_tx) { + log_it(L_WARNING, "Requested conditional transaction not found"); + return NULL; + } + int l_prev_cond_idx; + dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx); + if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_stake->tx_hash, l_prev_cond_idx)) { + log_it(L_WARNING, "Requested conditional transaction is already used out"); + return NULL; + } + assert(l_tx_out_cond->header.value == a_stake->value); + dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_stake->tx_hash, l_prev_cond_idx, 0); + + // add 'out_cond' item + { + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID }; + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value, + &a_stake->addr_fee, &a_stake->addr_hldr, + (void *)&a_stake->signing_addr, sizeof(dap_chain_addr_t)); + if (!l_tx_out) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Can't compose the transaction conditional output"); + return NULL; + } + dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out); + DAP_DELETE(l_tx_out); + } + + // add 'sign' items + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it( L_ERROR, "Can't add sign output"); + return NULL; + } + return l_tx; +} + static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_chain_wallet_t *a_wallet) { // create empty transaction @@ -339,15 +511,20 @@ static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_c char *s_stake_order_create(dap_chain_net_srv_stake_item_t *a_item, dap_enc_key_t *l_key) { dap_chain_hash_fast_t l_tx_hash = {}; - dap_srv_stake_order_ext_t l_ext; - memcpy(&l_ext.addr_from, &a_item->addr_from, sizeof(dap_chain_addr_t)); - memcpy(&l_ext.addr_to, &a_item->addr_to, sizeof(dap_chain_addr_t)); + dap_srv_stake_order_ext_t l_ext = {}; + memcpy(&l_ext.addr_hldr, &a_item->addr_hldr, sizeof(dap_chain_addr_t)); + dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_SELL; + if (memcmp(&a_item->signing_addr, &l_ext.signing_addr, sizeof(dap_chain_addr_t))) { + // Signing addr is not empty + l_dir = SERV_DIR_BUY; + memcpy(&l_ext.signing_addr, &a_item->signing_addr, sizeof(dap_chain_addr_t)); + } l_ext.fee_value = a_item->fee_value; uint32_t l_ext_size = sizeof(dap_srv_stake_order_ext_t); dap_chain_node_addr_t *l_node_addr = dap_chain_net_get_cur_addr(a_item->net); dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED}; dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID }; - char *l_order_hash_str = dap_chain_net_srv_order_create(a_item->net, SERV_DIR_BUY, l_uid, *l_node_addr, + char *l_order_hash_str = dap_chain_net_srv_order_create(a_item->net, l_dir, l_uid, *l_node_addr, l_tx_hash, a_item->value, l_unit, a_item->token, 0, (uint8_t *)&l_ext, l_ext_size, NULL, 0, l_key); return l_order_hash_str; @@ -370,12 +547,12 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net, dap_chain_addr_t l_cert_addr; dap_chain_addr_fill(&l_cert_addr, l_sign->header.type, &l_pkey_hash, a_net->pub.id); dap_chain_net_srv_stake_item_t *l_item = DAP_NEW_Z(dap_chain_net_srv_stake_item_t); - if (memcmp(&l_cert_addr, &l_ext->addr_to, sizeof(dap_chain_addr_t))) { - log_it(L_WARNING, "Order sign addr & addr_to are different"); + if (memcmp(&l_cert_addr, &l_ext->signing_addr, sizeof(dap_chain_addr_t))) { + log_it(L_WARNING, "Order sign addr & signing_addr are different"); return NULL; } - memcpy(&l_item->addr_from, &l_ext->addr_from, sizeof(dap_chain_addr_t)); - memcpy(&l_item->addr_to, &l_ext->addr_to, sizeof(dap_chain_addr_t)); + memcpy(&l_item->addr_hldr, &l_ext->addr_hldr, sizeof(dap_chain_addr_t)); + memcpy(&l_item->signing_addr, &l_ext->signing_addr, sizeof(dap_chain_addr_t)); l_item->fee_value = l_ext->fee_value; l_item->net = a_net; l_item->value = a_order->price; @@ -386,7 +563,7 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net, static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, char **a_str_reply, const char *a_hash_out_type) { enum { - CMD_NONE, CMD_CREATE, CMD_REMOVE, CMD_LIST, CMD_UPDATE + CMD_NONE, CMD_CREATE, CMD_DECLARE, CMD_REMOVE, CMD_LIST, CMD_UPDATE }; int l_cmd_num = CMD_NONE; if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "create", NULL)) { @@ -405,7 +582,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha switch (l_cmd_num) { case CMD_CREATE: { const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL; - const char *l_addr_from_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL; + const char *l_addr_hldr_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL; dap_chain_net_t *l_net = NULL; dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { @@ -431,18 +608,18 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -coins"); return -7; } - uint64_t l_value = strtoull(l_coins_str, NULL, 10); + uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format if (!l_value) { dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); return -8; } - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_from", &l_addr_from_str); - if (!l_addr_from_str) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -addr_from"); + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_hldr", &l_addr_hldr_str); + if (!l_addr_hldr_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -addr_hldr"); return -9; } - dap_chain_addr_t *l_addr_from = dap_chain_addr_from_str(l_addr_from_str); - if (!l_addr_from) { + dap_chain_addr_t *l_addr_hldr = dap_chain_addr_from_str(l_addr_hldr_str); + if (!l_addr_hldr) { dap_chain_node_cli_set_reply_text(a_str_reply, "Wrong address format"); return -10; } @@ -463,7 +640,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha } long double l_fee = strtold(l_fee_str, NULL); if (!l_fee) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double> %"); + dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double>(%)"); return -12; } // Create the stake item @@ -471,11 +648,11 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha l_stake->net = l_net; dap_stpcpy(l_stake->token, l_token_str); l_stake->value = l_value; - memcpy(&l_stake->addr_from, l_addr_from, sizeof(dap_chain_addr_t)); - dap_chain_addr_t *l_addr_to = dap_cert_to_addr(l_cert, l_net->pub.id); - memcpy(&l_stake->addr_to, l_addr_to, sizeof(dap_chain_addr_t)); - DAP_DELETE(l_addr_from); - DAP_DELETE(l_addr_to); + memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t)); + dap_chain_addr_t *l_signing_addr = dap_cert_to_addr(l_cert, l_net->pub.id); + memcpy(&l_stake->signing_addr, l_signing_addr, sizeof(dap_chain_addr_t)); + DAP_DELETE(l_addr_hldr); + DAP_DELETE(l_signing_addr); l_stake->fee_value = l_fee; // Create the order & put it to GDB char *l_order_hash_str = s_stake_order_create(l_stake, l_cert->enc_key); @@ -489,6 +666,85 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha return -15; } } break; + case CMD_DECLARE: { + const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL; + const char *l_wallet_str = NULL, *l_fee_str = NULL; + dap_chain_net_t *l_net = NULL; + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -net"); + return -3; + } + l_net = dap_chain_net_by_name(l_net_str); + if (!l_net) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_str); + return -4; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token", &l_token_str); + if (!l_token_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -token"); + return -5; + } + if (!dap_chain_ledger_token_ticker_check(l_net->pub.ledger, l_token_str)) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_str); + return -6; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_coins_str); + if (!l_coins_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -coins"); + return -7; + } + uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format + if (!l_value) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); + return -8; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str); + if (!l_wallet_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -wallet"); + return -9; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); + if (!l_wallet) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found"); + return -18; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-fee_percent", &l_fee_str); + if (!l_fee_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -fee_percent"); + return -11; + } + long double l_fee = strtold(l_fee_str, NULL); + if (!l_fee) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double>(%)"); + return -12; + } + uint64_t l_balance = dap_chain_uint128_to(dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_token_str)); + if (l_balance < l_value) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Insufficient coins for token %s in wallet '%s'", l_token_str, l_wallet_str); + return -13; + } + // Create the stake item + dap_chain_net_srv_stake_item_t *l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t); + l_stake->net = l_net; + dap_stpcpy(l_stake->token, l_token_str); + l_stake->value = l_value; + dap_chain_addr_t *l_addr_hldr = dap_chain_wallet_get_addr(l_wallet, l_net->pub.id); + memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t)); + DAP_DELETE(l_addr_hldr); + l_stake->fee_value = l_fee; + // Create the order & put it to GDB + char *l_order_hash_str = s_stake_order_create(l_stake, dap_chain_wallet_get_key(l_wallet, 0)); + if (l_order_hash_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); + DAP_DELETE(l_order_hash_str); + DAP_DELETE(l_stake); + } else { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order"); + DAP_DELETE(l_stake); + return -15; + } + } break; case CMD_REMOVE: { const char *l_net_str = NULL, *l_order_hash_str = NULL; dap_chain_net_t *l_net = NULL; @@ -531,9 +787,10 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha } break; case CMD_UPDATE: { const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL; - const char *l_addr_from_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL; - char *l_order_hash_str = NULL; + const char *l_addr_hldr_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL; + const char *l_order_hash_str = NULL, *l_wallet_str = NULL; dap_chain_net_t *l_net = NULL; + dap_enc_key_t *l_key = NULL; dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' required parameter -net"); @@ -569,16 +826,6 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha dap_chain_node_cli_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_base58_str); return -14; } - dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_cert_str); - if (!l_cert_str) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' required parameter -cert"); - return -9; - } - dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); - if (!l_cert) { - dap_chain_node_cli_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str); - return -10; - } dap_chain_net_srv_stake_item_t *l_stake = s_stake_item_from_order(l_net, l_order); dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token", &l_token_str); if (l_token_str) { @@ -591,7 +838,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha } dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_coins_str); if (l_coins_str) { - uint64_t l_value = strtoull(l_coins_str, NULL, 10); + uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format if (!l_value) { dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>"); DAP_DELETE(l_stake); @@ -608,19 +855,60 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha return -12; } } - if (!l_token_str && !l_coins_str && !l_addr_from_str && !l_fee_str) { + dap_chain_addr_t l_empty_addr = {}; + if (memcmp(&l_stake->signing_addr, &l_empty_addr, sizeof(dap_chain_addr_t))) { + // It's a buying order + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); + if (!l_cert_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' requires parameter -cert for buying orders"); + return -9; + } + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str); + DAP_DELETE(l_stake); + return -10; + } + l_key = l_cert->enc_key; + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_hldr", &l_addr_hldr_str); + if (l_addr_hldr_str) { + dap_chain_addr_t *l_addr_hldr = dap_chain_addr_from_str(l_addr_hldr_str); + if (!l_addr_hldr) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Wrong address format"); + DAP_DELETE(l_stake); + return -14; + } + memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t)); + DAP_DELETE(l_addr_hldr); + } + } else { // It's a selling order + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str); + if (!l_wallet_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' requires parameter -wallet for selling orders"); + return -7; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); + if (!l_wallet) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found"); + return -18; + } + uint64_t l_balance = dap_chain_uint128_to(dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_stake->token)); + if (l_balance < l_stake->value) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Insufficient coins for token %s in wallet '%s'", l_token_str, l_wallet_str); + return -11; + } + l_key = dap_chain_wallet_get_key(l_wallet, 0); + } + if (!l_token_str && !l_coins_str && !l_addr_hldr_str && !l_fee_str) { dap_chain_node_cli_set_reply_text(a_str_reply, "At least one of updating parameters is mandatory"); DAP_DELETE(l_stake); return -16; } - dap_chain_addr_t *l_addr_to = dap_cert_to_addr(l_cert, l_net->pub.id); - memcpy(&l_stake->addr_to, l_addr_to, sizeof(dap_chain_addr_t)); - DAP_DELETE(l_addr_to); // Create the order & put it to GDB dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_hex_str); DAP_DELETE(l_order_hash_hex_str); DAP_DELETE(l_order_hash_base58_str); - l_order_hash_hex_str = s_stake_order_create(l_stake, l_cert->enc_key); + l_order_hash_hex_str = s_stake_order_create(l_stake, l_key); if(l_order_hash_hex_str) { if(!dap_strcmp(a_hash_out_type, "hex")) { dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_hex_str); @@ -662,7 +950,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha continue; // TODO add filters to list (token, address, etc.) l_stake = s_stake_item_from_order(l_net, l_order); - char *l_addr = dap_chain_addr_to_str(&l_stake->addr_to); + char *l_addr = dap_chain_addr_to_str(&l_stake->signing_addr); dap_string_append_printf(l_reply_str, "%s %"DAP_UINT64_FORMAT_U" %s %s %Lf\n", l_orders[i].key, l_stake->value, l_stake->token, l_addr, l_stake->fee_value); DAP_DELETE(l_addr); @@ -686,19 +974,18 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) { enum { - CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_TX, CMD_INVALIDATE + CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_APPROVE, CMD_TX, CMD_INVALIDATE }; int l_arg_index = 1; const char * l_hash_out_type = NULL; dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "-H", &l_hash_out_type); if(!l_hash_out_type) - l_hash_out_type = "hex"; - if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) { + l_hash_out_type = "base58"; + if(dap_strcmp(l_hash_out_type," hex") && dap_strcmp(l_hash_out_type, "base58")) { dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>"); return -1; } - int l_cmd_num = CMD_NONE; if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "order", NULL)) { l_cmd_num = CMD_ORDER; @@ -706,6 +993,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "delegate", NULL)) { l_cmd_num = CMD_DELEGATE; } + else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "approve", NULL)) { + l_cmd_num = CMD_APPROVE; + } else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "transactions", NULL)) { l_cmd_num = CMD_TX; } @@ -764,15 +1054,16 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) } memcpy(&l_stake->addr_fee, l_addr_fee, sizeof(dap_chain_addr_t)); DAP_DELETE(l_addr_fee); + dap_chain_addr_t *l_hldr_addr = dap_chain_wallet_get_addr(l_wallet, l_net->pub.id); + memcpy(&l_stake->addr_hldr, l_hldr_addr, sizeof(dap_chain_addr_t)); + DAP_DELETE(l_hldr_addr); // Create conditional transaction dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_stake, l_wallet); dap_chain_wallet_close(l_wallet); - if (l_tx) { - dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash); - if (s_stake_tx_put(l_tx, l_net)) { - // TODO send request to order owner to delete it - dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_str); - } + if (l_tx && s_stake_tx_put(l_tx, l_net)) { + dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash); + // TODO send request to order owner to delete it + dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_str); } DAP_DELETE(l_order); dap_chain_node_cli_set_reply_text(a_str_reply, l_tx ? "Stake transaction has done" : @@ -781,13 +1072,65 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) DAP_DELETE(l_stake); return -19; } - HASH_ADD(hh, s_srv_stake->itemlist, addr_to, sizeof(dap_chain_addr_t), l_stake); + HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake); } else { DAP_DELETE(l_addr_fee); dap_chain_node_cli_set_reply_text(a_str_reply, "Specified order not found"); return -14; } } break; + case CMD_APPROVE: { + const char *l_net_str = NULL, *l_tx_hash_str = NULL, *l_cert_str = NULL; + l_arg_index++; + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'approve' required parameter -net"); + return -3; + } + dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str); + if (!l_net) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_str); + return -4; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); + if (!l_cert_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'approve' required parameter -cert"); + return -17; + } + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Specified certificate not found"); + return -18; + } + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str); + if (!l_tx_hash_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'delegate' required parameter -tx"); + return -13; + } + dap_chain_hash_fast_t l_tx_hash = {}; + int l_result = dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); + if (l_result) + l_result = dap_enc_base58_decode(l_tx_hash_str, &l_tx_hash) - sizeof(dap_chain_hash_fast_t); + if (l_result) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid transaction hash format"); + return -14; + } + dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp; + HASH_ITER(hh, s_srv_stake->itemlist, l_stake, l_tmp) { + if (!memcmp(&l_stake->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t))) { + break; + } + } + if (!l_stake) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Transaction %s not found", l_tx_hash_str); + return -20; + } + dap_chain_datum_tx_t *l_tx = s_stake_tx_approve(l_stake, l_cert); + if (l_tx && s_stake_tx_put(l_tx, l_net)) { + dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash); + l_stake->is_active = true; + } + } break; case CMD_TX: { const char *l_net_str = NULL; l_arg_index++; @@ -808,15 +1151,15 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) continue; } char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_stake->tx_hash); - char *l_addr_from_str = dap_chain_addr_to_str(&l_stake->addr_from); - char *l_addr_to_str = dap_chain_addr_to_str(&l_stake->addr_to); + char *l_addr_hldr_str = dap_chain_addr_to_str(&l_stake->addr_hldr); + char *l_signing_addr_str = dap_chain_addr_to_str(&l_stake->signing_addr); char *l_addr_fee_str = dap_chain_addr_to_str(&l_stake->addr_fee); dap_string_append_printf(l_reply_str, "%s %s %"DAP_UINT64_FORMAT_U" %s %s %s %Lf\n", l_tx_hash_str, l_stake->token, - l_stake->value, l_addr_from_str, l_addr_to_str, + l_stake->value, l_addr_hldr_str, l_signing_addr_str, l_addr_fee_str, l_stake->fee_value); DAP_DELETE(l_tx_hash_str); - DAP_DELETE(l_addr_from_str); - DAP_DELETE(l_addr_to_str); + DAP_DELETE(l_addr_hldr_str); + DAP_DELETE(l_signing_addr_str); DAP_DELETE(l_addr_fee_str); } if (!l_reply_str->len) { diff --git a/modules/service/stake/include/dap_chain_net_srv_stake.h b/modules/service/stake/include/dap_chain_net_srv_stake.h index 4a89391531b1a3fa7881344ba2ce6fc53f405750..c539cee32af31515178a85a6355857e404ee3e55 100644 --- a/modules/service/stake/include/dap_chain_net_srv_stake.h +++ b/modules/service/stake/include/dap_chain_net_srv_stake.h @@ -27,15 +27,16 @@ #include "dap_chain_net_srv.h" #include "dap_chain_net_srv_order.h" -#define DAP_CHAIN_NET_SRV_STAKE_ID 0x3 +#define DAP_CHAIN_NET_SRV_STAKE_ID 0x13 typedef struct dap_chain_net_srv_stake_item { + bool is_active; dap_chain_net_t *net; char token[DAP_CHAIN_TICKER_SIZE_MAX]; uint64_t value; - dap_chain_addr_t addr_from; - dap_chain_addr_t addr_to; + dap_chain_addr_t addr_hldr; dap_chain_addr_t addr_fee; + dap_chain_addr_t signing_addr; long double fee_value; dap_chain_hash_fast_t tx_hash; dap_chain_hash_fast_t order_hash; @@ -43,8 +44,8 @@ typedef struct dap_chain_net_srv_stake_item { } dap_chain_net_srv_stake_item_t; typedef struct dap_srv_stake_order_ext { - dap_chain_addr_t addr_from; - dap_chain_addr_t addr_to; + dap_chain_addr_t addr_hldr; + dap_chain_addr_t signing_addr; long double fee_value; } dap_srv_stake_order_ext_t; @@ -55,6 +56,7 @@ typedef struct dap_chain_net_srv_stake { int dap_chain_net_srv_stake_init(); void dap_chain_net_srv_stake_deinit(); -bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx); -bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx); +bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner); +bool dap_chain_net_srv_stake_updater(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner); +bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum); bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr); diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index d36662f7279e17bc15040a9c3c2d7862ea42a898..df904b6701f4432326172ca942dc695649498fbf 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -101,8 +101,10 @@ void dap_chain_net_srv_xchange_deinit() DAP_DELETE(s_srv_xchange); } -bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx) +bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner) { + if (a_owner) + return true; /* Check the condition for verification success * a_cond.srv_xchange.rate >= a_tx.out.rate */ diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h index f59791fea9c51326e5026278a59de60c0de0078a..0e098f7c67445ac7dfcca10a0ef964fc24feb3e8 100644 --- a/modules/service/xchange/include/dap_chain_net_srv_xchange.h +++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h @@ -71,4 +71,4 @@ typedef struct dap_chain_net_srv_xchange { int dap_chain_net_srv_xchange_init(); void dap_chain_net_srv_xchange_deinit(); -bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx); +bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);