diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index d2c63fac6ec3cc6a14d16aced477537fa43c1ffa..428123d4de03e9cfde56a7d949bd5f8e8d329c0a 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -3549,7 +3549,7 @@ dap_chain_datum_tx_t* dap_chain_ledger_tx_cache_find_out_cond(dap_ledger_t *a_le bool is_search_enable = is_null_hash; dap_chain_ledger_tx_item_t *l_iter_current = NULL, *l_item_tmp = NULL; dap_chain_tx_out_cond_t *l_tx_out_cond = NULL; - int l_tx_out_cond_idx; + int l_tx_out_cond_idx = 0; pthread_rwlock_rdlock(&l_ledger_priv->ledger_rwlock); HASH_ITER(hh, l_ledger_priv->ledger_items, l_iter_current, l_item_tmp) { dap_chain_datum_tx_t *l_tx_tmp = l_iter_current->tx; @@ -3630,7 +3630,7 @@ uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, d * @param a_addr_from * @param a_value_need * @param a_value_transfer - * @return + * @return list of list_used_item_t */ dap_list_t *dap_chain_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, uint256_t a_value_need, uint256_t *a_value_transfer) diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c index 3e0ba4267257dff335ff2aa08f255edb91a5597b..c85b498521274b1008121b223ed6fd1f7bd5f944 100644 --- a/modules/common/dap_chain_datum_tx.c +++ b/modules/common/dap_chain_datum_tx.c @@ -142,6 +142,11 @@ int dap_chain_datum_tx_add_in_cond_item(dap_chain_datum_tx_t **a_tx, dap_chain_h } +/** + * Create 'out_cond' item with fee value and insert to transaction + * + * return 1 Ok, -1 Error + */ int dap_chain_datum_tx_add_fee_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value) { dap_chain_tx_out_cond_t *l_tx_out_fee = dap_chain_datum_tx_item_out_cond_create_fee(a_value); @@ -153,6 +158,22 @@ int dap_chain_datum_tx_add_fee_item(dap_chain_datum_tx_t **a_tx, uint256_t a_val return -1; } +/** + * Create 'out_cond' item with fee stake value and insert to transaction + * + * return 1 Ok, -1 Error + */ +int dap_chain_datum_tx_add_fee_stake_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value) +{ + dap_chain_tx_out_cond_t *l_tx_out_fee_stake = dap_chain_datum_tx_item_out_cond_create_fee_stake(a_value); + if(l_tx_out_fee_stake) { + dap_chain_datum_tx_add_item(a_tx, (const uint8_t*) l_tx_out_fee_stake); + DAP_DELETE(l_tx_out_fee_stake); + return 1; + } + return -1; +} + /** * Create 'out' item and insert to transaction * diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c index 4d7115cd9efa88f564bae217c8d804162c408b42..c3f16a8ba9a585856dd74bf345592a597f952113 100644 --- a/modules/common/dap_chain_datum_tx_items.c +++ b/modules/common/dap_chain_datum_tx_items.c @@ -260,6 +260,22 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee(uint256_t a return l_item; } +/** + * Create item dap_chain_tx_out_cond_t with fee stake subtype + * + * return item, NULL Error + */ +dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee_stake(uint256_t a_value) +{ + 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); + l_item->header.item_type = TX_ITEM_TYPE_OUT_COND; + l_item->header.value = a_value; + l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE; + return l_item; +} + /** * Create item dap_chain_tx_out_cond_t * @@ -415,7 +431,6 @@ uint8_t* dap_chain_datum_tx_item_get( dap_chain_datum_tx_t *a_tx, int *a_item_id * Get all item from transaction by type * * a_tx [in] transaction - * a_item_idx_start[in/out] start index / found index of item in transaction, if 0 then from beginning * a_type[in] type of item being find, if TX_ITEM_TYPE_ANY - any item * a_item_count[out] count of returned item * return item data, NULL Error index or bad format transaction @@ -426,7 +441,7 @@ dap_list_t *items_list = NULL; int l_items_count = 0, l_item_idx_start = 0; uint8_t *l_tx_item; - // Get sign item from transaction + // Get a_type item from transaction while ((l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx_start, a_type, NULL)) != NULL) { items_list = dap_list_append(items_list, l_tx_item); @@ -440,12 +455,22 @@ uint8_t *l_tx_item; return items_list; } +/** + * Get tx_out_cond item from transaction + * + * a_tx [in] transaction + * a_out_num[in/out] start index / found index of item in transaction, if 0 then from beginning + * return tx_out_cond, or NULL + */ dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a_tx, int *a_out_num) { dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL); int l_prev_cond_idx = l_list_out_items ? 0 : -1; dap_chain_tx_out_cond_t *l_res = NULL; for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_prev_cond_idx++) { + // Start from *a_out_num item if a_out_num != NULL + if(a_out_num && *a_out_num && l_prev_cond_idx <= *a_out_num) + continue; if (*(uint8_t *)l_list_tmp->data == TX_ITEM_TYPE_OUT_COND) { l_res = l_list_tmp->data; break; diff --git a/modules/common/include/dap_chain_datum_tx.h b/modules/common/include/dap_chain_datum_tx.h index 7698f0e4627fe598f6da32dae48b322fd7db8bac..226fe77eb32b2b09e66e4724b1ed9a4f62969ff6 100644 --- a/modules/common/include/dap_chain_datum_tx.h +++ b/modules/common/include/dap_chain_datum_tx.h @@ -111,6 +111,13 @@ int dap_chain_datum_tx_add_out_item(dap_chain_datum_tx_t **a_tx, const dap_chain */ int dap_chain_datum_tx_add_fee_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value); +/** + * Create 'out_cond' item with fee stake value and insert to transaction + * + * return 1 Ok, -1 Error + */ +int dap_chain_datum_tx_add_fee_stake_item(dap_chain_datum_tx_t **a_tx, uint256_t a_value); + /** * Create 'out'_ext item and insert to transaction * diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h index 7712406aec2afe5f028f1b56200dafed51960ce3..f71d6f514ba74d4078d5e1d9b9cbb4d5cd096388 100644 --- a/modules/common/include/dap_chain_datum_tx_items.h +++ b/modules/common/include/dap_chain_datum_tx_items.h @@ -113,6 +113,13 @@ dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_a */ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee(uint256_t a_value); +/** + * Create item dap_chain_tx_out_cond_t with fee stake subtype + * + * return item, NULL Error + */ +dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee_stake(uint256_t a_value); + /** * Create item dap_chain_tx_out_cond_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 8a328923bb52b2887183cab84f4dace134d7b96c..552841785a0061ae25e04dd4add004bf091d90df 100644 --- a/modules/common/include/dap_chain_datum_tx_out_cond.h +++ b/modules/common/include/dap_chain_datum_tx_out_cond.h @@ -30,11 +30,15 @@ #include "dap_chain_common.h" #include "dap_chain_datum_tx.h" +// Maximum fee stake, if the actual fee is less, the difference will be returned to the sender +#define MAX_FEE_STAKE GET_256_FROM_64(1000) + 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 = 0x3, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE = 0x04, + DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE = 0x05, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE = 0xFA // Virtual type for stake update verificator //TODO change it to new type of callback for ledger tx add }; typedef byte_t dap_chain_tx_out_cond_subtype_t; @@ -44,6 +48,7 @@ DAP_STATIC_INLINE const char *dap_chain_tx_out_cond_subtype_to_str(dap_chain_tx_ case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY"; case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE"; case DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE"; + case DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE"; case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE: return "DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE"; default: {} } diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index b62adffae318455615c6afe5a4725f0f16c1d668..2ee9a1595859a07610d0e1cd8dda1288f3d1fa29 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -117,7 +117,12 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_ // find the transactions from which to take away coins uint256_t l_value_transfer = {}; // how many coins to transfer uint256_t l_value_need; - SUM_256_256(a_value, a_value_fee, &l_value_need); + // Full fee + uint256_t l_value_fee_full = {}; + // Add fee stake + SUM_256_256(a_value_fee, MAX_FEE_STAKE, &l_value_fee_full); + // Add full fee + SUM_256_256(a_value, l_value_fee_full, &l_value_need); dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker, a_addr_from, l_value_need, &l_value_transfer); if (!l_list_used_out) { @@ -142,6 +147,11 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_ if(dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee) == 1) SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); } + // Staker fee + if(!IS_ZERO_256(MAX_FEE_STAKE)) { + if(dap_chain_datum_tx_add_fee_stake_item(&l_tx, MAX_FEE_STAKE) == 1) + SUM_256_256(l_value_pack, MAX_FEE_STAKE, &l_value_pack); + } } // coin back uint256_t l_value_back; @@ -202,7 +212,12 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a // Search unused out: uint256_t l_single_val = {}; - SUM_256_256(a_value, a_value_fee, &l_single_val); + // Full fee + uint256_t l_value_fee_full = {}; + // Add fee stake + SUM_256_256(a_value_fee, MAX_FEE_STAKE, &l_value_fee_full); + // Add full fee + SUM_256_256(a_value, l_value_fee_full, &l_single_val); uint256_t l_value_need = {}; MULT_256_256(dap_chain_uint256_from(a_tx_num), l_single_val, &l_value_need); uint256_t l_value_transfer = {}; // how many coins to transfer @@ -257,11 +272,16 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a uint256_t l_value_pack = {}; // how much coin add to 'out' items if(dap_chain_datum_tx_add_out_item(&l_tx_new, a_addr_to, a_value) == 1) { SUM_256_256(l_value_pack, a_value, &l_value_pack); - // transaction fee + // Transaction fee if (!IS_ZERO_256(a_value_fee)) { if (dap_chain_datum_tx_add_fee_item(&l_tx_new, a_value_fee) == 1) SUM_256_256(l_value_pack, a_value_fee, &l_value_pack); } + // Staker fee + if(!IS_ZERO_256(MAX_FEE_STAKE)) { + if(dap_chain_datum_tx_add_fee_stake_item(&l_tx_new, MAX_FEE_STAKE) == 1) + SUM_256_256(l_value_pack, MAX_FEE_STAKE, &l_value_pack); + } } // coin back SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); @@ -375,7 +395,7 @@ dap_chain_datum_t *dap_chain_tx_create_cond_input(dap_chain_net_t * a_net, dap_c // add 'in_cond' items dap_chain_hash_fast_t *l_tx_prev_hash = a_tx_prev_hash; dap_chain_datum_tx_t *l_tx_cond = dap_chain_ledger_tx_find_by_hash(l_ledger, l_tx_prev_hash); - int l_prev_cond_idx; + int l_prev_cond_idx = 0; dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_cond, &l_prev_cond_idx); if (!l_out_cond) { log_it(L_WARNING, "Requested conditioned transaction have no conditioned output"); diff --git a/modules/service/stake/dap_chain_net_srv_stake.c b/modules/service/stake/dap_chain_net_srv_stake.c index c5f3e64720ef048247a1b43d7a8c13ed582a8d84..ffcf0fec9c82409f8847596735ddc2c3355094b0 100644 --- a/modules/service/stake/dap_chain_net_srv_stake.c +++ b/modules/service/stake/dap_chain_net_srv_stake.c @@ -25,6 +25,7 @@ #include <math.h> #include "dap_chain_node_cli.h" #include "dap_string.h" +#include "dap_list.h" #include "dap_enc_base58.h" #include "dap_chain_common.h" #include "dap_chain_mempool.h" @@ -67,6 +68,8 @@ int dap_chain_net_srv_stake_init() "\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 requested stake transaction by hash within net name and return stake to specified wallet\n" + "srv_stake commit -net <net name> [-block <block hash> | [-tx <transaction hash>]\n" + "\tSend a staker fee from the block or transaction to the holder\n" ); s_srv_stake = DAP_NEW_Z(dap_chain_net_srv_stake_t); @@ -350,6 +353,7 @@ bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum return true; } +// Freeze staker's funds when delegating an order 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->signing_addr.addr_ver || !a_stake->addr_hldr.addr_ver || @@ -363,7 +367,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_hldr, sizeof(dap_chain_addr_t))) { - log_it(L_WARNING, "Odrer and wallet address do not match"); + log_it(L_WARNING, "Order and wallet address do not match"); return NULL; } dap_enc_key_t *l_owner_key = dap_chain_wallet_get_key(a_wallet, 0); @@ -466,7 +470,7 @@ static dap_chain_datum_tx_t *s_stake_tx_approve(dap_chain_net_srv_stake_item_t * log_it(L_WARNING, "Requested conditional transaction not found"); return NULL; } - int l_prev_cond_idx; + int l_prev_cond_idx = 0; 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"); @@ -508,7 +512,7 @@ static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_c dap_chain_addr_t *l_owner_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_stake->net->pub.id); dap_enc_key_t *l_owner_key = dap_chain_wallet_get_key(a_wallet, 0); - // create and add reciept + // create and add receipt 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); @@ -521,7 +525,7 @@ static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_c log_it(L_WARNING, "Requested conditional transaction not found"); return false; } - int l_prev_cond_idx; + int l_prev_cond_idx = 0; 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"); @@ -609,6 +613,146 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net, return l_item; } +// Ledger verificator for DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE +bool dap_chain_net_srv_fee_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner) +{ + if (!s_srv_stake) { + return false; + } + return false; +} + +static bool s_stake_block_commit(dap_chain_net_t *a_net, dap_list_t *a_tx_hash_list) +{ + size_t l_all_tx = 0, l_process_tx = 0; + // find all stake + dap_list_t *l_staker_list0 = dap_chain_net_srv_stake_get_validators(); + if(!l_staker_list0){ + return false; + } + // find all certs + size_t l_auth_certs_count = 0; + dap_cert_t **l_auth_certs = NULL; + for(dap_chain_t *l_chain = a_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; + } + // create empty transaction + dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + uint256_t l_fee_sum_total = {}; + dap_chain_net_srv_stake_item_t *l_stake = NULL; + dap_enc_key_t *l_owner_key = NULL; + while(a_tx_hash_list) + { + l_all_tx++; + dap_chain_hash_fast_t *tx_hash = a_tx_hash_list->data;// = NULL; + // Get tx by hash + dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_net->pub.name); + dap_chain_datum_tx_t *l_tx_with_cond = l_ledger ? dap_chain_ledger_tx_find_by_hash(l_ledger, tx_hash) : NULL; + if(!l_tx_with_cond) { + // go to the next tx + a_tx_hash_list = dap_list_next(a_tx_hash_list); + continue; + } + // Get cond out with type=DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE within tx + dap_chain_tx_out_cond_t *l_tx_out_cond = NULL; + int l_prev_cond_idx = 0; + do { + l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_with_cond, &l_prev_cond_idx); + if(l_tx_out_cond && l_tx_out_cond->header.subtype==DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE) { + break; + } + } + while(l_tx_out_cond); + + if(!l_tx_out_cond) { + // go to the next tx + a_tx_hash_list = dap_list_next(a_tx_hash_list); + continue; + } + + // Find stake + //dap_chain_net_srv_stake_item_t *l_stake = NULL;/ + // Get all sig within tx + dap_list_t *l_sig_item_list0 = dap_chain_datum_tx_items_get(l_tx_with_cond, TX_ITEM_TYPE_SIG, NULL); + dap_list_t *l_sig_item_list = l_sig_item_list0; + while(l_sig_item_list) { + dap_chain_tx_sig_t *l_sign_item = (dap_chain_tx_sig_t*) l_sig_item_list->data; + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_sign_item); + // find stake by l_sign + for(size_t i = 0; i < l_auth_certs_count; i++) { + // if the tx is signed with a key from the l_auth_certs list + if(!dap_cert_compare_with_sign(l_auth_certs[i], l_sign)) { + dap_chain_addr_t *l_signing_addr = dap_cert_to_addr(l_auth_certs[i], a_net->pub.id); + HASH_FIND(hh, s_srv_stake->itemlist, l_signing_addr, sizeof(dap_chain_addr_t), l_stake); + DAP_DELETE(l_signing_addr); + if(l_stake) + break; + else{ + l_owner_key = l_auth_certs[i]->enc_key; + } + } + } + l_sig_item_list = dap_list_next(l_sig_item_list); + } + dap_list_free(l_sig_item_list0); + + // tmp + //l_stake = (dap_chain_net_srv_stake_item_t*)l_staker_list0->data; + if(!l_stake || !l_stake->is_active) { + // go to the next tx + a_tx_hash_list = dap_list_next(a_tx_hash_list); + continue; + } + + // add 'in' item from cond transaction + if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, tx_hash, l_prev_cond_idx)) { + log_it(L_WARNING, "Requested conditional transaction is already used out"); + // go to the next tx + a_tx_hash_list = dap_list_next(a_tx_hash_list); + continue; + } + dap_chain_datum_tx_add_in_cond_item(&l_tx, tx_hash, l_prev_cond_idx, 0); + // Summ funds from all in items + uint256_t l_fee_sum = l_fee_sum_total; + SUM_256_256(l_fee_sum, l_tx_out_cond->header.value, &l_fee_sum_total); + + l_process_tx++; + a_tx_hash_list = dap_list_next(a_tx_hash_list); + } + dap_list_free_full(l_staker_list0, free); + log_it(L_INFO, "Processed %ld tx from %ld", l_process_tx, l_all_tx); + + if(!IS_ZERO_256(l_fee_sum_total)) { + dap_chain_addr_t l_holder_addr = l_stake->addr_hldr; + + // add a 'out' item + if(dap_chain_datum_tx_add_out_item(&l_tx, &l_holder_addr, l_fee_sum_total) == -1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Cant add returning coins output"); + return false; + } + // add 'sign' items + if(dap_chain_datum_tx_add_sign_item(&l_tx, l_owner_key) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_ERROR, "Can't add sign output"); + return false; + } + if(!s_stake_tx_put(l_tx, a_net)) { + dap_chain_datum_tx_delete(l_tx); + return false; + } + } + dap_chain_datum_tx_delete(l_tx); + if(l_process_tx > 0) + return true; + return false; +} + 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 { @@ -1023,7 +1167,7 @@ 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_APPROVE, CMD_TX, CMD_INVALIDATE + CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_APPROVE, CMD_TX_LIST, CMD_INVALIDATE, CMD_COMMIT }; int l_arg_index = 1; @@ -1039,18 +1183,26 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) 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; } + // Create tx to freeze staker's funds and delete order 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; } + // Create tx to approve staker's funds freeze 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; } + // Show the tx list with frozen staker funds 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; + l_cmd_num = CMD_TX_LIST; } + // Return staker's funds else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "invalidate", NULL)) { l_cmd_num = CMD_INVALIDATE; } + // Send a staker fee to staker + else if(dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "commit", NULL)) { + l_cmd_num = CMD_COMMIT; + } switch (l_cmd_num) { case CMD_ORDER: return s_cli_srv_stake_order(a_argc, a_argv, l_arg_index + 1, a_str_reply, l_hash_out_type); @@ -1180,7 +1332,7 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) l_stake->is_active = true; } } break; - case CMD_TX: { + case CMD_TX_LIST: { const char *l_net_str = NULL; l_arg_index++; dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str); @@ -1269,6 +1421,48 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply) return -21; } } break; + case CMD_COMMIT: { + const char *l_net_str = NULL, *l_tx_hash_str = NULL, *l_block_hash_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 'commit' 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, "-tx", &l_tx_hash_str); + dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-block", &l_block_hash_str); + if(!l_tx_hash_str && !l_block_hash_str) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'commit' required parameter -block or -tx"); + return -22; + } + // list of tx hash + dap_list_t *l_tx_list = NULL; + if(l_block_hash_str) { + dap_chain_hash_fast_t l_block_hash = { }; + dap_chain_hash_fast_from_str(l_block_hash_str, &l_block_hash); + // TODO add tx from block to tx_list + } + if(l_tx_hash_str) { + dap_chain_hash_fast_t *l_tx_hash = DAP_NEW_Z(dap_chain_hash_fast_t); + dap_chain_hash_fast_from_str(l_tx_hash_str, l_tx_hash); + l_tx_list = dap_list_append(l_tx_list, l_tx_hash); + } + bool l_success = s_stake_block_commit(l_net, l_tx_list); + dap_list_free_full(l_tx_list, free); + if(l_success) { + dap_chain_node_cli_set_reply_text(a_str_reply, "Stake successfully transfered to holder"); + } else { + dap_chain_node_cli_set_reply_text(a_str_reply, "Can't transfered to holder"); + return -23; + } + } + break; + default: { dap_chain_node_cli_set_reply_text(a_str_reply, "Command %s not recognized", a_argv[l_arg_index]); return -1; 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 f28cdcc8a73e744fb30b2578b0ef73fe67320a11..9fa9d2b28b6e40c807033954d7bebf1d18d7ef3b 100644 --- a/modules/service/stake/include/dap_chain_net_srv_stake.h +++ b/modules/service/stake/include/dap_chain_net_srv_stake.h @@ -61,3 +61,6 @@ bool dap_chain_net_srv_stake_updater(dap_chain_tx_out_cond_t *a_cond, dap_chain_ 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); dap_list_t *dap_chain_net_srv_stake_get_validators(); + +// Ledger verificator for DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STAKE +bool dap_chain_net_srv_fee_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner); diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c index b75af2c623964437a0532e05835e115b74335ebc..ba5ce01c71cc003d58f7a2699172e5164b2dc9de 100644 --- a/modules/service/xchange/dap_chain_net_srv_xchange.c +++ b/modules/service/xchange/dap_chain_net_srv_xchange.c @@ -265,7 +265,7 @@ static dap_chain_datum_tx_t *s_xchange_tx_create_exchange(dap_chain_net_srv_xcha log_it(L_WARNING, "Requested conditional transaction not found"); return NULL; } - int l_prev_cond_idx; + int l_prev_cond_idx = 0; 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_price->tx_hash, l_prev_cond_idx)) { log_it(L_WARNING, "Requested conditional transaction is already used out"); @@ -367,7 +367,7 @@ static bool s_xchage_tx_invalidate(dap_chain_net_srv_xchange_price_t *a_price, d log_it(L_WARNING, "Requested conditional transaction not found"); return false; } - int l_prev_cond_idx; + int l_prev_cond_idx = 0; 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_price->tx_hash, l_prev_cond_idx)) { log_it(L_WARNING, "Requested conditional transaction is already used out");