diff --git a/dap-sdk b/dap-sdk index d6ff75b22f70b79af1b54ee8d5da03252c8d599a..d3ce46e3c991bc58d97c951c2c731bd3eed9ca6f 160000 --- a/dap-sdk +++ b/dap-sdk @@ -1 +1 @@ -Subproject commit d6ff75b22f70b79af1b54ee8d5da03252c8d599a +Subproject commit d3ce46e3c991bc58d97c951c2c731bd3eed9ca6f diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index 782c239dfa0a3679c9791978520e026f134c0673..e27960b2e989a47d177ec1b9f248e60a32513d3e 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -47,7 +47,7 @@ static size_t dap_chain_tx_in_cond_get_size(const dap_chain_tx_in_cond_t *a_item return size; } -static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_old_t *a_item) +static size_t dap_chain_tx_out_old_get_size(const dap_chain_tx_out_old_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_out_old_t); @@ -55,7 +55,7 @@ static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_old_t *a_item) } // 256 -static size_t dap_chain_256_tx_out_get_size(const dap_chain_tx_out_t *a_item) +static size_t dap_chain_tx_out_get_size(const dap_chain_tx_out_t *a_item) { (void) a_item; size_t size = sizeof(dap_chain_tx_out_t); @@ -193,10 +193,10 @@ size_t dap_chain_datum_item_tx_get_size(const void *a_item) size = dap_chain_tx_in_get_size((const dap_chain_tx_in_t*) a_item); break; case TX_ITEM_TYPE_OUT_OLD: //64 - size = dap_chain_tx_out_get_size((const dap_chain_tx_out_old_t*) a_item); + size = dap_chain_tx_out_old_get_size((const dap_chain_tx_out_old_t*) a_item); break; case TX_ITEM_TYPE_OUT: // Transaction outputs - size = dap_chain_256_tx_out_get_size((const dap_chain_tx_out_t*) a_item); + size = dap_chain_tx_out_get_size((const dap_chain_tx_out_t*) a_item); break; case TX_ITEM_TYPE_OUT_EXT: // Exchange transaction outputs size = dap_chain_tx_out_ext_get_size((const dap_chain_tx_out_ext_t*) a_item); @@ -574,11 +574,14 @@ json_object* dap_chain_datum_tx_item_out_cond_srv_xchange_to_json(dap_chain_tx_o } 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, uint256_t a_value, - dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_signer_node_addr) + dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_signer_node_addr, + dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax) { if (IS_ZERO_256(a_value)) return NULL; - dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z(dap_chain_tx_out_cond_t); + size_t l_tsd_total_size = a_sovereign_addr && !dap_chain_addr_is_blank(a_sovereign_addr) ? + sizeof(dap_tsd_t) * 2 + sizeof(*a_sovereign_addr) + sizeof(a_sovereign_tax) : 0; + 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) + l_tsd_total_size); if (!l_item) { return NULL; } @@ -588,6 +591,11 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_c l_item->header.srv_uid = a_srv_uid; l_item->subtype.srv_stake_pos_delegate.signing_addr = *a_signing_addr; l_item->subtype.srv_stake_pos_delegate.signer_node_addr = *a_signer_node_addr; + if (a_sovereign_addr) { + l_item->tsd_size = l_tsd_total_size; + byte_t *l_next_tsd_ptr = dap_tsd_write(l_item->tsd, DAP_CHAIN_TX_OUT_COND_TSD_ADDR, a_sovereign_addr, sizeof(*a_sovereign_addr)); + dap_tsd_write(l_next_tsd_ptr, DAP_CHAIN_TX_OUT_COND_TSD_VALUE, &a_sovereign_tax, sizeof(a_sovereign_tax)); + } return l_item; } diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h index 9d31a756c3cd548f28d3453e16b32d03662e83df..c646a3b4990b2aba060336faf78f1b870c0f7707 100644 --- a/modules/common/include/dap_chain_datum_tx_items.h +++ b/modules/common/include/dap_chain_datum_tx_items.h @@ -189,7 +189,8 @@ json_object* dap_chain_datum_tx_item_out_cond_srv_xchange_to_json(dap_chain_tx_o * 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, uint256_t a_value, - dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_signer_node_addr); + dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_signer_node_addr, + dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax); json_object *dap_chain_datum_tx_item_out_cond_srv_stake_to_json(dap_chain_tx_out_cond_t* a_srv_stake); 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 94fdd48b6cf4a3502789e7cd3c1e0b1523ec6077..77ae1149364f749fcf2f5dca60df2247bd695e27 100644 --- a/modules/common/include/dap_chain_datum_tx_out_cond.h +++ b/modules/common/include/dap_chain_datum_tx_out_cond.h @@ -61,6 +61,12 @@ DAP_STATIC_INLINE const char *dap_chain_tx_out_cond_subtype_to_str(dap_chain_tx_ // Emit with single lock TX #define DAP_CHAIN_NET_SRV_STAKE_LOCK_FLAG_EMIT 0x00000020 +/// Conditional ouptput TSD types +// 256-bit value +#define DAP_CHAIN_TX_OUT_COND_TSD_VALUE 0xf000 +// Cahin wallet address +#define DAP_CHAIN_TX_OUT_COND_TSD_ADDR 0xf001 + /** * @struct dap_chain_tx_out * @brief Transaction item out_cond diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index 9cb9695fea063368c5eee50cbfb3d5c6432f7dfd..5ad77a015b7156141c62dc06576740649e0c64dc 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -519,9 +519,37 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf return 0; } -bool dap_chain_esbocs_started() +bool dap_chain_esbocs_started(dap_chain_net_id_t a_net_id) { - return s_session_items; + dap_chain_esbocs_session_t *l_session; + DL_FOREACH(s_session_items, l_session) { + if (l_session->chain->net_id.uint64 == a_net_id.uint64 && + l_session->esbocs && l_session->esbocs->_pvt) + return true; + } + return false; +} + +dap_pkey_t *dap_chain_esbocs_get_sign_pkey(dap_chain_net_id_t a_net_id) +{ + dap_chain_esbocs_session_t *l_session; + DL_FOREACH(s_session_items, l_session) { + if (l_session->chain->net_id.uint64 == a_net_id.uint64 && + l_session->esbocs && l_session->esbocs->_pvt) + return PVT(l_session->esbocs)->block_sign_pkey; + } + return NULL; +} + +uint256_t dap_chain_esbocs_get_fee(dap_chain_net_id_t a_net_id) +{ + dap_chain_esbocs_session_t *l_session; + DL_FOREACH(s_session_items, l_session) { + if (l_session->chain->net_id.uint64 == a_net_id.uint64 && + l_session->esbocs && l_session->esbocs->_pvt) + return PVT(l_session->esbocs)->minimum_fee; + } + return uint256_0; } void dap_chain_esbocs_stop_timer(dap_chain_net_id_t a_net_id) diff --git a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h index fb23fe97a9617a75ef0185b5041f14f6a035fa8b..0f9d9a554427bde03e0d537a2f06e3d7febe0bd8 100644 --- a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h +++ b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h @@ -212,3 +212,5 @@ bool dap_chain_esbocs_started(); void dap_chain_esbocs_stop_timer(dap_chain_net_id_t a_net_id); void dap_chain_esbocs_start_timer(dap_chain_net_id_t a_net_id); +dap_pkey_t *dap_chain_esbocs_get_sign_pkey(dap_chain_net_id_t a_net_id); +uint256_t dap_chain_esbocs_get_fee(dap_chain_net_id_t a_net_id); diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index b27a585e03ed8da7f3cd392695c43bbaada41529..4d0e37e3182baf620964c234a7cf177c36c842ae 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -65,6 +65,7 @@ #include "dap_chain_datum_tx_items.h" #include "dap_chain_net_srv.h" #include "dap_chain_cs_blocks.h" +#include "dap_chain_net_srv_stake_pos_delegate.h" #include "dap_chain_mempool_rpc.h" @@ -344,6 +345,10 @@ char *dap_chain_mempool_tx_coll_fee_create(dap_chain_cs_blocks_t *a_blocks, dap_ } SUM_256_256(l_value_out, l_value_out_block, &l_value_out); } + dap_hash_fast_t l_sign_pkey_hash; + dap_hash_fast(l_sign_pkey->pkey, l_sign_pkey->header.size, &l_sign_pkey_hash); + DAP_DELETE(l_sign_pkey); + //add 'fee' items { uint256_t l_value_pack = {}; @@ -367,21 +372,39 @@ char *dap_chain_mempool_tx_coll_fee_create(dap_chain_cs_blocks_t *a_blocks, dap_ return NULL; } } - if(compare256(l_value_out,l_value_pack)!=-1) - SUBTRACT_256_256(l_value_out,l_value_pack,&l_value_out); - else - { + if (compare256(l_value_out, l_value_pack) == 1) + SUBTRACT_256_256(l_value_out, l_value_pack, &l_value_out); + else { log_it(L_WARNING, "The transaction fee is greater than the sum of the block fees"); dap_chain_datum_tx_delete(l_tx); return NULL; } } + // Check and apply sovereign tax for this key + uint256_t l_value_tax = {}; + dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(&l_sign_pkey_hash); + if (l_key_item && !IS_ZERO_256(l_key_item->sovereign_tax) && + dap_chain_addr_is_blank(&l_key_item->sovereign_addr)) { + MULT_256_COIN(l_value_out, l_key_item->sovereign_tax, &l_value_tax); + if (compare256(l_value_tax, l_value_out) < 1) + SUBTRACT_256_256(l_value_out, l_value_tax, &l_value_out); + } + //add 'out' items - if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) { - dap_chain_datum_tx_delete(l_tx); - log_it(L_WARNING, "Can't create out item in transaction fee"); - return NULL; + if (!IS_ZERO_256(l_value_out)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } + } + if (!IS_ZERO_256(l_value_tax)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_key_item->sovereign_addr, l_value_tax) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } } // add 'sign' items @@ -487,11 +510,29 @@ char *dap_chain_mempool_tx_reward_create(dap_chain_cs_blocks_t *a_blocks, dap_en dap_chain_datum_tx_delete(l_tx); return NULL; } - //add 'out' item - if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) { - dap_chain_datum_tx_delete(l_tx); - log_it(L_WARNING, "Can't create out item in transaction fee"); - return NULL; + // Check and apply sovereign tax for this key + uint256_t l_value_tax = {}; + dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(&l_sign_pkey_hash); + if (l_key_item && !IS_ZERO_256(l_key_item->sovereign_tax) && + dap_chain_addr_is_blank(&l_key_item->sovereign_addr)) { + MULT_256_COIN(l_value_out, l_key_item->sovereign_tax, &l_value_tax); + if (compare256(l_value_tax, l_value_out) < 1) + SUBTRACT_256_256(l_value_out, l_value_tax, &l_value_out); + } + //add 'out' items + if (!IS_ZERO_256(l_value_out)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } + } + if (!IS_ZERO_256(l_value_tax)) { + if (dap_chain_datum_tx_add_out_item(&l_tx, &l_key_item->sovereign_addr, l_value_tax) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't create out item in transaction fee"); + return NULL; + } } // add 'sign' item if(dap_chain_datum_tx_add_sign_item(&l_tx, a_sign_key) != 1) { diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 366908e66e011234333d2d79bda79f802b560692..7a36a6408add968ef4acabbe6a341837c3a6fe59 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -56,7 +56,7 @@ #include "json.h" #include "json_object.h" #include "dap_notify_srv.h" - +#include "dap_chain_net_srv_stake_pos_delegate.h" #define LOG_TAG "dap_ledger" @@ -3465,6 +3465,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx dap_chain_hash_fast_t l_tx_first_sign_pkey_hash = {}; dap_pkey_t *l_tx_first_sign_pkey = NULL; bool l_girdled_ems_used = false; + uint256_t l_taxed_value = {}; // find all previous transactions for (dap_list_t *it = l_list_in; it; it = it->next) { @@ -3736,6 +3737,8 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx } l_bound_item->token_item = l_token_item; l_bound_item->reward_key = l_search_key; + // Overflow checked later with overall values sum + SUM_256_256(l_taxed_value, l_value, &l_taxed_value); } break; case TX_ITEM_TYPE_IN: @@ -3819,7 +3822,17 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ITEM_NOT_FOUND; break; } - + if (dap_hash_fast_is_blank(&l_tx_first_sign_pkey_hash)) { + // Get sign item + 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); + assert(l_tx_sig); + // Get sign from sign item + dap_sign_t *l_tx_first_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); + assert(l_tx_first_sign); + // calculate hash from sign public key + dap_sign_get_pkey_hash(l_tx_first_sign, &l_tx_first_sign_pkey_hash); + } if (l_cond_type == TX_ITEM_TYPE_IN) { dap_chain_addr_t *l_addr_from = NULL; dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_prev_out; @@ -3846,17 +3859,6 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx l_bound_item->in.addr_from = *l_addr_from; strncpy(l_bound_item->in.token_ticker, l_token, DAP_CHAIN_TICKER_SIZE_MAX - 1); // 4. compare public key hashes in the signature of the current transaction and in the 'out' item of the previous transaction - if (dap_hash_fast_is_blank(&l_tx_first_sign_pkey_hash)) { - // Get sign item - 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); - assert(l_tx_sig); - // Get sign from sign item - dap_sign_t *l_tx_first_sign = dap_chain_datum_tx_item_sign_get_sig(l_tx_sig); - assert(l_tx_first_sign); - // calculate hash from sign public key - dap_sign_get_pkey_hash(l_tx_first_sign, &l_tx_first_sign_pkey_hash); - } if (!dap_hash_fast_compare(&l_tx_first_sign_pkey_hash, &l_addr_from->data.hash_fast)) { l_err_num = DAP_LEDGER_TX_CHECK_PKEY_HASHES_DONT_MATCH; break; @@ -3912,9 +3914,6 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx dap_chain_tx_out_cond_t *l_tx_prev_out_cond = NULL; l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out; - if (l_tx_prev_out_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) - l_token = a_ledger->net->pub.native_ticker; - l_main_ticker = l_token; bool l_owner = false; l_owner = dap_sign_match_pkey_signs(l_prev_sign, l_sign); @@ -3938,6 +3937,12 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx } l_bound_item->cond = l_tx_prev_out_cond; l_value = l_tx_prev_out_cond->header.value; + if (l_tx_prev_out_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { + l_token = a_ledger->net->pub.native_ticker; + // Overflow checked later with overall values sum + SUM_256_256(l_taxed_value, l_value, &l_taxed_value); + } + l_main_ticker = l_token; } } break; @@ -3969,7 +3974,12 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx HASH_ADD_STR(l_values_from_prev_tx, token_ticker, l_value_cur); } // calculate from previous transactions per each token - SUM_256_256(l_value_cur->sum, l_value, &l_value_cur->sum); + if (SUM_256_256(l_value_cur->sum, l_value, &l_value_cur->sum)) { + debug_if(s_debug_more, L_WARNING, "Sum result overflow for tx_add_check with ticker %s", + l_value_cur->token_ticker); + l_err_num = -88; + break; + } } if (l_list_in) @@ -4016,9 +4026,12 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur); } + dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(&l_tx_first_sign_pkey_hash); + bool l_tax_check = !dap_chain_addr_is_blank(&l_key_item->sovereign_addr) && !IS_ZERO_256(l_key_item->sovereign_tax); + // find 'out' items dap_list_t *l_list_out = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_OUT_ALL, NULL); - uint256_t l_value = {}, l_fee_sum = {}; + uint256_t l_value = {}, l_fee_sum = {}, l_tax_sum = {}; bool l_fee_check = !IS_ZERO_256(a_ledger->net->pub.fee_value) && !dap_chain_addr_is_blank(&a_ledger->net->pub.fee_addr); int l_item_idx = 0; for (dap_list_t *it = l_list_out; it; it = it->next, l_item_idx++) { @@ -4075,6 +4088,12 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx } l_value = l_tx_out->header.value; l_list_tx_out = dap_list_append(l_list_tx_out, l_tx_out); + if (l_tx_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE && + SUBTRACT_256_256(l_taxed_value, l_value, &l_taxed_value)) { + log_it(L_WARNING, "Fee is greater than sum of inputs"); + l_err_num = -89; + break; + } } break; default: {} } @@ -4136,9 +4155,12 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx } if (l_fee_check && dap_chain_addr_compare(&l_tx_out_to, &a_ledger->net->pub.fee_addr) && - !dap_strcmp(l_value_cur->token_ticker, a_ledger->net->pub.native_ticker)) { + !dap_strcmp(l_value_cur->token_ticker, a_ledger->net->pub.native_ticker)) SUM_256_256(l_fee_sum, l_value, &l_fee_sum); - } + + if (l_tax_check && dap_chain_addr_compare(&l_tx_out_to, &l_key_item->sovereign_addr) && + !dap_strcmp(l_value_cur->token_ticker, a_ledger->net->pub.native_ticker)) + SUM_256_256(l_tax_sum, l_value, &l_tax_sum); } if ( l_list_out ) @@ -4176,6 +4198,24 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx } } + // 8. Check sovereign tax + if (l_fee_check && SUBTRACT_256_256(l_taxed_value, l_fee_sum, &l_taxed_value)) { + log_it(L_WARNING, "Fee is greater than sum of inputs"); + l_err_num = -89; + } + if (l_tax_check && !l_err_num) { + uint256_t l_expected_tax = {}; + MULT_256_COIN(l_taxed_value, l_key_item->sovereign_tax, &l_expected_tax); + if (compare256(l_tax_sum, l_expected_tax) == -1) { + char *l_current_tax_str = dap_chain_balance_to_coins(l_tax_sum); + char *l_expected_tax_str = dap_chain_balance_to_coins(l_expected_tax); + log_it(L_ERROR, "Tax value is invalid, expected %s pointed %s", l_expected_tax_str, l_current_tax_str); + l_err_num = -55; + DAP_DEL_Z(l_current_tax_str); + DAP_DEL_Z(l_expected_tax_str); + } + } + if (a_main_ticker && !l_err_num) *a_main_ticker = dap_strdup(l_main_ticker); diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index a167020174c150463752b7b9b57e4679a5c22c0f..8686bb5d7c51b9c1cecdb9735b4afc90301f9f34 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -2060,7 +2060,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; char *l_l_addr_str = dap_chain_addr_to_str((dap_chain_addr_t*) l_addr); if(l_wallet) - dap_string_append_printf(l_string_ret, "%s\nwallet: %s\n", dap_chain_wallet_check_sign(l_wallet), l_wallet->name); + dap_string_append_printf(l_string_ret, "%swallet: %s\n", dap_chain_wallet_check_sign(l_wallet), l_wallet->name); dap_string_append_printf(l_string_ret, "addr: %s\n", (l_l_addr_str) ? l_l_addr_str : "-"); dap_string_append_printf(l_string_ret, "network: %s\n", (l_net_name ) ? l_net_name : "-"); @@ -2165,7 +2165,7 @@ int l_arg_index = 1, l_rc, cmd_num = CMD_NONE; } log_it(L_INFO, "Wallet %s has been converted", l_wallet_name); - dap_string_append_printf(l_string_ret, "%s\nWallet: %s successfully converted\n", dap_chain_wallet_check_sign(l_wallet), l_wallet_name); + dap_string_append_printf(l_string_ret, "%sWallet: %s successfully converted\n", dap_chain_wallet_check_sign(l_wallet), l_wallet_name); dap_chain_wallet_close(l_wallet); break; } @@ -4339,11 +4339,11 @@ int com_tx_cond_create(int a_argc, char ** a_argv, char **a_str_reply) DAP_DELETE(l_key_cond); if (l_hash_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Conditional 256bit TX created succefully, hash=%s\n%s\n", l_hash_str, l_sign_str); + dap_cli_server_cmd_set_reply_text(a_str_reply, "%sConditional 256bit TX created succefully, hash=%s\n", l_hash_str, l_sign_str); DAP_DELETE(l_hash_str); return 0; } - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create conditional 256bit TX\n%s\n", l_sign_str); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create conditional 256bit TX\n"); return -1; } @@ -5118,7 +5118,8 @@ int com_tx_create_json(int a_argc, char ** a_argv, char **a_str_reply) log_it(L_ERROR, "Json TX: bad node_addr in OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE"); break; } - dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_srv_uid, l_value, l_signing_addr, &l_signer_node_addr); + dap_chain_tx_out_cond_t *l_out_cond_item = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_srv_uid, l_value, l_signing_addr, + &l_signer_node_addr, NULL, uint256_0); l_item = (const uint8_t*) l_out_cond_item; // Save value for using in In item if(l_item) { @@ -5661,7 +5662,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) dap_cli_server_cmd_set_reply_text(a_str_reply, "wallet %s does not exist", l_from_wallet_name); return -9; } else { - dap_string_append_printf(l_string_ret, "%s\n", dap_chain_wallet_check_sign(l_wallet)); + dap_string_append(l_string_ret, dap_chain_wallet_check_sign(l_wallet)); } const dap_chain_addr_t *addr_from = (const dap_chain_addr_t *) dap_chain_wallet_get_addr(l_wallet, l_net->pub.id); @@ -5965,8 +5966,7 @@ int com_tx_history(int a_argc, char ** a_argv, char **a_str_reply) dap_string_t *l_str_ret = dap_string_new(""); if (l_addr) { char *l_addr_str = dap_chain_addr_to_str(l_addr); - dap_string_append_printf(l_str_ret, "%s\n%s\n", dap_strdup_printf("History for addr %s:\n%s", l_addr_str, - l_str_out ? l_str_out : " empty"), l_sign_str); + dap_string_append_printf(l_str_ret, "%sHistory for addr %s:\n%s", l_sign_str, l_addr_str, l_str_out ? l_str_out : " empty"); DAP_DELETE(l_addr_str); DAP_DELETE(l_str_out); } else diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c index 2e473780f6c75727ebbedd94c7ee11ec521395d2..5036e2a08b13ae5d8a7281c8466f1f8c9a2fc7b4 100644 --- a/modules/net/dap_chain_node_cli_cmd_tx.c +++ b/modules/net/dap_chain_node_cli_cmd_tx.c @@ -303,7 +303,7 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const dap_chain_tx_in_ems_t *l_tx_in_ems = (dap_chain_tx_in_ems_t *)it->data; l_base_tx = true; l_noaddr_token = l_tx_in_ems->header.ticker; - } + } break; case TX_ITEM_TYPE_IN_REWARD: { l_base_tx = l_reward_collect = true; l_noaddr_token = l_native_ticker; @@ -820,7 +820,7 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply) DAP_DELETE(l_str_out); DAP_DELETE(l_addr); s_dap_chain_tx_hash_processed_ht_free(&l_list_tx_hash_processd); - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\n%s", l_str_ret->str, l_sign_str); + dap_cli_server_cmd_set_reply_text(a_str_reply, "%s%s", l_sign_str, l_str_ret->str); dap_string_free(l_str_ret, true); return 0; } diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c index 6fb414757554acd550311d2be3a54245c9bc4ef5..ebf145c201fddf4193b96a1903346ff706776cca 100644 --- a/modules/net/srv/dap_chain_net_srv.c +++ b/modules/net/srv/dap_chain_net_srv.c @@ -313,7 +313,7 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply) } if(l_continent_num>=0) l_order->continent = l_continent_num;*/ - char *l_new_order_hash_str = dap_chain_net_srv_order_save(l_net, l_order); + char *l_new_order_hash_str = dap_chain_net_srv_order_save(l_net, l_order, false); if (l_new_order_hash_str) { // delete prev order if(dap_strcmp(l_new_order_hash_str, l_order_hash_hex_str)) diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c index c53d35d127e1adacce2d2ac51ed8ac39bad74bd2..72d73bd09f0cbdcc57a49985e5cc0db3f85504d9 100644 --- a/modules/net/srv/dap_chain_net_srv_order.c +++ b/modules/net/srv/dap_chain_net_srv_order.c @@ -259,7 +259,7 @@ char * dap_chain_net_srv_order_create( a_region, a_continent_num, a_key); if (!l_order) return NULL; - char *l_ret = dap_chain_net_srv_order_save(a_net, l_order); + char *l_ret = dap_chain_net_srv_order_save(a_net, l_order, false); DAP_DELETE(l_order); return l_ret; } @@ -342,7 +342,7 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose(dap_chain_net_t *a_ne * @param a_order * @return */ -char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order) +char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order, bool a_common) { if (!a_net || !a_order) return NULL; @@ -350,12 +350,16 @@ char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_ord size_t l_order_size = dap_chain_net_srv_order_get_size(a_order); dap_hash_fast(a_order, l_order_size, &l_order_hash); char *l_order_hash_str = dap_chain_hash_fast_to_str_new(&l_order_hash); - char *l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(a_net); - if ( dap_global_db_set_sync( l_gdb_group_str,l_order_hash_str, a_order, l_order_size, true ) != 0) { - DAP_DELETE(l_gdb_group_str); + if (!l_order_hash_str) return NULL; - } + char *l_gdb_group_str = a_common ? dap_chain_net_srv_order_get_common_group(a_net) + : dap_chain_net_srv_order_get_gdb_group(a_net); + if (!l_gdb_group_str) + return NULL; + int l_rc = dap_global_db_set_sync(l_gdb_group_str, l_order_hash_str, a_order, l_order_size, true); DAP_DELETE(l_gdb_group_str); + if (l_rc != DAP_GLOBAL_DB_RC_SUCCESS) + DAP_DEL_Z(l_order_hash_str); return l_order_hash_str; } @@ -409,21 +413,26 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_read(byte_t *a_order, size_t * @param a_hash_str * @return */ -dap_chain_net_srv_order_t * dap_chain_net_srv_order_find_by_hash_str(dap_chain_net_t * a_net, const char * a_hash_str) +dap_chain_net_srv_order_t *dap_chain_net_srv_order_find_by_hash_str(dap_chain_net_t *a_net, const char *a_hash_str) { - dap_chain_net_srv_order_t * l_order = NULL; - if ( a_net && a_hash_str ){ - char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net); - size_t l_order_size =0; - l_order = (dap_chain_net_srv_order_t *) dap_global_db_get_sync(l_gdb_group_str, a_hash_str, &l_order_size, NULL, NULL ); + dap_chain_net_srv_order_t *l_order = NULL; + for (int i = 0; a_net && a_hash_str && i < 2; i++) { + char *l_gdb_group_str = i ? dap_chain_net_srv_order_get_gdb_group(a_net) + : dap_chain_net_srv_order_get_common_group(a_net); + size_t l_order_size = 0; + byte_t *l_gdb_order = dap_global_db_get_sync(l_gdb_group_str, a_hash_str, &l_order_size, NULL, NULL); + DAP_DELETE(l_gdb_group_str); + if (!l_gdb_order) + continue; // check order size - if(l_order_size != dap_chain_net_srv_order_get_size(l_order)) { - log_it( L_ERROR, "Found wrong size order"); - DAP_DELETE( l_order ); - DAP_DELETE( l_gdb_group_str ); + size_t l_expected_size = dap_chain_net_srv_order_get_size(l_order); + if (l_order_size != l_expected_size) { + log_it(L_ERROR, "Found wrong size order %zu, expected %zu", l_order_size, l_expected_size); + DAP_DELETE(l_gdb_order); return NULL; } - DAP_DELETE( l_gdb_group_str ); + l_order = dap_chain_net_srv_order_read(l_gdb_order, l_order_size); + DAP_DELETE(l_gdb_order); } return l_order; } @@ -448,56 +457,59 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_ { if (!a_net || !a_output_orders || !a_output_orders_count) return -1; - char *l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(a_net); - size_t l_orders_count = 0; - dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count); - log_it( L_DEBUG, "Loaded %zu orders", l_orders_count); - dap_chain_net_srv_order_t *l_order = NULL; - *a_output_orders = NULL; - size_t l_output_orders_count = 0; - size_t l_orders_size = 0; - for (size_t i = 0; i < l_orders_count; i++) { - DAP_DEL_Z(l_order); - l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len); - if (!l_order) { - dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key); - continue; // order is corrupted - } - dap_chain_hash_fast_t l_hash, l_hash_gdb; - dap_hash_fast(l_orders[i].value, l_orders[i].value_len, &l_hash); - dap_chain_hash_fast_from_str(l_orders[i].key, &l_hash_gdb); - if (memcmp(&l_hash, &l_hash_gdb, sizeof(dap_chain_hash_fast_t))) { - dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key); - continue; // order is corrupted + for (int i = 0; i < 2; i++) { + char *l_gdb_group_str = i ? dap_chain_net_srv_order_get_gdb_group(a_net) + : dap_chain_net_srv_order_get_common_group(a_net); + size_t l_orders_count = 0; + dap_global_db_obj_t *l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count); + log_it( L_DEBUG, "Loaded %zu orders", l_orders_count); + dap_chain_net_srv_order_t *l_order = NULL; + *a_output_orders = NULL; + size_t l_output_orders_count = 0; + size_t l_orders_size = 0; + for (size_t i = 0; i < l_orders_count; i++) { + DAP_DEL_Z(l_order); + l_order = dap_chain_net_srv_order_read(l_orders[i].value, l_orders[i].value_len); + if (!l_order) { + dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key); + continue; // order is corrupted + } + dap_chain_hash_fast_t l_hash, l_hash_gdb; + dap_hash_fast(l_orders[i].value, l_orders[i].value_len, &l_hash); + dap_chain_hash_fast_from_str(l_orders[i].key, &l_hash_gdb); + if (memcmp(&l_hash, &l_hash_gdb, sizeof(dap_chain_hash_fast_t))) { + dap_global_db_del_sync(l_gdb_group_str, l_orders[i].key); + continue; // order is corrupted + } + // Check direction + if (a_direction != SERV_DIR_UNDEFINED && l_order->direction != a_direction) + continue; + // Check srv uid + if (a_srv_uid.uint64 && l_order->srv_uid.uint64 != a_srv_uid.uint64) + continue; + // check price unit + if (a_price_unit.uint32 && a_price_unit.uint32 != l_order->price_unit.uint32) + continue; + // Check price minimum + if (!IS_ZERO_256(a_price_min) && compare256(l_order->price, a_price_min) == -1) + continue; + // Check price maximum + if (!IS_ZERO_256(a_price_max) && compare256(l_order->price, a_price_max) == 1) + continue; + // Check ticker + if (a_price_ticker && strcmp( l_order->price_ticker, a_price_ticker)) + continue; + size_t l_order_mem_size = dap_chain_net_srv_order_get_size(l_order); + *a_output_orders = DAP_REALLOC(*a_output_orders, l_orders_size + l_order_mem_size); + memcpy((byte_t *)*a_output_orders + l_orders_size, l_order, l_order_mem_size); + l_orders_size += l_order_mem_size; + l_output_orders_count++; } - // Check direction - if (a_direction != SERV_DIR_UNDEFINED && l_order->direction != a_direction) - continue; - // Check srv uid - if (a_srv_uid.uint64 && l_order->srv_uid.uint64 != a_srv_uid.uint64) - continue; - // check price unit - if (a_price_unit.uint32 && a_price_unit.uint32 != l_order->price_unit.uint32) - continue; - // Check price minimum - if (!IS_ZERO_256(a_price_min) && compare256(l_order->price, a_price_min) == -1) - continue; - // Check price maximum - if (!IS_ZERO_256(a_price_max) && compare256(l_order->price, a_price_max) == 1) - continue; - // Check ticker - if (a_price_ticker && strcmp( l_order->price_ticker, a_price_ticker)) - continue; - size_t l_order_mem_size = dap_chain_net_srv_order_get_size(l_order); - *a_output_orders = DAP_REALLOC(*a_output_orders, l_orders_size + l_order_mem_size); - memcpy((byte_t *)*a_output_orders + l_orders_size, l_order, l_order_mem_size); - l_orders_size += l_order_mem_size; - l_output_orders_count++; + *a_output_orders_count = l_output_orders_count; + DAP_DEL_Z(l_order); + dap_global_db_objs_delete(l_orders, l_orders_count); + DAP_DELETE(l_gdb_group_str); } - *a_output_orders_count = l_output_orders_count; - DAP_DEL_Z(l_order); - dap_global_db_objs_delete(l_orders, l_orders_count); - DAP_DELETE(l_gdb_group_str); return 0; } @@ -507,14 +519,16 @@ int dap_chain_net_srv_order_find_all_by(dap_chain_net_t * a_net,const dap_chain_ * @param a_hash_str * @return */ -int dap_chain_net_srv_order_delete_by_hash_str_sync(dap_chain_net_t * a_net, const char * a_hash_str ) +int dap_chain_net_srv_order_delete_by_hash_str_sync(dap_chain_net_t *a_net, const char *a_hash_str) { int l_ret = -2; - if ( a_net && a_hash_str ){ - char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group( a_net); - - l_ret = dap_global_db_del_sync( l_gdb_group_str, a_hash_str) ; - DAP_DELETE( l_gdb_group_str ); + for (int i = 0; a_net && a_hash_str && i < 2; i++) { + char *l_gdb_group_str = i ? dap_chain_net_srv_order_get_gdb_group(a_net) + : dap_chain_net_srv_order_get_common_group(a_net); + l_ret = dap_global_db_del_sync(l_gdb_group_str, a_hash_str); + DAP_DELETE(l_gdb_group_str); + if (!l_ret) + break; } return l_ret; } diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h index 24f26df936320eba9fb69029f1a48fbd16ed3b4f..8ebb4ed5d09f22a68d468d1645d844085c9f80a6 100644 --- a/modules/net/srv/include/dap_chain_net_srv_order.h +++ b/modules/net/srv/include/dap_chain_net_srv_order.h @@ -157,8 +157,11 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose( dap_enc_key_t *a_key ); -char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order); -void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,dap_string_t * a_str_out, const char *a_hash_out_type, const char *a_native_ticker); +char *dap_chain_net_srv_order_save(dap_chain_net_t *a_net, dap_chain_net_srv_order_t *a_order, bool a_common); + +void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order, dap_string_t *a_str_out, + const char *a_hash_out_type, const char *a_native_ticker); + void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg); /** * @brief dap_chain_net_srv_order_get_gdb_group_mempool @@ -169,3 +172,8 @@ DAP_STATIC_INLINE char * dap_chain_net_srv_order_get_gdb_group(dap_chain_net_t * { return a_net ? dap_strdup_printf("%s.service.orders",a_net->pub.gdb_groups_prefix) : NULL; } + +DAP_STATIC_INLINE char *dap_chain_net_srv_order_get_common_group(dap_chain_net_t * a_net) +{ + return a_net ? dap_strdup_printf("%s.orders", a_net->pub.gdb_groups_prefix) : NULL; +} diff --git a/modules/service/stake/dap_chain_net_srv_stake_lock.c b/modules/service/stake/dap_chain_net_srv_stake_lock.c index 6a3d0ff3e01028f81a95b28b7be80c9da5d82269..cfeb70da97b63608ee8473cc341d97f3415912a7 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_lock.c +++ b/modules/service/stake/dap_chain_net_srv_stake_lock.c @@ -299,7 +299,7 @@ static enum error_code s_cli_hold(int a_argc, char **a_argv, int a_arg_index, da dap_string_append_printf(output_line, "'%s'", l_wallet_str); return WALLET_OPEN_ERROR; } else { - dap_string_append_printf(output_line, "%s\n", dap_chain_wallet_check_sign(l_wallet)); + dap_string_append(output_line, dap_chain_wallet_check_sign(l_wallet)); } if (compare256(dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_ticker_str), l_value) == -1) { @@ -454,7 +454,7 @@ static enum error_code s_cli_take(int a_argc, char **a_argv, int a_arg_index, da if (NULL == (l_wallet = dap_chain_wallet_open(l_wallet_str, l_wallets_path))) return WALLET_OPEN_ERROR; else - dap_string_append_printf(output_line, "%s\n", dap_chain_wallet_check_sign(l_wallet)); + dap_string_append(output_line, dap_chain_wallet_check_sign(l_wallet)); if (NULL == (l_owner_key = dap_chain_wallet_get_key(l_wallet, 0))) { diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c index 055145bcba99ace7f1d98d40034ac02fb59ff7b9..130d6ed21da3eaa9d4626a485a5088df04515d58 100644 --- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c +++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c @@ -66,18 +66,23 @@ int dap_chain_net_srv_stake_pos_delegate_init() dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_stake_verificator_callback, s_stake_updater_callback); dap_cli_server_cmd_add("srv_stake", s_cli_srv_stake, "Delegated stake service commands", "\t\t=== Commands for work with orders ===\n" - "srv_stake order create -net <net_name> -value <value> -cert <priv_cert_name> \n" - "\tCreates a new order signed with a delegated key, which declares the commission for which \n" - "\tthe node agrees to conduct the transaction.\n" - "srv_stake order remove -net <net_name> -order <order_hash> [-H {hex | base58(default)}]\n" + "srv_stake order create [fee] -net <net_name> -value <value> -cert <priv_cert_name> [-H {hex(default) | base58}]\n" + "\tCreates an order declaring the minimum fee that the validator agrees to for process a transaction.\n" + "srv_stake order create validator -net <net_name> -value_min <minimum_stake_value> -value_max <maximum_stake_value>" + " -tax <percent> [-H {hex(default) | base58}]\n" + "\tCreates an order declaring wanted tax and minimum/maximum stake value that the validator agrees to work.\n" + "srv_stake order create staker -net <net_name> -w <wallet_wtih_m_tokens> -value <stake_value> -tax <percent> [-addr <for_tax_collecting>] [-H {hex(default) | base58}]\n" + "\tCreates an order allowing the validator to delegate it's key with specified params\n" + "srv_stake order update -net <net_name> -order <order_hash> [-params]\n" + "\tUpdates an order with specified hash\n" + "srv_stake order list [fee | validator | staker] -net <net_name>\n" + "\tGet orders list of specified type within specified net name\n" + "srv_stake order remove -net <net_name> -order <order_hash>\n" "\tRemove order with specified hash\n" - "srv_stake order update -net <net_name> -order <order_hash> [-H {hex | base58(default)}] -cert <priv_cert_name> -value <value>\n" - "\tUpdate order with specified hash\n" - "srv_stake order list -net <net_name>\n" - "\tGet the fee orders list within specified net name\n" "\t\t === Commands for work with stake delegate ===\n" - "srv_stake delegate -cert <pub_cert_name> -net <net_name> -w <wallet_name> -value <datoshi> [-node_addr <node_addr>] -fee <value> \n" - "\tDelegate public key in specified certificate with specified net name. Pay with specified value of m-tokens of native net token.\n" + "srv_stake delegate {-cert <pub_cert_name> [-node_addr <node_addr>] | -order <order_hash> [-tax_addr <wallet_addr_for_tax_collecting>]}" + " -net <net_name> -w <wallet_name> -value <datoshi> -fee <value> \n" + "\tDelegate public key in specified certificate or order with specified net name. Pay with specified value of m-tokens of native net token.\n" "srv_stake approve -net <net_name> -tx <transaction_hash> -poa_cert <priv_cert_name>\n" "\tApprove stake transaction by root node certificate within specified net name\n" "srv_stake list keys -net <net_name> [-cert <delegated_cert> | -pkey <pkey_hash_str>]\n" @@ -151,11 +156,22 @@ void dap_chain_net_srv_stake_pos_delegate_deinit() } static bool s_stake_verificator_callback(dap_ledger_t UNUSED_ARG *a_ledger, dap_chain_tx_out_cond_t UNUSED_ARG *a_cond, - dap_chain_datum_tx_t UNUSED_ARG *a_tx_in, bool a_owner) + dap_chain_datum_tx_t *a_tx_in, bool a_owner) { assert(s_srv_stake); if (!a_owner) return false; + if (a_tx_in->header.ts_created < 1702857600) // Dec 18 2023 00:00:00 GMT + return true; + dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_IN_COND, 0); + if (!l_tx_in_cond) + return false; + if (dap_hash_fast_is_blank(&l_tx_in_cond->header.tx_prev_hash)) + return false; + dap_chain_net_srv_stake_item_t *l_stake; + HASH_FIND(hh, s_srv_stake->tx_itemlist, &l_tx_in_cond->header.tx_prev_hash, sizeof(dap_hash_t), l_stake); + if (l_stake) + return false; return true; } @@ -186,8 +202,8 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr uint256_t a_value, dap_chain_node_addr_t *a_node_addr) { assert(s_srv_stake); - if (!a_signing_addr || !a_node_addr || !a_stake_tx_hash) - return; + dap_return_if_fail(a_net && a_signing_addr && a_node_addr && a_stake_tx_hash); + dap_chain_net_srv_stake_item_t *l_stake = NULL; bool l_found = false; HASH_FIND(hh, s_srv_stake->itemlist, a_signing_addr, sizeof(dap_chain_addr_t), l_stake); @@ -205,8 +221,21 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr l_stake->is_active = true; if (!l_found) HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake); - if (!dap_hash_fast_is_blank(a_stake_tx_hash)) + if (!dap_hash_fast_is_blank(a_stake_tx_hash)) { HASH_ADD(ht, s_srv_stake->tx_itemlist, tx_hash, sizeof(dap_chain_hash_fast_t), l_stake); + dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, a_stake_tx_hash); + if (l_tx) { + dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, NULL); + if (l_cond && l_cond->tsd_size) { + dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR); + l_stake->sovereign_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t); + l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE); + l_stake->sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t); + if (compare256(l_stake->sovereign_tax, dap_chain_coins_to_balance("1.0")) == 1) + l_stake->sovereign_tax = dap_chain_coins_to_balance("1.0"); + } + } + } char l_key_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; dap_chain_hash_fast_to_str(&a_signing_addr->data.hash_fast, l_key_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE); @@ -277,19 +306,6 @@ dap_list_t *dap_chain_net_srv_stake_get_validators(dap_chain_net_id_t a_net_id, return l_ret; } -dap_chain_node_addr_t *dap_chain_net_srv_stake_key_get_node_addr(dap_chain_addr_t *a_signing_addr) -{ - assert(s_srv_stake); - if (!a_signing_addr) - NULL; - - dap_chain_net_srv_stake_item_t *l_stake = NULL; - HASH_FIND(hh, s_srv_stake->itemlist, a_signing_addr, sizeof(dap_chain_addr_t), l_stake); - if (l_stake) // public key delegated for this network - return &l_stake->node_addr; - return NULL; -} - int dap_chain_net_srv_stake_mark_validator_active(dap_chain_addr_t *a_signing_addr, bool a_on_off) { assert(s_srv_stake); @@ -357,12 +373,9 @@ int dap_chain_net_srv_stake_load_cache(dap_chain_net_t *a_net) return -1; } dap_ledger_t *l_ledger = a_net->pub.ledger; - if(!l_ledger) { - log_it(L_ERROR, "Invalid arguments l_ledger in dap_chain_net_srv_stake_load_cache"); - return -1; - } if (!dap_ledger_cache_enabled(l_ledger)) return 0; + char *l_gdb_group = dap_ledger_get_gdb_group(l_ledger, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_GDB_GROUP); size_t l_objs_count = 0; @@ -370,7 +383,7 @@ int dap_chain_net_srv_stake_load_cache(dap_chain_net_t *a_net) if (!l_objs_count || !l_store_obj) { log_it(L_ATT, "Stake cache data not found"); - return -1; + return -2; } for (size_t i = 0; i < l_objs_count; i++){ dap_chain_net_srv_stake_cache_data_t *l_cache_data = @@ -378,7 +391,7 @@ int dap_chain_net_srv_stake_load_cache(dap_chain_net_t *a_net) dap_chain_net_srv_stake_cache_item_t *l_cache = DAP_NEW_Z(dap_chain_net_srv_stake_cache_item_t); if (!l_cache) { log_it(L_CRITICAL, "Memory allocation error"); - return -1; + return -3; } l_cache->signing_addr = l_cache_data->signing_addr; l_cache->tx_hash = l_cache_data->tx_hash; @@ -402,7 +415,8 @@ void dap_chain_net_srv_stake_purge(dap_chain_net_t *a_net) // Freeze staker's funds when delegating a key static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, dap_chain_wallet_t *a_wallet, uint256_t a_value, uint256_t a_fee, - dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr) + dap_chain_addr_t *a_signing_addr, dap_chain_node_addr_t *a_node_addr, + dap_chain_addr_t *a_sovereign_addr, uint256_t a_sovereign_tax) { if (!a_net || !a_wallet || IS_ZERO_256(a_value) || !a_signing_addr || !a_node_addr) return NULL; @@ -456,7 +470,8 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, dap_chai // add 'out_cond' & 'out_ext' items dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID }; - dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr); + dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_value, a_signing_addr, a_node_addr, + a_sovereign_addr, a_sovereign_tax); if (!l_tx_out) { log_it(L_ERROR, "Can't compose the transaction conditional output"); goto tx_fail; @@ -513,6 +528,13 @@ tx_fail: return NULL; } +static dap_chain_datum_tx_t *s_order_tx_create(dap_chain_net_t * a_net, dap_enc_key_t *a_key, + uint256_t a_value, uint256_t a_fee, + uint256_t a_sovereign_tax, dap_chain_addr_t *a_sovereign_addr) +{ + return NULL; +} + // Put the transaction to mempool static char *s_stake_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net) { @@ -984,7 +1006,7 @@ static dap_chain_datum_decree_t *s_stake_decree_set_min_stake(dap_chain_net_t *a return l_decree; } -char *s_stake_order_create(dap_chain_net_t *a_net, uint256_t *a_fee, dap_enc_key_t *a_key) +char *s_fee_order_create(dap_chain_net_t *a_net, uint256_t *a_fee, dap_enc_key_t *a_key, const char *a_hash_out_type) { dap_chain_hash_fast_t l_tx_hash = {}; dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_SELL; @@ -994,181 +1016,301 @@ char *s_stake_order_create(dap_chain_net_t *a_net, uint256_t *a_fee, dap_enc_key char *l_order_hash_str = dap_chain_net_srv_order_create(a_net, l_dir, l_uid, g_node_addr, l_tx_hash, a_fee, l_unit, l_native_ticker, 0, NULL, 0, 1, NULL, 0, a_key); + if (l_order_hash_str && !dap_strcmp(a_hash_out_type, "base58")) { + char *l_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str); + DAP_DELETE(l_order_hash_str); + l_order_hash_str = l_base58_str; + } + return l_order_hash_str; +} + +char *s_validator_order_create(dap_chain_net_t *a_net, uint256_t a_value_min, uint256_t a_value_max, uint256_t a_tax, const char *a_hash_out_type) +{ + dap_chain_hash_fast_t l_tx_hash = {}; + dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_BUY; + const char *l_native_ticker = a_net->pub.native_ticker; + dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_PCS}; + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS }; + struct odrer_ext { + uint256_t value_min; + uint256_t value_max; + } DAP_ALIGN_PACKED l_order_ext = { a_value_min, a_value_max }; + dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_compose(a_net, l_dir, l_uid, g_node_addr, + l_tx_hash, &a_tax, l_unit, l_native_ticker, 0, + (const uint8_t *)&l_order_ext, sizeof(l_order_ext), + 1, NULL, 0, NULL); + if (!l_order) + return NULL; + char *l_order_hash_str = dap_chain_net_srv_order_save(a_net, l_order, true); + DAP_DELETE(l_order); + if (l_order_hash_str && !dap_strcmp(a_hash_out_type, "base58")) { + char *l_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str); + DAP_DELETE(l_order_hash_str); + l_order_hash_str = l_base58_str; + } + return l_order_hash_str; +} + +char *s_staker_order_create(dap_chain_net_t *a_net, uint256_t a_value, uint256_t a_tax, dap_hash_fast_t *a_tx_hash, + dap_chain_addr_t *a_addr, const char *a_hash_out_type) +{ + dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_SELL; + const char *l_native_ticker = a_net->pub.native_ticker; + dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_PCS}; + dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS }; + struct odrer_ext { + uint256_t value; + dap_chain_addr_t addr; + } DAP_ALIGN_PACKED l_order_ext = { a_value, *a_addr }; + dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_compose(a_net, l_dir, l_uid, g_node_addr, + *a_tx_hash, &a_tax, l_unit, l_native_ticker, 0, + (const uint8_t *)&l_order_ext, sizeof(l_order_ext), + 1, NULL, 0, NULL); + if (!l_order) + return NULL; + char *l_order_hash_str = dap_chain_net_srv_order_save(a_net, l_order, true); + DAP_DELETE(l_order); + if (l_order_hash_str && !dap_strcmp(a_hash_out_type, "base58")) { + char *l_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str); + DAP_DELETE(l_order_hash_str); + l_order_hash_str = l_base58_str; + } return l_order_hash_str; } 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_DECLARE, CMD_REMOVE, CMD_LIST, CMD_UPDATE + CMD_NONE, CMD_CREATE_FEE, CMD_CREATE_VALIDATOR, CMD_CREATE_STAKER, CMD_UPDATE, CMD_LIST, CMD_REMOVE }; int l_cmd_num = CMD_NONE; - if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "create", NULL)) { - l_cmd_num = CMD_CREATE; - } - else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "remove", NULL)) { - l_cmd_num = CMD_REMOVE; - } - else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "list", NULL)) { - l_cmd_num = CMD_LIST; - } - else if(dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "update", NULL)) { + const char *l_create_type = NULL; + if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "create", &l_create_type)) { + if (!dap_strcmp(l_create_type, "validator")) + l_cmd_num = CMD_CREATE_VALIDATOR; + else if (!dap_strcmp(l_create_type, "staker")) + l_cmd_num = CMD_CREATE_STAKER; + else + l_cmd_num = CMD_CREATE_FEE; + } + else if (dap_cli_server_cmd_check_option(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "update") >= 0) l_cmd_num = CMD_UPDATE; - } - int l_arg_index = a_arg_index + 1; - switch (l_cmd_num) { - case CMD_CREATE: { - const char *l_net_str = NULL, - *l_value_str = NULL, - *l_cert_str = NULL; - dap_chain_net_t *l_net = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -net"); - return -3; - } - l_net = dap_chain_net_by_name(l_net_str); - if (!l_net) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); - return -4; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); - if (!l_value_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -value"); - return -5; - } - uint256_t l_value = dap_chain_balance_scan(l_value_str); - if (IS_ZERO_256(l_value)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <256 bit integer>"); - return -6; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); - if (!l_cert_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order create' requires parameter -cert"); - return -7; - } - dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); - if (!l_cert) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str); - return -8; - } - // Create the order & put it in GDB - char *l_order_hash_str = s_stake_order_create(l_net, &l_value, l_cert->enc_key); - if (l_order_hash_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); - DAP_DELETE(l_order_hash_str); - } else { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the order"); - return -9; - } - } break; - case CMD_REMOVE: { - const char *l_net_str = NULL, *l_order_hash_str = NULL; - dap_chain_net_t *l_net = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order remove' requires parameter -net"); - return -3; - } - l_net = dap_chain_net_by_name(l_net_str); - if (!l_net) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); - return -4; - } - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); - - char *l_order_hash_hex_str; - char *l_order_hash_base58_str; - // datum hash may be in hex or base58 format - if(!dap_strncmp(l_order_hash_str, "0x", 2) || !dap_strncmp(l_order_hash_str, "0X", 2)) { - l_order_hash_hex_str = dap_strdup(l_order_hash_str); - l_order_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str); - } - else { - l_order_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_order_hash_str); - l_order_hash_base58_str = dap_strdup(l_order_hash_str); - } + else if (dap_cli_server_cmd_check_option(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "list") >= 0) + l_cmd_num = CMD_LIST; + else if (dap_cli_server_cmd_check_option(a_argv, a_arg_index, dap_min(a_argc, a_arg_index + 1), "remove") >= 0) + l_cmd_num = CMD_REMOVE; - dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str); - if (!l_order) { - if(!dap_strcmp(a_hash_out_type,"hex")) - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_hex_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_base58_str); - return -5; - } + int l_arg_index = a_arg_index + 1; + const char *l_net_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order' requires parameter -net"); + return -3; + } + dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str); + if (!l_net) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); + return -4; + } - if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID) { - if(!dap_strcmp(a_hash_out_type,"hex")) - dap_cli_server_cmd_set_reply_text(a_str_reply, "Order %s is not a delegated stake order.\n", - l_order_hash_hex_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, - "Order %s is not a delegated stake order.\n", l_order_hash_base58_str); - return -6; + switch (l_cmd_num) { + case CMD_CREATE_FEE: { + const char *l_value_str = NULL, + *l_cert_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); + if (!l_value_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Fee order creation requires parameter -value"); + return -5; + } + uint256_t l_value = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <256 bit integer>"); + return -6; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); + if (!l_cert_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Fee order creation requires parameter -cert"); + return -7; + } + dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str); + return -8; + } + // Create the order & put it in GDB + char *l_order_hash_str = s_fee_order_create(l_net, &l_value, l_cert->enc_key, a_hash_out_type); + if (l_order_hash_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); + DAP_DELETE(l_order_hash_str); + } else { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the order"); + return -9; + } + } break; + + case CMD_CREATE_VALIDATOR: { + const char *l_value_min_str = NULL, + *l_value_max_str = NULL, + *l_tax_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value_min", &l_value_min_str); + if (!l_value_min_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -value_min"); + return -5; + } + uint256_t l_value_min = dap_chain_balance_scan(l_value_min_str); + if (IS_ZERO_256(l_value_min)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value_min <256 bit integer>"); + return -6; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value_max", &l_value_max_str); + if (!l_value_max_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -value_max"); + return -7; + } + uint256_t l_value_max = dap_chain_balance_scan(l_value_max_str); + if (IS_ZERO_256(l_value_max)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value_max <256 bit integer>"); + return -8; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str); + if (!l_tax_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -tax"); + return -9; + } + uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); + if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || + compare256(l_tax, GET_256_FROM_64(100)) == -1) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Tax must be lower or eqal than 100%% and higher or eqal than 1.0e-16%%"); + return -10; + } + // Create the order & put it in GDB + char *l_order_hash_str = s_validator_order_create(l_net, l_value_min, l_value_max, l_tax, a_hash_out_type); + if (l_order_hash_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str); + DAP_DELETE(l_order_hash_str); + } else { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the order"); + return -9; + } + } break; + + case CMD_CREATE_STAKER: { + const char *l_value_str = NULL, + *l_wallet_str = NULL, + *l_tax_str = NULL, + *l_addr_str = NULL, + *l_fee_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); + if (!l_value_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -value"); + return -5; + } + uint256_t l_value = dap_chain_balance_scan(l_value_str); + if (IS_ZERO_256(l_value)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -value <256 bit integer>"); + return -6; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); + if (!l_fee_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -fee"); + return -7; + } + uint256_t l_fee = dap_chain_balance_scan(l_fee_str); + if (IS_ZERO_256(l_fee)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Format -fee <256 bit integer>"); + return -8; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax", &l_tax_str); + if (!l_tax_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -tax"); + return -9; + } + uint256_t l_tax = dap_chain_coins_to_balance(l_tax_str); + if (compare256(l_tax, dap_chain_coins_to_balance("100.0")) == 1 || + compare256(l_tax, GET_256_FROM_64(100)) == -1) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Tax must be lower or eqal than 100%% and higher or eqal than 1.0e-16%%"); + return -10; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-w", &l_wallet_str); + if (!l_wallet_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Validator order creation requires parameter -w"); + return -17; + } + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config)); + if (!l_wallet) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified wallet not found"); + return -18; + } + // Create conditional transaction for order + const char *l_sign_str = dap_chain_wallet_check_sign(l_wallet); + dap_chain_addr_t l_addr = {}; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-addr", &l_addr_str); + if (l_addr_str) { + dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_addr_str); + if (!l_spec_addr) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified address is ivalid"); + dap_chain_wallet_close(l_wallet); + return -24; } - + l_addr = *l_spec_addr; + DAP_DELETE(l_spec_addr); + } + dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); + dap_chain_datum_tx_t *l_tx = s_order_tx_create(l_net, l_enc_key, l_value, l_fee, l_tax, &l_addr); + dap_chain_wallet_close(l_wallet); + DAP_DEL_Z(l_enc_key); + char *l_tx_hash_str = NULL; + /*if (!l_tx || !(l_tx_hash_str = s_stake_tx_put(l_tx, l_net))) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose transaction for order, examine log files for details"); + DAP_DEL_Z(l_tx); + return -21; + }*/ // TODO - make conditional transaction with specified params + // Create the order & put it in GDB + dap_hash_fast_t l_tx_hash = {}; + dap_chain_hash_fast_from_hex_str(l_tx_hash_str, &l_tx_hash); + char *l_order_hash_str = s_staker_order_create(l_net, l_value, l_tax, &l_tx_hash, &l_addr, a_hash_out_type); + if (l_order_hash_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%sSuccessfully created order %s", l_sign_str, l_order_hash_str); + DAP_DELETE(l_order_hash_str); + } else { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't compose the order"); + return -9; + } + } break; + + case CMD_REMOVE: + case CMD_UPDATE: { + const char *l_order_hash_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); + + char *l_order_hash_hex_str; + // datum hash may be in hex or base58 format + if(!dap_strncmp(l_order_hash_str, "0x", 2) || !dap_strncmp(l_order_hash_str, "0X", 2)) + l_order_hash_hex_str = dap_strdup(l_order_hash_str); + else + l_order_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_order_hash_str); + dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_hex_str); + if (!l_order) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_str); + DAP_DELETE(l_order_hash_hex_str); + return -5; + } + if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Order %s is not a delegated stake order\n", l_order_hash_str); + DAP_DELETE(l_order_hash_hex_str); + return -6; + } + if (l_cmd_num == CMD_REMOVE) { if (dap_chain_net_srv_order_delete_by_hash_str_sync(l_net, l_order_hash_hex_str)) { - if(!dap_strcmp(a_hash_out_type,"hex")) - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't remove order %s\n", l_order_hash_hex_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't remove order %s\n", l_order_hash_base58_str); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't remove order %s\n", l_order_hash_str); return -14; } dap_cli_server_cmd_set_reply_text(a_str_reply, "Stake order successfully removed"); - } break; - case CMD_UPDATE: { - const char *l_net_str = NULL, *l_value_str = NULL; - const char *l_cert_str = NULL, *l_order_hash_str = NULL; - dap_chain_net_t *l_net = NULL; - dap_enc_key_t *l_key = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order update' requires parameter -net"); - return -3; - } - l_net = dap_chain_net_by_name(l_net_str); - if (!l_net) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); - return -4; - } - if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order update' requires parameter -order"); - return -5; - } - dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str); - - char *l_order_hash_hex_str; - char *l_order_hash_base58_str; - // datum hash may be in hex or base58 format - if(!dap_strncmp(l_order_hash_str, "0x", 2) || !dap_strncmp(l_order_hash_str, "0X", 2)) { - l_order_hash_hex_str = dap_strdup(l_order_hash_str); - l_order_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_str); - } else { - l_order_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_order_hash_str); - l_order_hash_base58_str = dap_strdup(l_order_hash_str); - } - - if (!l_order) { - if(!dap_strcmp(a_hash_out_type,"hex")) - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_hex_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_base58_str); - return -6; - } - - if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID) { - if(!dap_strcmp(a_hash_out_type,"hex")) - dap_cli_server_cmd_set_reply_text(a_str_reply, "Order %s is not a delegated stake order.\n", - l_order_hash_hex_str); - else - dap_cli_server_cmd_set_reply_text(a_str_reply, - "Order %s is not a delegated stake order.\n", l_order_hash_base58_str); - return -7; - } - - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); - uint256_t l_value = {0}; + DAP_DELETE(l_order_hash_hex_str); + } else { // l_cmd_num == CMD_UPDATE + const char *l_cert_str = NULL, *l_value_str = NULL; + // TODO make orders updatable + /*uint256_t l_value = {0}; if (l_value_str) { l_value = dap_chain_balance_scan(l_value_str); if (IS_ZERO_256(l_value)) { @@ -1191,67 +1333,61 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha dap_chain_net_srv_order_delete_by_hash_str_sync(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_net, &l_value, l_key); + l_order_hash_hex_str = s_fee_order_create(l_net, &l_value, l_key); if(!l_order_hash_hex_str) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't create new order"); return -15; - } - if(!dap_strcmp(a_hash_out_type, "hex")) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_hex_str); - } else { - l_order_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_order_hash_hex_str); - dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_base58_str); - DAP_DELETE(l_order_hash_base58_str); - } - DAP_DELETE(l_order_hash_hex_str); - } break; - case CMD_LIST: { - const char *l_net_str = NULL; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); - if (!l_net_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order list' requires parameter -net"); - return -3; - } - dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str); - if (!l_net) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); - return -4; - } - char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(l_net); - size_t l_orders_count = 0; - dap_global_db_obj_t * l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count); - dap_string_t *l_reply_str = dap_string_new(""); - for (size_t i = 0; i < l_orders_count; i++) { - dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)l_orders[i].value; - if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID) - continue; - // TODO add filters to list (token, address, etc.) - char *l_price_coins = dap_chain_balance_to_coins(l_order->price); - char *l_price_datoshi = dap_chain_balance_print(l_order->price); - char *l_node_addr = dap_strdup_printf(NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_order->node_addr)); - char l_created[80] = {'\0'}; - dap_time_t l_ts_created = l_order->ts_created; - dap_ctime_r(&l_ts_created, l_created); - dap_string_append_printf(l_reply_str, "Order: %s\n" - "\tCreated: %s" - "\tPrice: %s (%s) %s\n" - "\tNode addr: %s\n", - l_orders[i].key, l_created, l_price_coins, l_price_datoshi, l_order->price_ticker, l_node_addr); - DAP_DELETE(l_price_coins); - DAP_DELETE(l_price_datoshi); - DAP_DELETE(l_node_addr); - } - dap_global_db_objs_delete(l_orders, l_orders_count); - DAP_DELETE( l_gdb_group_str); - if (!l_reply_str->len) { - dap_string_append(l_reply_str, "No orders found"); - } - *a_str_reply = dap_string_free(l_reply_str, false); - } break; - default: { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index]); - return -2; + }*/ + } + } break; + + case CMD_LIST: { + const char *l_net_str = NULL; + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); + if (!l_net_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'order list' requires parameter -net"); + return -3; + } + dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str); + if (!l_net) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Network %s not found", l_net_str); + return -4; } + char * l_gdb_group_str = dap_chain_net_srv_order_get_gdb_group(l_net); + size_t l_orders_count = 0; + dap_global_db_obj_t * l_orders = dap_global_db_get_all_sync(l_gdb_group_str, &l_orders_count); + dap_string_t *l_reply_str = dap_string_new(""); + for (size_t i = 0; i < l_orders_count; i++) { + dap_chain_net_srv_order_t *l_order = (dap_chain_net_srv_order_t *)l_orders[i].value; + if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID) + continue; + // TODO add filters to list (token, address, etc.) + char *l_price_coins = dap_chain_balance_to_coins(l_order->price); + char *l_price_datoshi = dap_chain_balance_print(l_order->price); + char *l_node_addr = dap_strdup_printf(NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_order->node_addr)); + char l_created[80] = {'\0'}; + dap_time_t l_ts_created = l_order->ts_created; + dap_ctime_r(&l_ts_created, l_created); + dap_string_append_printf(l_reply_str, "Order: %s\n" + "\tCreated: %s" + "\tPrice: %s (%s) %s\n" + "\tNode addr: %s\n", + l_orders[i].key, l_created, l_price_coins, l_price_datoshi, l_order->price_ticker, l_node_addr); + DAP_DELETE(l_price_coins); + DAP_DELETE(l_price_datoshi); + DAP_DELETE(l_node_addr); + } + dap_global_db_objs_delete(l_orders, l_orders_count); + DAP_DELETE( l_gdb_group_str); + if (!l_reply_str->len) { + dap_string_append(l_reply_str, "No orders found"); + } + *a_str_reply = dap_string_free(l_reply_str, false); + } break; + + default: + dap_cli_server_cmd_set_reply_text(a_str_reply, "Subcommand %s not recognized", a_argv[a_arg_index]); + return -2; } return 0; } @@ -1280,17 +1416,24 @@ static void s_srv_stake_print(dap_chain_net_srv_stake_item_t *a_stake, uint256_t char l_active_str[32] = {}; if (s_chain_esbocs_started(a_stake->net)) snprintf(l_active_str, 32, "\tActive: %s\n", a_stake->is_active ? "true" : "false"); + char *l_sov_addr_str = dap_chain_addr_is_blank(&a_stake->sovereign_addr) ? + dap_strdup("N/A") : dap_chain_addr_to_str(&a_stake->sovereign_addr); + char *l_sov_tax_str = dap_chain_balance_to_coins(a_stake->sovereign_tax); dap_string_append_printf(a_string, "Pkey hash: %s\n" "\tStake value: %s\n" "\tRelated weight: %s%%\n" "\tTx hash: %s\n" "\tNode addr: "NODE_ADDR_FP_STR"\n" + "\tSovereign addr: %s\n" + "\tSovereign tax: %s\n" "%s\n", l_pkey_hash_str, l_balance, l_rel_weight_str, l_tx_hash_str, NODE_ADDR_FP_ARGS_S(a_stake->node_addr), - l_active_str); + l_sov_addr_str, l_sov_tax_str, l_active_str); DAP_DELETE(l_balance); DAP_DELETE(l_rel_weight_str); + DAP_DELETE(l_sov_addr_str); + DAP_DELETE(l_sov_tax_str); } /** @@ -1581,7 +1724,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) *l_cert_str = NULL, *l_value_str = NULL, *l_fee_str = NULL, - *l_node_addr_str = NULL; + *l_node_addr_str = NULL, + *l_order_hash_str = NULL, + *l_sovereign_addr_str = NULL; l_arg_index++; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); if (!l_net_str) { @@ -1606,33 +1751,97 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) } else { l_sign_str = dap_chain_wallet_check_sign(l_wallet); } + dap_chain_addr_t l_signing_addr, l_sovereign_addr = {}; + uint256_t l_sovereign_tax = uint256_0; dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str); - if (!l_cert_str) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -cert"); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-order", &l_order_hash_str); + if (!l_cert_str && !l_order_hash_str) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -cert or -order"); + dap_chain_wallet_close(l_wallet); return -13; } - dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); - if (!l_signing_cert) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found"); - return -19; - } - dap_chain_addr_t l_signing_addr; - if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, l_net->pub.id)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong"); - return -20; + dap_chain_node_addr_t l_node_addr; + if (l_cert_str) { + dap_cert_t *l_signing_cert = dap_cert_find_by_name(l_cert_str); + if (!l_signing_cert) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate not found"); + dap_chain_wallet_close(l_wallet); + return -19; + } + if (dap_chain_addr_fill_from_key(&l_signing_addr, l_signing_cert->enc_key, l_net->pub.id)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is wrong"); + dap_chain_wallet_close(l_wallet); + return -20; + } + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); + if (l_node_addr_str) { + if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized node addr %s", l_node_addr_str); + dap_chain_wallet_close(l_wallet); + return -14; + } + } else + l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net); + } else { + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-tax_addr", &l_sovereign_addr_str); + if (l_sovereign_addr_str) { + dap_chain_addr_t *l_spec_addr = dap_chain_addr_from_str(l_sovereign_addr_str); + if (!l_spec_addr) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified address is ivalid"); + return -24; + } + l_sovereign_addr = *l_spec_addr; + DAP_DELETE(l_spec_addr); + } else + dap_chain_addr_fill_from_key(&l_sovereign_addr, dap_chain_wallet_get_key(l_wallet, 0), l_net->pub.id); + dap_chain_net_srv_order_t *l_order = dap_chain_net_srv_order_find_by_hash_str(l_net, l_order_hash_str); + if (!l_order) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order not found"); + dap_chain_wallet_close(l_wallet); + return -25; + } + dap_pkey_t *l_pkey = (dap_pkey_t *)l_order->ext_n_sign; + if (l_order->ext_size < sizeof(dap_pkey_t) || l_order->ext_size != dap_pkey_get_size(l_pkey)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order has invalid size"); + dap_chain_wallet_close(l_wallet); + DAP_DELETE(l_order); + return -26; + } + if (dap_strcmp(l_order->price_ticker, l_net->pub.native_ticker)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified order is invalid"); + dap_chain_wallet_close(l_wallet); + DAP_DELETE(l_order); + return -27; + } + dap_hash_t l_pkey_hash; + dap_pkey_get_hash(l_pkey, &l_pkey_hash); + dap_chain_addr_fill(&l_signing_addr, dap_pkey_type_to_sign_type(l_pkey->header.type), &l_pkey_hash, l_net->pub.id); + l_node_addr = l_order->node_addr; + l_sovereign_tax = l_order->price; + DAP_DELETE(l_order); + if (compare256(l_sovereign_tax, dap_chain_coins_to_balance("100.0")) == 1 || + compare256(l_sovereign_tax, GET_256_FROM_64(100)) == -1) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Tax must be lower or eqal than 100%% and higher or eqal than 1.0e-16%%"); + dap_chain_wallet_close(l_wallet); + return -28; + } + DIV_256(l_sovereign_tax, GET_256_FROM_64(100), &l_sovereign_tax); } if (dap_chain_net_srv_stake_key_delegated(&l_signing_addr)) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is already delegated"); + dap_chain_wallet_close(l_wallet); return -21; } dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-value", &l_value_str); if (!l_value_str) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -value"); + dap_chain_wallet_close(l_wallet); return -9; } uint256_t l_value = dap_chain_balance_scan(l_value_str); if (IS_ZERO_256(l_value)) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-value' param"); + dap_chain_wallet_close(l_wallet); return -10; } if (compare256(l_value, s_srv_stake->delegate_allowed_min) == -1) { @@ -1644,44 +1853,43 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) DAP_DELETE(l_coin_str); DAP_DELETE(l_value_min_str); DAP_DELETE(l_coin_min_str); + dap_chain_wallet_close(l_wallet); return -11; } - dap_chain_node_addr_t l_node_addr; - dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-node_addr", &l_node_addr_str); - if (l_node_addr_str) { - if (dap_chain_node_addr_from_str(&l_node_addr, l_node_addr_str)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized node addr %s", l_node_addr_str); - return -14; - } - } else - l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net); + dap_cli_server_cmd_find_option_val(a_argv, l_arg_index, a_argc, "-fee", &l_fee_str); if (!l_fee_str) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'delegate' requires parameter -fee"); + dap_chain_wallet_close(l_wallet); return -15; } uint256_t l_fee = dap_chain_balance_scan(l_fee_str); if (IS_ZERO_256(l_fee)) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Unrecognized number in '-fee' param"); + dap_chain_wallet_close(l_wallet); return -16; } int ret_val = 0; if((ret_val = dap_chain_net_srv_stake_verify_key_and_node(&l_signing_addr, &l_node_addr)) != 0){ dap_cli_server_cmd_set_reply_text(a_str_reply, "Key and node verification error"); + dap_chain_wallet_close(l_wallet); return ret_val; } + // Create conditional transaction - dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_net, l_wallet, l_value, l_fee, &l_signing_addr, &l_node_addr); + dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_net, l_wallet, l_value, l_fee, &l_signing_addr, &l_node_addr, + &l_sovereign_addr, l_sovereign_tax); dap_chain_wallet_close(l_wallet); if (!l_tx || !s_stake_tx_put(l_tx, l_net)) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Stake transaction error"); + DAP_DEL_Z(l_tx); return -12; } dap_hash_fast_t l_tx_hash; dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash); DAP_DELETE(l_tx); char *l_tx_hash_str = dap_hash_fast_to_str_new(&l_tx_hash); - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nSAVE TO TAKE ===>>> Stake transaction %s has done", l_sign_str, l_tx_hash_str); + dap_cli_server_cmd_set_reply_text(a_str_reply, "%sSAVE TO TAKE ===>>> Stake transaction %s has done", l_sign_str, l_tx_hash_str); DAP_DELETE(l_tx_hash_str); } break; case CMD_APPROVE: { @@ -1950,14 +2158,22 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) } } - dap_hash_fast_t *l_final_tx_hash = NULL; + dap_hash_fast_t l_tx_hash = {}; if (l_tx_hash_str) { - l_final_tx_hash = DAP_NEW(dap_hash_fast_t); - dap_chain_hash_fast_from_str(l_tx_hash_str, l_final_tx_hash); - if(!dap_ledger_tx_find_by_hash(l_net->pub.ledger, l_final_tx_hash)) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s is not found.", l_tx_hash_str); + dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash); + if (!dap_ledger_tx_find_by_hash(l_net->pub.ledger, &l_tx_hash)) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s is not found", l_tx_hash_str); return -20; } + dap_chain_net_srv_stake_item_t *l_stake; + HASH_FIND(hh, s_srv_stake->tx_itemlist, &l_tx_hash, sizeof(dap_hash_t), l_stake); + if (l_stake) { + char l_pkey_hash_str[DAP_HASH_FAST_STR_SIZE]; + dap_hash_fast_to_str(&l_stake->signing_addr.data.hash_fast, l_pkey_hash_str, DAP_HASH_FAST_STR_SIZE); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Transaction %s has active delegated key %s, need to revoke it first", + l_tx_hash_str, l_pkey_hash_str); + return -30; + } } else { dap_chain_addr_t l_signing_addr; if (l_cert_str) { @@ -1985,7 +2201,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) " Try to invalidate with tx hash instead"); return -24; } - l_final_tx_hash = &l_stake->tx_hash; + l_tx_hash = l_stake->tx_hash; } if (l_wallet_str) { const char* l_sign_str = ""; @@ -1997,23 +2213,20 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) l_sign_str = dap_chain_wallet_check_sign(l_wallet); } dap_enc_key_t *l_enc_key = dap_chain_wallet_get_key(l_wallet, 0); - dap_chain_datum_tx_t *l_tx = s_stake_tx_invalidate(l_net, l_final_tx_hash, l_fee, l_enc_key); - if (l_tx_hash_str) { - DAP_DELETE(l_final_tx_hash); - } + dap_chain_datum_tx_t *l_tx = s_stake_tx_invalidate(l_net, &l_tx_hash, l_fee, l_enc_key); dap_chain_wallet_close(l_wallet); dap_enc_key_delete(l_enc_key); - char *l_decree_hash_str = NULL; - if (l_tx && (l_decree_hash_str = s_stake_tx_put(l_tx, l_net))) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nAll m-tokens successfully returned to " - "owner. Returning tx hash %s.", l_sign_str, l_decree_hash_str); - DAP_DEL_Z(l_decree_hash_str); + char *l_tx_hash_str = NULL; + if (l_tx && (l_tx_hash_str = s_stake_tx_put(l_tx, l_net))) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "%sAll m-tokens successfully returned to " + "owner. Returning tx hash %s.", l_sign_str, l_tx_hash_str); + DAP_DEL_Z(l_tx_hash_str); DAP_DELETE(l_tx); } else { - char *l_final_tx_hash_str = dap_chain_hash_fast_to_str_new(l_final_tx_hash); - dap_cli_server_cmd_set_reply_text(a_str_reply, "%s\nCan't invalidate transaction %s, examine log files for details", l_sign_str, l_final_tx_hash_str); - DAP_DELETE(l_final_tx_hash_str); - DAP_DELETE(l_tx); + l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_tx_hash); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str); + DAP_DELETE(l_tx_hash_str); + DAP_DEL_Z(l_tx); return -21; } } else { @@ -2026,7 +2239,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified certificate is not PoA root one"); return -26; } - dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, l_final_tx_hash, l_poa_cert); + dap_chain_datum_decree_t *l_decree = s_stake_decree_invalidate(l_net, &l_tx_hash, l_poa_cert); char *l_decree_hash_str = NULL; if (l_decree && (l_decree_hash_str = s_stake_decree_put(l_decree, l_net))) { dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified delageted key invalidated. " @@ -2035,10 +2248,10 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) DAP_DELETE(l_decree); DAP_DELETE(l_decree_hash_str); } else { - char l_final_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; - dap_chain_hash_fast_to_str(l_final_tx_hash, l_final_tx_hash_str, sizeof(l_final_tx_hash_str)); - dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_final_tx_hash_str); - DAP_DELETE(l_decree); + char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE]; + dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str)); + dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't invalidate transaction %s, examine log files for details", l_tx_hash_str); + DAP_DEL_Z(l_decree); return -21; } } diff --git a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h index d0089145573457fa8e00216e583add209ca77d23..ff69a780555530f66e2115885afc85fe3d3bf932 100644 --- a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h +++ b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h @@ -31,6 +31,7 @@ #include "dap_stream_ch_chain_net.h" #define DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID 0x13 +#define DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ORDERS 0x14 typedef struct dap_chain_net_srv_stake_item { bool is_active; @@ -39,6 +40,8 @@ typedef struct dap_chain_net_srv_stake_item { dap_chain_addr_t signing_addr; dap_chain_hash_fast_t tx_hash; dap_chain_node_addr_t node_addr; + dap_chain_addr_t sovereign_addr; + uint256_t sovereign_tax; UT_hash_handle hh, ht; } dap_chain_net_srv_stake_item_t; @@ -73,7 +76,6 @@ uint256_t dap_chain_net_srv_stake_get_allowed_min_value(); int dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr); int dap_chain_net_srv_stake_verify_key_and_node(dap_chain_addr_t* a_signing_addr, dap_chain_node_addr_t* a_node_addr); dap_list_t *dap_chain_net_srv_stake_get_validators(dap_chain_net_id_t a_net_id, bool a_only_active); -dap_chain_node_addr_t *dap_chain_net_srv_stake_key_get_node_addr(dap_chain_addr_t *a_signing_addr); bool dap_chain_net_srv_stake_get_fee_validators(dap_chain_net_t *a_net, uint256_t *a_max_fee, uint256_t *a_average_fee, uint256_t *a_min_fee, uint256_t *a_median_fee); diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 5ae67b39dae1e6d901d53134be6fdca184396c34..2a5a7f498de62d641584826731a9597d7193461d 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -34,6 +34,8 @@ #include "dap_cli_server.h" #include "dap_chain_node_cli_cmd.h" #include "dap_chain_mempool.h" +#include "dap_chain_net_srv_stake_pos_delegate.h" +#include "dap_chain_cs_esbocs.h" #define LOG_TAG "dap_chain_cs_blocks" @@ -182,7 +184,7 @@ int dap_chain_cs_blocks_init() "Commission collect:\n" "block -net <net_name> -chain <chain_name> fee collect" " -cert <priv_cert_name> -addr <addr> -hashes <hashes_list> -fee <value>\n" - "\t\t Take the whole commission\n\n" + "\t\t Take delegated part of commission\n\n" "Reward for block signs:\n" "block -net <net_name> -chain <chain_name> reward set" @@ -195,7 +197,7 @@ int dap_chain_cs_blocks_init() "block -net <net_name> -chain <chain_name> reward collect" " -cert <priv_cert_name> -addr <addr> -hashes <hashes_list> -fee <value>\n" - "\t\t Take reward\n\n" + "\t\t Take delegated part of reward\n\n" "Rewards and comission autocollect status:\n" "block -net <net_name> -chain <chain_name> autocollect status\n\n" @@ -462,9 +464,31 @@ static void s_print_autocollect_table(dap_chain_net_t *a_net, dap_string_t *a_re } if (l_objs_count) { dap_global_db_objs_delete(l_objs, l_objs_count); + uint256_t l_collect_fee = dap_chain_esbocs_get_fee(a_net->pub.id); + SUM_256_256(l_collect_fee, a_net->pub.fee_value, &l_collect_fee); + uint256_t l_collect_tax = {}, l_collect_value = {}; + if (compare256(l_total_value, l_collect_fee) == 1) { + SUBTRACT_256_256(l_total_value, l_collect_fee, &l_collect_value); + dap_pkey_t *l_my_sign_pkey = dap_chain_esbocs_get_sign_pkey(a_net->pub.id); + dap_hash_t l_my_sign_pkey_hash; + dap_hash_fast(l_my_sign_pkey->pkey, l_my_sign_pkey->header.size, &l_my_sign_pkey_hash); + dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(&l_my_sign_pkey_hash); + if (l_key_item && !IS_ZERO_256(l_key_item->sovereign_tax) && + !dap_chain_addr_is_blank(&l_key_item->sovereign_addr)) { + MULT_256_COIN(l_collect_value, l_key_item->sovereign_tax, &l_collect_tax); + SUBTRACT_256_256(l_collect_value, l_collect_tax, &l_collect_value); + } + } char *l_total_str = dap_chain_balance_to_coins(l_total_value); - dap_string_append_printf(a_reply_str, "Total prepared value: %s %s\n", l_total_str, a_net->pub.native_ticker); + char *l_profit_str = dap_chain_balance_to_coins(l_collect_value); + char *l_tax_str = dap_chain_balance_to_coins(l_collect_tax); + char *l_fee_str = dap_chain_balance_to_coins(l_collect_fee); + dap_string_append_printf(a_reply_str, "Total prepared value: %s %s, where\n\tprofit is %s, tax is %s, fee is %s\n", + l_total_str, a_net->pub.native_ticker, l_profit_str, l_tax_str, l_fee_str); DAP_DEL_Z(l_total_str); + DAP_DEL_Z(l_profit_str); + DAP_DEL_Z(l_tax_str); + DAP_DEL_Z(l_fee_str); } else dap_string_append(a_reply_str, "Empty\n"); } diff --git a/modules/wallet/dap_chain_wallet.c b/modules/wallet/dap_chain_wallet.c index 900fb942a484ecffbb317c16015dac6f9035bbeb..01ec3cf9662c11c81d06f1e4e93da627c34adaa3 100644 --- a/modules/wallet/dap_chain_wallet.c +++ b/modules/wallet/dap_chain_wallet.c @@ -997,7 +997,7 @@ const char* dap_chain_wallet_check_sign(dap_chain_wallet_t *a_wallet) { for (size_t i = 0; i < l_wallet_internal->certs_count; ++i) { dap_sign_type_t l_sign_type = dap_sign_type_from_key_type(l_wallet_internal->certs[i]->enc_key->type); if (SIG_TYPE_BLISS == l_sign_type.type || SIG_TYPE_PICNIC == l_sign_type.type || SIG_TYPE_TESLA == l_sign_type.type) { - return "The Bliss, Picnic and Tesla signatures is deprecated. We recommend you to create a new wallet with another available signature and transfer funds there."; + return "The Bliss, Picnic and Tesla signatures is deprecated. We recommend you to create a new wallet with another available signature and transfer funds there.\n"; } } return "";