From 34fcfbb3fd337bbacca15e91460fef0d5a258ff8 Mon Sep 17 00:00:00 2001 From: Roman Khlopkov <roman.khlopkov@demlabs.net> Date: Mon, 3 Mar 2025 18:16:09 +0700 Subject: [PATCH] [*] Voting with non-native token partial debug --- modules/common/dap_chain_datum_tx_voting.c | 15 + .../include/dap_chain_datum_tx_voting.h | 9 +- .../consensus/esbocs/dap_chain_cs_esbocs.c | 5 +- modules/net/dap_chain_ledger.c | 21 +- modules/net/dap_chain_net_tx.c | 4 +- .../service/voting/dap_chain_net_srv_voting.c | 332 +++++++++++------- .../voting/include/dap_chain_net_srv_voting.h | 6 +- 7 files changed, 246 insertions(+), 146 deletions(-) diff --git a/modules/common/dap_chain_datum_tx_voting.c b/modules/common/dap_chain_datum_tx_voting.c index 2a161dd3a9..eb2ab0320c 100644 --- a/modules/common/dap_chain_datum_tx_voting.c +++ b/modules/common/dap_chain_datum_tx_voting.c @@ -124,6 +124,18 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool return l_tsd; } +dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker) +{ + dap_return_val_if_fail(a_token_ticker && *a_token_ticker, NULL); + size_t l_ticker_len = strlen(a_token_ticker); + if (l_ticker_len >= DAP_CHAIN_TICKER_SIZE_MAX) { + log_it(L_ERROR, "Ticker len %zu is too big", l_ticker_len); + return NULL; + } + dap_chain_tx_tsd_t *l_tsd = dap_chain_datum_tx_item_tsd_create((char *)a_token_ticker, VOTING_TSD_TYPE_TOKEN, l_ticker_len); + return l_tsd; +} + dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx) { dap_chain_tx_voting_tx_cond_t l_temp = { @@ -176,6 +188,9 @@ json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_ case VOTING_TSD_TYPE_ANSWER: json_object_array_add(l_answer_array_object, json_object_new_string_len((char*)l_tsd->data, l_tsd->size)); break; + case VOTING_TSD_TYPE_TOKEN: + json_object_object_add(l_object, "token", json_object_new_string_len((char*)l_tsd->data, l_tsd->size)); + break; case VOTING_TSD_TYPE_EXPIRE: json_object_object_add(l_object, "exired", json_object_new_uint64(*(uint64_t*)l_tsd->data)); break; diff --git a/modules/common/include/dap_chain_datum_tx_voting.h b/modules/common/include/dap_chain_datum_tx_voting.h index a87c67824c..add632997a 100644 --- a/modules/common/include/dap_chain_datum_tx_voting.h +++ b/modules/common/include/dap_chain_datum_tx_voting.h @@ -43,7 +43,8 @@ typedef enum dap_chain_datum_voting_tsd_type { VOTING_TSD_TYPE_MAX_VOTES_COUNT, VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED, VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED, - VOTING_TSD_TYPE_VOTE_TX_COND + VOTING_TSD_TYPE_VOTE_TX_COND, + VOTING_TSD_TYPE_TOKEN } dap_chain_datum_voting_tsd_type_t; typedef struct dap_chain_tx_voting { @@ -63,13 +64,14 @@ typedef struct dap_chain_tx_vote { typedef struct dap_chain_datum_tx_voting_params { - char *voting_question; + char *voting_question; dap_list_t *answers_list; uint8_t answers_count; dap_time_t voting_expire; uint64_t votes_max_count; bool delegate_key_required; bool vote_changing_allowed; + char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; } dap_chain_datum_tx_voting_params_t; #ifdef __cplusplus @@ -86,6 +88,7 @@ dap_chain_tx_tsd_t* dap_chain_datum_voting_max_votes_count_tsd_create(uint64_t a dap_chain_tx_tsd_t *dap_chain_datum_voting_delegated_key_required_tsd_create(bool a_delegated_key_required); dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_changing_allowed_tsd_create(bool a_vote_changing_allowed); dap_chain_tx_tsd_t* dap_chain_datum_voting_vote_tx_cond_tsd_create(dap_chain_hash_fast_t a_tx_hash, int a_out_idx); +dap_chain_tx_tsd_t *dap_chain_datum_voting_token_tsd_create(const char *a_token_ticker); dap_chain_tx_voting_t *dap_chain_datum_tx_item_voting_create(void); json_object *dap_chain_datum_tx_item_voting_tsd_to_json(dap_chain_datum_tx_t* a_tx); @@ -96,4 +99,4 @@ json_object *dap_chain_datum_tx_item_vote_to_json(dap_chain_tx_vote_t *a_vote, d #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c index 88546b2272..f7c088e54b 100644 --- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c +++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c @@ -837,7 +837,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_ dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs); dap_list_t *l_ret = NULL; dap_list_t *l_validators = NULL; - if (!l_esbocs_pvt->poa_mode) { + if (l_esbocs_pvt->poa_mode) { // UNDO it after debug if (a_excluded_list_size) { l_validators = dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL); uint16_t l_excluded_num = *a_excluded_list; @@ -2774,6 +2774,9 @@ static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_b static uint64_t s_get_precached_key_hash(dap_list_t **a_precached_keys_list, dap_sign_t *a_source_sign, dap_hash_fast_t *a_result) { + if (DAP_SIGN_GET_PKEY_HASHING_FLAG(a_source_sign->header.hash_type)) + return !dap_sign_get_pkey_hash(a_source_sign, a_result); + bool l_found = false; struct precached_key *l_key = NULL; dap_list_t *l_cur; diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c index 03fcb33ba6..deaac956e7 100644 --- a/modules/net/dap_chain_ledger.c +++ b/modules/net/dap_chain_ledger.c @@ -5678,10 +5678,13 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * // Get 'out_cond' item from transaction byte_t *l_item; size_t l_size; int i, l_out_idx = 0; TX_ITEM_ITER_TX_TYPE(l_item, TX_ITEM_TYPE_OUT_ALL, l_size, i, it->tx) { - if (*l_item == TX_ITEM_TYPE_OUT_COND && - ((dap_chain_tx_out_cond_t *)l_item)->header.subtype == a_subtype) { - ret = (dap_chain_tx_out_cond_t *)l_item; - break; + if (*l_item == TX_ITEM_TYPE_OUT_COND) { + dap_chain_tx_out_cond_subtype_t l_subtype = ((dap_chain_tx_out_cond_t *)l_item)->header.subtype; + if (l_subtype == a_subtype || + (a_subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL && l_subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)) { + ret = (dap_chain_tx_out_cond_t *)l_item; + break; + } } l_out_idx++; } @@ -5689,7 +5692,8 @@ dap_chain_tx_out_cond_t *dap_ledger_out_cond_unspent_find_by_addr(dap_ledger_t * if (!ret || !dap_hash_fast_is_blank(&it->cache_data.tx_hash_spent_fast[l_out_idx])) continue; dap_hash_fast_t l_owner_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, it->tx, a_subtype); - dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash); + dap_chain_datum_tx_t *l_tx = dap_hash_fast_is_blank(&l_owner_tx_hash) ? it->tx + : dap_ledger_tx_find_by_hash(a_ledger, &l_owner_tx_hash); if (!l_tx) { log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(&it->tx_hash_fast)); continue; @@ -5738,12 +5742,13 @@ bool dap_ledger_check_condition_owner(dap_ledger_t *a_ledger, dap_hash_fast_t *a log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(a_tx_hash)); return false; } - dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype); - if (dap_hash_fast_is_blank(&l_first_tx_hash)) { + if (!dap_chain_datum_tx_out_cond_get(l_check_tx, a_cond_subtype, NULL)) { log_it(L_ERROR, "Can't find owner for tx %s", dap_hash_fast_to_str_static(a_tx_hash)); return false; } - dap_chain_datum_tx_t *l_first_tx = dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash); + dap_hash_fast_t l_first_tx_hash = dap_ledger_get_first_chain_tx_hash(a_ledger, l_check_tx, a_cond_subtype); + dap_chain_datum_tx_t *l_first_tx = dap_hash_fast_is_blank(&l_first_tx_hash) ? l_check_tx + : dap_ledger_tx_find_by_hash(a_ledger, &l_first_tx_hash); if (!l_first_tx) { log_it(L_ERROR, "Can't find owner tx %s", dap_hash_fast_to_str_static(&l_first_tx_hash)); return false; diff --git a/modules/net/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c index addcb27c56..937c0464f5 100644 --- a/modules/net/dap_chain_net_tx.c +++ b/modules/net/dap_chain_net_tx.c @@ -1633,7 +1633,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json json_object_object_add(json_obj_item,"type", json_object_new_string("voting")); json_object_object_add(json_obj_item,"voting_question", json_object_new_string(l_voting_params->voting_question)); json_object_object_add(json_obj_item,"answer_options", json_object_new_string("")); - + json_object_object_add(json_obj_item, "token", json_object_new_string(l_voting_params->token_ticker)); dap_list_t *l_temp = l_voting_params->answers_list; uint8_t l_index = 0; while (l_temp) { @@ -1643,7 +1643,7 @@ int dap_chain_net_tx_to_json(dap_chain_datum_tx_t *a_tx, json_object *a_out_json } if (l_voting_params->voting_expire) { dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting_params->voting_expire); - json_object_object_add(json_obj_item,"Voting expire", json_object_new_string(l_tmp_buf)); + json_object_object_add(json_obj_item, "Voting expire", json_object_new_string(l_tmp_buf)); } if (l_voting_params->votes_max_count) { json_object_object_add(json_obj_item, "Votes max count", json_object_new_uint64(l_voting_params->votes_max_count)); diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c index 3734ed953c..6f55e66960 100644 --- a/modules/service/voting/dap_chain_net_srv_voting.c +++ b/modules/service/voting/dap_chain_net_srv_voting.c @@ -50,6 +50,7 @@ typedef struct dap_chain_net_voting_params_offsets{ uint64_t votes_max_count; bool delegate_key_required; bool vote_changing_allowed; + char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; } dap_chain_net_voting_params_offsets_t; typedef struct dap_chain_net_vote_option { @@ -115,7 +116,8 @@ int dap_chain_net_srv_voting_init() pthread_rwlock_init(&s_votings_rwlock, NULL); dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback); dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", "" - "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>] [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name>\n" + "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>]" + " [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name> -token <ticker>\n" "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n" "voting list -net <net_name>\n" "voting dump -net <net_name> -hash <voting_hash>\n"); @@ -218,14 +220,29 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t dap_list_t* l_tsd_list = dap_chain_datum_tx_items_get(a_tx_in, TX_ITEM_TYPE_TSD, NULL); for (dap_list_t *it = l_tsd_list; it; it = it->next) { - dap_tsd_t* l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t*)it->data)->tsd; + dap_chain_tx_tsd_t *l_tx_tsd = it->data; + dap_tsd_t *l_tsd = (dap_tsd_t *)l_tx_tsd->tsd; + if (l_tx_tsd->header.size < sizeof(dap_tsd_t) || + l_tx_tsd->header.size != dap_tsd_size(l_tsd)) { + log_it(L_WARNING, "Incorrect size %" DAP_UINT64_FORMAT_U " of TX_TSD item for voting %s", + l_tx_tsd->header.size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } dap_chain_net_vote_option_t *l_vote_option = NULL; switch(l_tsd->type){ case VOTING_TSD_TYPE_QUESTION: + if (!l_tsd->size) { + log_it(L_WARNING, "Incorrect size %u of TSD section QUESTION for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } l_item->voting_params.voting_question_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx); l_item->voting_params.voting_question_length = l_tsd->size; break; case VOTING_TSD_TYPE_ANSWER: + if (!l_tsd->size) { + log_it(L_WARNING, "Incorrect size %u of TSD section ANSWER for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } l_vote_option = DAP_NEW_Z(dap_chain_net_vote_option_t); l_vote_option->vote_option_offset = (size_t)(l_tsd->data - (byte_t*)l_item->voting_params.voting_tx); l_vote_option->vote_option_length = l_tsd->size; @@ -233,41 +250,50 @@ static int s_voting_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t break; case VOTING_TSD_TYPE_EXPIRE: if (l_tsd->size != sizeof(dap_time_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section EXPIRE for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.voting_expire = *(dap_time_t *)l_tsd->data; break; case VOTING_TSD_TYPE_MAX_VOTES_COUNT: if (l_tsd->size != sizeof(uint64_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section MAX_VOTES_COUNT for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.votes_max_count = *(uint64_t *)l_tsd->data; break; case VOTING_TSD_TYPE_DELEGATED_KEY_REQUIRED: if (l_tsd->size != sizeof(byte_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section DELEGATED_KEY_REQUIRED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.delegate_key_required = *(byte_t *)l_tsd->data; break; case VOTING_TSD_TYPE_VOTE_CHANGING_ALLOWED: if (l_tsd->size != sizeof(byte_t)) { - log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED vot voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + log_it(L_WARNING, "Incorrect size %u of TSD section VOTE_CHANGING_ALLOWED for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INVALID_SIZE; } l_item->voting_params.vote_changing_allowed = *(byte_t *)l_tsd->data; break; + case VOTING_TSD_TYPE_TOKEN: + if (!l_tsd->size || l_tsd->size >= DAP_CHAIN_TICKER_SIZE_MAX) { + log_it(L_WARNING, "Incorrect size %u of TSD section TOKEN for voting %s", l_tsd->size, dap_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INVALID_SIZE; + } + strcpy(l_item->voting_params.token_ticker, (char *)l_tsd->data); default: break; } } dap_list_free(l_tsd_list); + if (!*l_item->voting_params.token_ticker) + strcpy(l_item->voting_params.token_ticker, a_ledger->net->pub.native_ticker); pthread_rwlock_wrlock(&s_votings_rwlock); HASH_ADD(hh, s_votings, voting_hash, sizeof(dap_hash_fast_t), l_item); pthread_rwlock_unlock(&s_votings_rwlock); + log_it(L_NOTICE, "Voting with hash %s succefully added to ledger", dap_hash_fast_to_str_static(a_tx_hash)); return DAP_LEDGER_CHECK_OK; } @@ -340,25 +366,26 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a int l_out_idx = ((dap_chain_tx_voting_tx_cond_t*)l_tsd->data)->out_idx; if (l_tsd->type != VOTING_TSD_TYPE_VOTE_TX_COND) return -14; - if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) - return -15; dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_hash); - dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t*)dap_chain_datum_tx_item_get(l_tx_prev_temp, &l_out_idx, NULL, TX_ITEM_TYPE_OUT_COND, NULL); - if (!l_prev_out || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) + dap_chain_tx_out_cond_t *l_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_out_idx); + if (!l_prev_out || l_prev_out->header.item_type != TX_ITEM_TYPE_OUT_COND || l_prev_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) return -16; if (!dap_ledger_check_condition_owner(a_ledger, &l_hash, l_prev_out->header.subtype, l_out_idx, (dap_sign_t *)l_tx_sig->sig)) return -17; + if (s_datum_tx_voting_coin_check_cond_out(a_ledger->net, l_vote_tx_item->voting_hash, l_hash, l_out_idx)) + return -15; if (SUM_256_256(l_weight, l_prev_out->header.value, &l_weight)) { log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; } - - dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); - l_item->tx_hash = l_hash; - l_item->out_idx = l_out_idx; - pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); - HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); - pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); + if (a_apply) { + dap_chain_net_voting_cond_outs_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_net_voting_cond_outs_t, -DAP_LEDGER_CHECK_NOT_ENOUGH_MEMORY); + l_item->tx_hash = l_hash; + l_item->out_idx = l_out_idx; + pthread_rwlock_wrlock(&l_voting->s_tx_outs_rwlock); + HASH_ADD(hh, l_voting->voting_spent_cond_outs, tx_hash, sizeof(dap_hash_fast_t), l_item); + pthread_rwlock_unlock(&l_voting->s_tx_outs_rwlock); + } } dap_list_free(l_tsd_list); // check inputs @@ -369,17 +396,34 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a } for (dap_list_t *it = l_ins_list; it; it = it->next) { dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data; - if (!s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, + dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); + dap_chain_tx_out_ext_t *l_prev_out_union = (dap_chain_tx_out_ext_t *)dap_chain_datum_tx_out_get_by_out_idx( + l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx); + if (!l_prev_out_union) + return -18; + const char *l_ticker_in = NULL; + switch (l_prev_out_union->header.type) { + case TX_ITEM_TYPE_OUT: + l_ticker_in = dap_ledger_tx_get_token_ticker_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); + break; + case TX_ITEM_TYPE_OUT_EXT: + l_ticker_in = l_prev_out_union->token; + break; + default: + log_it(L_WARNING, "Unexpected tx item %d in vote tx %s", l_prev_out_union->header.type, dap_hash_fast_to_str_static(a_tx_hash)); + return -19; + } + if (dap_strcmp(l_ticker_in, l_voting->voting_params.token_ticker)) + continue; + if (s_datum_tx_voting_coin_check_spent(a_ledger->net, l_vote_tx_item->voting_hash, l_tx_in->header.tx_prev_hash, l_tx_in->header.tx_out_prev_idx, &pkey_hash)) { - dap_chain_datum_tx_t *l_tx_prev_temp = dap_ledger_tx_find_by_hash(a_ledger, &l_tx_in->header.tx_prev_hash); - dap_chain_tx_out_t *l_prev_out_union = (dap_chain_tx_out_t *)dap_chain_datum_tx_out_get_by_out_idx(l_tx_prev_temp, l_tx_in->header.tx_out_prev_idx); - if (!l_prev_out_union) - return -18; - if ((l_prev_out_union->header.type == TX_ITEM_TYPE_OUT || l_prev_out_union->header.type == TX_ITEM_TYPE_OUT_EXT) && - SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { - log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); - return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; - } + log_it(L_WARNING, "Coin with out number %u for tx %s is spent for votnig %s", l_tx_in->header.tx_out_prev_idx, + dap_hash_fast_to_str_static(a_tx_hash), dap_hash_fast_to_str_static(&l_vote_tx_item->voting_hash)); + return -20; + } + if (SUM_256_256(l_weight, l_prev_out_union->header.value, &l_weight)) { + log_it(L_WARNING, "Integer overflow while parsing vote tx %s", dap_chain_hash_fast_to_str_static(a_tx_hash)); + return -DAP_LEDGER_CHECK_INTEGER_OVERFLOW; } } dap_list_free(l_ins_list); @@ -436,14 +480,14 @@ static int s_vote_verificator(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; dap_hash_fast_to_str(&((dap_chain_net_vote_t *)it->data)->vote_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); DAP_DELETE(it->data); - log_it(L_INFO, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); + log_it(L_NOTICE, "Vote %s of voting %s has been changed", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); return DAP_LEDGER_CHECK_OK; } } l_voting->votes = dap_list_append(l_voting->votes, l_vote_item); char l_vote_hash_str[DAP_HASH_FAST_STR_SIZE]; dap_hash_fast_to_str(a_tx_hash, l_vote_hash_str, DAP_HASH_FAST_STR_SIZE); - log_it(L_INFO, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); + log_it(L_NOTICE, "Vote %s of voting %s has been accepted", l_vote_hash_str, dap_hash_fast_to_str_static(&l_voting->voting_hash)); } return DAP_LEDGER_CHECK_OK; } @@ -503,7 +547,7 @@ static bool s_datum_tx_voting_verification_delete_callback(dap_ledger_t *a_ledge return false; } - dap_chain_net_votings_t * l_voting = NULL; + dap_chain_net_votings_t *l_voting = NULL; pthread_rwlock_wrlock(&s_votings_rwlock); HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting); pthread_rwlock_unlock(&s_votings_rwlock); @@ -615,6 +659,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) const char* l_max_votes_count_str = NULL; const char* l_fee_str = NULL; const char* l_wallet_str = NULL; + const char *l_token_str = NULL; dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-question", &l_question_str); if (!l_question_str){ @@ -647,8 +692,6 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_CONTAIN_MAX_OPTIONS; } - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); - dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_str); if (!l_fee_str){ dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_FEE_PARAM_NOT_VALID, "Voting requires paramete -fee to be valid."); @@ -662,6 +705,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID; } + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-expire", &l_voting_expire_str); dap_time_t l_time_expire = 0; if (l_voting_expire_str) l_time_expire = dap_time_from_str_rfc822(l_voting_expire_str); @@ -670,6 +714,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) "Wrong time format. -expire parameter must be in format \"Day Month Year HH:MM:SS Timezone\" e.g. \"19 August 2024 22:00:00 +00\""); return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT; } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-max_votes_count", &l_max_votes_count_str); uint64_t l_max_count = 0; if (l_max_votes_count_str) l_max_count = strtoul(l_max_votes_count_str, NULL, 10); @@ -683,8 +729,26 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) return -DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST; } + + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-token", &l_token_str); + if (l_token_str && !dap_ledger_token_ticker_check(l_net->pub.ledger, l_token_str)) { + dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, "Token %s does not exist", l_token_str); + return -DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN; + } + char *l_hash_ret = NULL; - int res = dap_chain_net_vote_create(l_question_str, l_options_list, l_time_expire, l_max_count, l_value_fee, l_is_delegated_key, l_is_vote_changing_allowed, l_wallet_fee, l_net, l_hash_out_type, &l_hash_ret); + int res = dap_chain_net_vote_create(l_question_str, + l_options_list, + l_time_expire, + l_max_count, + l_value_fee, + l_is_delegated_key, + l_is_vote_changing_allowed, + l_wallet_fee, + l_net, + l_token_str, + l_hash_out_type, + &l_hash_ret); dap_list_free(l_options_list); dap_chain_wallet_close(l_wallet_fee); @@ -812,8 +876,8 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) } const char *c_wallets_path = dap_chain_wallet_get_path(g_config); - dap_chain_wallet_t *l_wallet_fee = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); - if (!l_wallet_fee) { + dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, c_wallets_path,NULL); + if (!l_wallet) { dap_json_rpc_error_add(*json_arr_reply, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, "Wallet %s does not exist", l_wallet_str); return -DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST; } @@ -822,9 +886,9 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) char *l_hash_tx; - int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet_fee, l_voting_hash, l_option_idx_count, + int res = dap_chain_net_vote_voting(l_cert, l_value_fee, l_wallet, l_voting_hash, l_option_idx_count, l_net, l_hash_out_type, &l_hash_tx); - dap_chain_wallet_close(l_wallet_fee); + dap_chain_wallet_close(l_wallet); switch (res) { case DAP_CHAIN_NET_VOTE_VOTING_OK: { @@ -918,6 +982,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) char* l_voting_question = (char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset; json_object_object_add( json_obj_vote, "question", json_object_new_string_len(l_voting_question, l_voting->voting_params.voting_question_length) ); + json_object_object_add(json_obj_vote, "token", json_object_new_string(l_voting->voting_params.token_ticker)); json_object_array_add(json_arr_voting_out, json_obj_vote); } pthread_rwlock_unlock(&s_votings_rwlock); @@ -968,6 +1033,7 @@ static int s_cli_voting(int a_argc, char **a_argv, void **a_str_reply) json_object_object_add(json_vote_out, "question", json_object_new_string_len((char*)l_voting->voting_params.voting_tx + l_voting->voting_params.voting_question_offset, l_voting->voting_params.voting_question_length)); + json_object_object_add(json_vote_out, "token", json_object_new_string(l_voting->voting_params.token_ticker)); if (l_voting->voting_params.voting_expire) { char l_tmp_buf[DAP_TIME_STR_SIZE]; dap_time_to_str_rfc822(l_tmp_buf, DAP_TIME_STR_SIZE, l_voting->voting_params.voting_expire); @@ -1028,21 +1094,26 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f { int l_coin_is_spent = 0; - - dap_ledger_t *l_ledger = a_net->pub.ledger; - if(!l_ledger){ - log_it(L_ERROR, "Can't find ledger"); + dap_chain_net_votings_t *l_voting = NULL; + pthread_rwlock_wrlock(&s_votings_rwlock); + HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); + pthread_rwlock_unlock(&s_votings_rwlock); + if (!l_voting) { + log_it(L_ERROR, "Can't find voting %s", dap_hash_fast_to_str_static(&a_voting_hash)); return -1; } + const char *l_token_ticker = l_voting->voting_params.token_ticker; + dap_ledger_t *l_ledger = a_net->pub.ledger; dap_chain_datum_tx_t *l_voting_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_voting_hash); - const char *l_native_ticker = a_net->pub.native_ticker; - - dap_list_t *l_tx_list = NULL; // "stack" for saving txs on up level + if (!l_voting_tx) { + log_it(L_ERROR, "Can't find voting tx %s", dap_hash_fast_to_str_static(&a_voting_hash)); + return -2; + } dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(l_ledger, &a_tx_prev_hash); - if (!l_tx){ - log_it(L_ERROR, "Can't find tx"); - return -1; + if (!l_tx) { + log_it(L_ERROR, "Can't find tx %s", dap_hash_fast_to_str_static(&a_tx_prev_hash)); + return -3; } if (l_tx->header.ts_created < l_voting_tx->header.ts_created){ @@ -1055,25 +1126,18 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f dap_chain_tx_vote_t *l_vote = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(l_tx, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); if (l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)) { - dap_chain_net_votings_t *l_voting = NULL; - pthread_rwlock_wrlock(&s_votings_rwlock); - HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); - pthread_rwlock_unlock(&s_votings_rwlock); - if (l_voting) { - for (dap_list_t *it = l_voting->votes; it; it = it->next) { - dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; - if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) { - if (l_voting->voting_params.vote_changing_allowed && - !dap_hash_fast_is_blank(a_pkey_hash) && - dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) - break; // it's vote changing, allow it - return 1; - } + for (dap_list_t *it = l_voting->votes; it; it = it->next) { + dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)it->data; + if (dap_hash_fast_compare(&l_vote->vote_hash, &a_tx_prev_hash)) { + if (l_voting->voting_params.vote_changing_allowed && + !dap_hash_fast_is_blank(a_pkey_hash) && + dap_hash_fast_compare(&l_vote->pkey_hash, a_pkey_hash)) + break; // it's vote changing, allow it + return 1; } } } - dap_list_t *l_ins_list_temp = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL); dap_list_t *l_cond_ins_list = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL); if (!l_ins_list_temp && !l_cond_ins_list){ @@ -1081,12 +1145,9 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f return -1; } - dap_list_t *l_ins_list = NULL; - l_ins_list = dap_list_concat(l_ins_list, l_ins_list_temp); - l_ins_list = dap_list_concat(l_ins_list, l_cond_ins_list); - - l_tx_list = dap_list_append(l_tx_list, l_ins_list); - dap_list_t* l_tx_temp = dap_list_last(l_tx_list); + dap_list_t *l_ins_list = dap_list_concat(l_ins_list_temp, l_cond_ins_list); + dap_list_t *l_tx_list = dap_list_append(NULL, l_ins_list); // "stack" for saving txs on up level + dap_list_t *l_tx_temp = dap_list_last(l_tx_list); while(l_tx_temp && !l_coin_is_spent){ if (l_tx_temp->data == NULL){ @@ -1118,22 +1179,24 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f l_tx_token = l_temp_out->token; }break; case TX_ITEM_TYPE_OUT_COND:{ - dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t*)l_prev_out_union; - if (l_temp_out->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK || - s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, l_temp_in->header.tx_out_prev_idx) == 0) + dap_chain_tx_out_cond_t *l_temp_out = (dap_chain_tx_out_cond_t *)l_prev_out_union; + if (l_temp_out->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) { + l_tx_token = a_net->pub.native_ticker; break; + } + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_voting_hash, l_temp_in->header.tx_prev_hash, + l_temp_in->header.tx_out_prev_idx) != 0) { + l_coin_is_spent = 1; + continue; + } + l_tx_token = dap_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_temp_in->header.tx_prev_hash); } default: - l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); - if (l_tx_temp->data == NULL){ - l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); - l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } - continue; + break; } if (l_tx_prev_temp->header.ts_created < l_voting_tx->header.ts_created || - dap_strcmp(l_tx_token, l_native_ticker)){ + dap_strcmp(l_tx_token, l_token_ticker)){ l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); if (l_tx_temp->data == NULL){ l_tx_list = dap_list_delete_link(l_tx_list, l_tx_temp); @@ -1142,13 +1205,8 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f continue; } - dap_chain_tx_vote_t *l_vote =(dap_chain_tx_vote_t *) dap_chain_datum_tx_item_get(l_tx_prev_temp, NULL, NULL, TX_ITEM_TYPE_VOTE, NULL); if(l_vote && dap_hash_fast_compare(&l_vote->voting_hash, &a_voting_hash)){ - dap_chain_net_votings_t *l_voting = NULL; - pthread_rwlock_wrlock(&s_votings_rwlock); - HASH_FIND(hh, s_votings, &a_voting_hash, sizeof(dap_hash_fast_t), l_voting); - pthread_rwlock_unlock(&s_votings_rwlock); dap_list_t *l_temp = NULL; while (l_temp){ dap_chain_net_vote_t *l_vote = (dap_chain_net_vote_t *)l_temp->data; @@ -1160,12 +1218,10 @@ static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_f } } - l_ins_list = dap_chain_datum_tx_items_get(l_tx_prev_temp, TX_ITEM_TYPE_IN, NULL); l_tx_list = dap_list_append(l_tx_list, l_ins_list); l_tx_temp->data = dap_list_remove((dap_list_t*)l_tx_temp->data, l_temp_in); l_tx_temp = l_tx_list ? dap_list_last(l_tx_list) : NULL; - } if(l_tx_list){ @@ -1209,7 +1265,8 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output) { + dap_chain_net_t *a_net, const char *a_token_ticker, + const char *a_hash_out_type, char **a_hash_output) { if (strlen(a_question) > DAP_CHAIN_DATUM_TX_VOTING_QUESTION_MAX_LENGTH){ return DAP_CHAIN_NET_VOTE_CREATE_LENGTH_QUESTION_OVERSIZE_MAX; @@ -1243,8 +1300,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap dap_ledger_t* l_ledger = a_net->pub.ledger; dap_list_t *l_list_used_out = NULL; if (dap_chain_wallet_cache_tx_find_outs_with_val(a_net, l_native_ticker, l_addr_from, &l_list_used_out, l_total_fee, &l_value_transfer) == -101) - l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, - l_addr_from, l_total_fee, &l_value_transfer); + l_list_used_out = dap_ledger_get_list_tx_outs_with_val(l_ledger, l_native_ticker, l_addr_from, l_total_fee, &l_value_transfer); if (!l_list_used_out) { return DAP_CHAIN_NET_VOTE_CREATE_NOT_ENOUGH_FUNDS_TO_TRANSFER; } @@ -1327,6 +1383,16 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap DAP_DEL_Z(l_vote_changing_item); } + if (a_token_ticker) { + dap_chain_tx_tsd_t *l_voting_token_item = dap_chain_datum_voting_token_tsd_create(a_token_ticker); + if (!l_voting_token_item) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN; + } + dap_chain_datum_tx_add_item(&l_tx, l_voting_token_item); + DAP_DEL_Z(l_voting_token_item); + } + // add 'in' items uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); assert(EQUAL_256(l_value_to_items, l_value_transfer)); @@ -1334,7 +1400,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap uint256_t l_value_pack = {}; // Network fee if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1) + if (dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, l_native_ticker) == 1) SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); else { dap_chain_datum_tx_delete(l_tx); @@ -1354,7 +1420,7 @@ int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap uint256_t l_value_back; SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { + if(dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_native_ticker) != 1) { dap_chain_datum_tx_delete(l_tx); return DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; } @@ -1433,15 +1499,18 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal if (!l_addr_from) return DAP_CHAIN_NET_VOTE_VOTING_SOURCE_ADDRESS_INVALID; - const char *l_native_ticker = a_net->pub.native_ticker; - uint256_t l_net_fee = {}, l_total_fee = {}, l_value_transfer; + const char *l_token_ticker = l_voting->voting_params.token_ticker; + uint256_t l_net_fee = {}, l_total_fee = a_fee, l_value_transfer, l_fee_transfer; dap_chain_addr_t l_addr_fee = {}; bool l_net_fee_used = dap_chain_net_tx_get_fee(a_net->pub.id, &l_net_fee, &l_addr_fee); - SUM_256_256(l_net_fee, a_fee, &l_total_fee); + if (l_net_fee_used) + SUM_256_256(l_net_fee, a_fee, &l_total_fee); - dap_ledger_t* l_ledger = dap_ledger_by_net_name(a_net->pub.name); - dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_native_ticker, l_addr_from, &l_value_transfer); - if (!l_list_used_out || compare256(l_value_transfer, l_total_fee) <= 0) { + bool l_native_tx = !dap_strcmp(l_token_ticker, a_net->pub.native_ticker); + dap_ledger_t *l_ledger = a_net->pub.ledger; + dap_list_t *l_list_used_out = dap_ledger_get_list_tx_outs(l_ledger, l_token_ticker, l_addr_from, &l_value_transfer); + if (!l_list_used_out || (l_native_tx && compare256(l_value_transfer, l_total_fee) < 0)) { + dap_list_free_full(l_list_used_out, NULL); return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; } @@ -1459,15 +1528,33 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal return DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW; } - if (IS_ZERO_256(l_value_transfer_new) || compare256(l_value_transfer_new, l_total_fee) <= 0){ + if (IS_ZERO_256(l_value_transfer_new) || (l_native_tx && compare256(l_value_transfer_new, l_total_fee) <= 0)) return DAP_CHAIN_NET_VOTE_VOTING_UNSPENT_UTX0_FOR_PARTICIPATION_THIS_VOTING; - } l_value_transfer = l_value_transfer_new; // create empty transaction dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create(); + uint256_t l_value_back = l_value_transfer, l_fee_back = {}; + if (!l_native_tx) { + dap_list_t *l_list_fee_outs = dap_ledger_get_list_tx_outs_with_val(l_ledger, a_net->pub.native_ticker, l_addr_from, l_total_fee, &l_fee_transfer); + if (!l_list_fee_outs) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_NOT_ENOUGH_FUNDS_TO_TRANSFER; + } + uint256_t l_value_fee_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_fee_outs); + assert(EQUAL_256(l_value_fee_items, l_fee_transfer)); + dap_list_free_full(l_list_fee_outs, NULL); + SUBTRACT_256_256(l_fee_transfer, l_total_fee, &l_fee_back); + } else + SUBTRACT_256_256(l_value_transfer, l_total_fee, &l_value_back); + + // add 'in' items + uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); + assert(EQUAL_256(l_value_to_items, l_value_transfer)); + dap_list_free_full(l_list_used_out, NULL); + // Add vote item if (a_option_idx > dap_list_length(l_voting->voting_params.option_offsets_list)){ dap_chain_datum_tx_delete(l_tx); @@ -1481,14 +1568,12 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal dap_chain_datum_tx_add_item(&l_tx, l_vote_item); DAP_DEL_Z(l_vote_item); - // add stake out conds items - dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, a_net->pub.native_ticker, l_addr_from); + // add out conds items + dap_list_t *l_outs = dap_ledger_get_list_tx_cond_outs(l_ledger, DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL, l_token_ticker, l_addr_from); for (dap_list_t *it = l_outs; it; it = it->next) { dap_chain_tx_used_out_item_t *l_out_item = (dap_chain_tx_used_out_item_t *)it->data; - if (dap_ledger_tx_hash_is_used_out_item(a_net->pub.ledger, &l_out_item->tx_hash_fast, l_out_item->num_idx_out, NULL) || - s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out ) != 0){ + if (s_datum_tx_voting_coin_check_cond_out(a_net, a_hash, l_out_item->tx_hash_fast, l_out_item->num_idx_out) != 0) continue; - } dap_chain_tx_tsd_t *l_item = dap_chain_datum_voting_vote_tx_cond_tsd_create(l_out_item->tx_hash_fast, l_out_item->num_idx_out); if(!l_item){ dap_chain_datum_tx_delete(l_tx); @@ -1501,37 +1586,26 @@ int dap_chain_net_vote_voting(dap_cert_t *a_cert, uint256_t a_fee, dap_chain_wal } dap_list_free_full(l_outs, NULL); - // add 'in' items - uint256_t l_value_to_items = dap_chain_datum_tx_add_in_item_list(&l_tx, l_list_used_out); - assert(EQUAL_256(l_value_to_items, l_value_transfer)); - dap_list_free_full(l_list_used_out, NULL); - uint256_t l_value_pack = {}; // Network fee - if (l_net_fee_used) { - if (dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_fee, l_net_fee) == 1) - SUM_256_256(l_value_pack, l_net_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } + if (l_net_fee_used && dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_fee, l_net_fee, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; } + // Validator's fee - if (!IS_ZERO_256(a_fee)) { - if (dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) == 1) - SUM_256_256(l_value_pack, a_fee, &l_value_pack); - else { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; - } + if (!IS_ZERO_256(a_fee) && dap_chain_datum_tx_add_fee_item(&l_tx, a_fee) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_NET_FEE_OUT; } + // coin back - uint256_t l_value_back; - SUBTRACT_256_256(l_value_transfer, l_value_pack, &l_value_back); - if(!IS_ZERO_256(l_value_back)) { - if(dap_chain_datum_tx_add_out_item(&l_tx, l_addr_from, l_value_back) != 1) { - dap_chain_datum_tx_delete(l_tx); - return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; - } + if (!IS_ZERO_256(l_value_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_value_back, l_token_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; + } + if (!IS_ZERO_256(l_fee_back) && dap_chain_datum_tx_add_out_ext_item(&l_tx, l_addr_from, l_fee_back, a_net->pub.native_ticker) != 1) { + dap_chain_datum_tx_delete(l_tx); + return DAP_CHAIN_NET_VOTE_VOTING_CAN_NOT_ADD_OUT_WITH_VALUE_BACK; } // add 'sign' items with wallet sign diff --git a/modules/service/voting/include/dap_chain_net_srv_voting.h b/modules/service/voting/include/dap_chain_net_srv_voting.h index 4bd1f71694..6252b37771 100644 --- a/modules/service/voting/include/dap_chain_net_srv_voting.h +++ b/modules/service/voting/include/dap_chain_net_srv_voting.h @@ -94,13 +94,14 @@ enum DAP_CHAIN_NET_VOTE_CREATE_ERROR { DAP_CHAIN_NET_VOTE_CREATE_WALLET_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_CREATE_WALLET_DOES_NOT_EXIST, DAP_CHAIN_NET_VOTE_CREATE_WRONG_TIME_FORMAT, - + DAP_CHAIN_NET_VOTE_CREATE_WRONG_TOKEN, + DAP_CHAIN_NET_VOTE_CREATE_CAN_NOT_CREATE_TSD_TOKEN, DAP_CHAIN_NET_VOTE_CREATE_UNKNOWN_ERR }; int dap_chain_net_vote_create(const char *a_question, dap_list_t *a_options, dap_time_t a_expire_vote, uint64_t a_max_vote, uint256_t a_fee, bool a_delegated_key_required, bool a_vote_changing_allowed, dap_chain_wallet_t *a_wallet, - dap_chain_net_t *a_net, const char *a_hash_out_type, char **a_hash_output); + dap_chain_net_t *a_net, const char *a_token_ticker, const char *a_hash_out_type, char **a_hash_output); enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_OK, @@ -131,7 +132,6 @@ enum DAP_CHAIN_NET_VOTE_VOTING_ERROR{ DAP_CHAIN_NET_VOTE_VOTING_WALLET_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_OPTION_IDX_PARAM_NOT_VALID, DAP_CHAIN_NET_VOTE_VOTING_WALLET_DOES_NOT_EXIST, - DAP_CHAIN_NET_VOTE_VOTING_UNKNOWN_ERR, DAP_CHAIN_NET_VOTE_VOTING_INTEGER_OVERFLOW -- GitLab