diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c index 569634b55a490b77327c0412a3710f0695382266..795d304030c402d61de15319f3f89bd5862c7b37 100644 --- a/modules/ledger/dap_chain_ledger.c +++ b/modules/ledger/dap_chain_ledger.c @@ -1518,6 +1518,28 @@ dap_chain_datum_tx_t *dap_ledger_datum_iter_get_last(dap_ledger_datum_iter_t *a_ return a_iter->cur; } +dap_chain_tx_used_out_item_t *dap_ledger_get_tx_cond_out(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr_from, dap_chain_tx_out_cond_subtype_t a_subtype) +{ + dap_chain_tx_used_out_item_t *l_item = NULL; + dap_chain_hash_fast_t l_tx_cur_hash = { }; + dap_chain_datum_tx_t *l_tx; + while(( l_tx = dap_ledger_tx_find_by_addr(a_ledger, a_ledger->net->pub.native_ticker, a_addr_from, &l_tx_cur_hash) )) { + byte_t *it; size_t l_size; int i, l_out_idx_tmp = -1; + TX_ITEM_ITER_TX_TYPE(it, TX_ITEM_TYPE_OUT_COND, l_size, i, l_tx) { + ++l_out_idx_tmp; + dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t *)it; + if ( a_subtype != l_out_cond->header.subtype || IS_ZERO_256(l_out_cond->header.value) ) + continue; + if (dap_ledger_tx_hash_is_used_out_item(a_ledger, &l_tx_cur_hash, l_out_idx_tmp, NULL)) + continue; // TODO Move this check to dap_ledger_tx_find_by_addr() to avoid double search + l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t); + *l_item = (dap_chain_tx_used_out_item_t) { l_tx_cur_hash, (uint32_t)l_out_idx_tmp, l_out_cond->header.value }; + } + } + + return l_item; +} + /** * @brief dap_ledger_get_list_tx_cond_outs_with_val diff --git a/modules/ledger/include/dap_chain_ledger.h b/modules/ledger/include/dap_chain_ledger.h index 0f4df48320bf2145bd1fbcbec8a78312a25a00dc..40718d524471fd62b5a80eaa091d5cb803111045 100644 --- a/modules/ledger/include/dap_chain_ledger.h +++ b/modules/ledger/include/dap_chain_ledger.h @@ -454,6 +454,8 @@ dap_list_t* dap_ledger_tx_cache_find_out_cond_all(dap_ledger_t *a_ledger, dap_ch // Get the value from all transactions in the cache with out_cond item uint256_t dap_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_subtype_t a_cond_type, dap_chain_addr_t *a_addr, dap_chain_tx_out_cond_t **tx_out_cond); +// Get first tx with type a_subtype +dap_chain_tx_used_out_item_t *dap_ledger_get_tx_cond_out(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr_from, dap_chain_tx_out_cond_subtype_t a_subtype); dap_list_t *dap_ledger_get_list_tx_outs(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from, uint256_t *a_value_transfer); diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index 2b0c0524848de65ebaee8f4b9db52a0c0644a050..89bb0963226ffacf4d4bff133a59841a5612f69a 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -67,6 +67,7 @@ #include "dap_chain_net_srv_stake_pos_delegate.h" #include "dap_chain_wallet.h" #include "dap_chain_wallet_cache.h" +#include "dap_chain_ledger.h" #include "dap_chain_mempool_rpc.h" @@ -568,6 +569,109 @@ char *dap_chain_mempool_tx_reward_create(dap_chain_cs_blocks_t *a_blocks, dap_en return l_ret; } +// get reward and fees from blocks before hardfork +char *dap_chain_mempool_tx_coll_fee_stack_create(dap_chain_cs_blocks_t *a_blocks, dap_enc_key_t *a_key_from, + const dap_chain_addr_t *a_addr_to, uint256_t a_value_fee, const char *a_hash_out_type) +{ + uint256_t l_value_out = {}; + uint256_t l_net_fee = {}; + dap_chain_datum_tx_t *l_tx; + dap_chain_addr_t l_addr_fee = {}; + + dap_return_val_if_fail(a_blocks && a_key_from && a_addr_to, NULL); + dap_chain_t *l_chain = a_blocks->chain; + bool l_net_fee_used = dap_chain_net_tx_get_fee(l_chain->net_id, &l_net_fee, &l_addr_fee); + dap_ledger_t *l_ledger = dap_chain_net_by_id(l_chain->net_id)->pub.ledger; + dap_pkey_t *l_sign_pkey = dap_pkey_from_enc_key(a_key_from); + dap_chain_tx_used_out_item_t * l_out_fee_stack = dap_ledger_get_tx_cond_out(l_ledger, a_addr_to, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK); + if (!l_out_fee_stack) { + log_it(L_WARNING, "Can't find fee_stack tx out item"); + return NULL; + } + + if (NULL == (l_tx = dap_chain_datum_tx_create())) { + log_it(L_WARNING, "Can't create datum tx"); + return NULL; + } + l_value_out = l_out_fee_stack->value; + + 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 = {}; + // 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 { + log_it(L_WARNING, "Can't create net_fee out item in transaction fee"); + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + // Validator's fee + if (!IS_ZERO_256(a_value_fee)) { + 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); + else { + log_it(L_WARNING, "Can't create valid_fee item in transaction fee"); + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + 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_chain->net_id, &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' items + if(dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from) != 1) { + dap_chain_datum_tx_delete(l_tx); + log_it(L_WARNING, "Can't sign item in transaction fee"); + return NULL; + } + + size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx); + dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, l_tx_size); + DAP_DELETE(l_tx); + char *l_ret = dap_chain_mempool_datum_add(l_datum, l_chain, a_hash_out_type); + DAP_DELETE(l_datum); + return l_ret; + +} + /** * Make transfer transaction & insert to cache * diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h index ce8bcc98482c430801639835980e5cbd109d9e9e..6c7fe2c3e8a03f45c043401233b5d7cf3d5b6291 100644 --- a/modules/mempool/include/dap_chain_mempool.h +++ b/modules/mempool/include/dap_chain_mempool.h @@ -116,3 +116,5 @@ char *dap_chain_mempool_tx_coll_fee_create(dap_chain_cs_blocks_t *a_blocks, dap_ uint256_t a_value_fee, const char *a_hash_out_type); char *dap_chain_mempool_tx_reward_create(dap_chain_cs_blocks_t *a_blocks, dap_enc_key_t *a_sign_key, dap_chain_addr_t *a_addr_to, dap_list_t *a_block_list, uint256_t a_value_fee, const char *a_hash_out_type); +char *dap_chain_mempool_tx_coll_fee_stack_create(dap_chain_cs_blocks_t *a_blocks, dap_enc_key_t *a_key_from, + const dap_chain_addr_t *a_addr_to, uint256_t a_value_fee, const char *a_hash_out_type); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index 937a7abe479f50ca18a944458c9918d5431bdd8f..3993d6e19781e97c03aba64980e26d14cc6e2b0d 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -1931,7 +1931,8 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx) } DAP_DELETE(l_service_cfg_path); } - closedir(l_service_cfg_dir); + if (l_service_cfg_dir) + closedir(l_service_cfg_dir); /* *** Chains init by configs *** */ DIR *l_chains_dir = opendir(a_path); diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c index 5cf639f773fa62edeed7fd1ab2b4ca6ffaa04dd1..9a58181baf6b243e34b78948d923183ab845ce86 100644 --- a/modules/type/blocks/dap_chain_cs_blocks.c +++ b/modules/type/blocks/dap_chain_cs_blocks.c @@ -140,6 +140,7 @@ static dap_chain_datum_t** s_callback_atom_get_datums(dap_chain_atom_ptr_t a_ato static dap_time_t s_chain_callback_atom_get_timestamp(dap_chain_atom_ptr_t a_atom) { return ((dap_chain_block_t *)a_atom)->hdr.ts_created; } static uint256_t s_callback_calc_reward(dap_chain_t *a_chain, dap_hash_fast_t *a_block_hash, dap_pkey_t *a_block_sign_pkey); static int s_fee_verificator_callback(dap_ledger_t * a_ledger, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_in_hash, dap_chain_tx_out_cond_t *a_cond, bool a_owner); +static int s_fee_stack_verificator_callback(dap_ledger_t * a_ledger, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_in_hash, dap_chain_tx_out_cond_t *a_cond, bool a_owner); // Get blocks static dap_chain_atom_ptr_t s_callback_atom_iter_get(dap_chain_atom_iter_t *a_atom_iter, dap_chain_iter_op_t a_operation, size_t *a_atom_size); static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter , size_t *a_links_size, @@ -228,8 +229,9 @@ 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" + " -cert <priv_cert_name> -addr <addr> -hashes <hashes_list> -fee <value> {-before_hardfork}\n" "\t\t Take delegated part of commission\n\n" + "\t\t {-before_hardfork} collect fees from blocks before hardfork\n\n" "Reward for block signs:\n" "block -net <net_name> [-chain <chain_name>] reward set" @@ -240,8 +242,9 @@ int dap_chain_cs_blocks_init() "\t\t Show base reward for sign for one block at one minute\n\n" "block -net <net_name> [-chain <chain_name>] reward collect" - " -cert <priv_cert_name> -addr <addr> -hashes <hashes_list> -fee <value>\n" + " -cert <priv_cert_name> -addr <addr> -hashes <hashes_list> -fee <value> {-before_hardfork}\n" "\t\t Take delegated part of reward\n\n" + "\t\t {-before_hardfork} collect rewards from blocks before hardfork\n\n" "Rewards and fees autocollect status:\n" "block -net <net_name> [-chain <chain_name>] autocollect status\n" @@ -266,6 +269,9 @@ int dap_chain_cs_blocks_init() dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL, NULL, NULL, NULL, NULL); log_it(L_NOTICE ,"Initialized blocks(m) chain type"); + dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK, s_fee_stack_verificator_callback, NULL, NULL, NULL, NULL, NULL); + log_it(L_NOTICE ,"Initialized blocks(m) chain type verificator for fee stack subtype"); + return 0; } @@ -1191,6 +1197,8 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply) dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-addr", &l_addr_str); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hashes", &l_hash_str); dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &l_fee_value_str); + dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-before_hardfork", &l_fee_value_str); + int l_before_hardfork = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-before_hardfork", NULL); if (!l_addr_str) { dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_BLOCK_PARAM_ERR, "Command 'block %s collect' requires parameter '-addr'", l_subcmd_str); @@ -1225,17 +1233,23 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply) dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_BLOCK_PARAM_ERR, "Command 'block fee collect' requires parameter '-hashes'"); return DAP_CHAIN_NODE_CLI_COM_BLOCK_PARAM_ERR; } - // NOTE: This call will modify source string - l_block_list = s_block_parse_str_list((char *)l_hash_str, &l_hashes_count, l_chain); - if (!l_block_list || !l_hashes_count) { - dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_BLOCK_HASH_ERR, - "Block fee collection requires at least one hash to create a transaction"); - return DAP_CHAIN_NODE_CLI_COM_BLOCK_HASH_ERR; - } - char *l_hash_tx = l_subcmd == SUBCMD_FEE - ? dap_chain_mempool_tx_coll_fee_create(l_blocks, l_cert->enc_key, l_addr, l_block_list, l_fee_value, l_hash_out_type) - : dap_chain_mempool_tx_reward_create(l_blocks, l_cert->enc_key, l_addr, l_block_list, l_fee_value, l_hash_out_type); + char *l_hash_tx = NULL; + if (l_before_hardfork == 0) { + // NOTE: This call will modify source string + l_block_list = s_block_parse_str_list((char *)l_hash_str, &l_hashes_count, l_chain); + if (!l_block_list || !l_hashes_count) { + dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_BLOCK_HASH_ERR, + "Block fee collection requires at least one hash to create a transaction"); + return DAP_CHAIN_NODE_CLI_COM_BLOCK_HASH_ERR; + } + char *l_hash_tx = l_subcmd == SUBCMD_FEE + ? dap_chain_mempool_tx_coll_fee_create(l_blocks, l_cert->enc_key, l_addr, l_block_list, l_fee_value, l_hash_out_type) + : dap_chain_mempool_tx_reward_create(l_blocks, l_cert->enc_key, l_addr, l_block_list, l_fee_value, l_hash_out_type); + } else { + char *l_hash_tx = dap_chain_mempool_tx_coll_fee_stack_create(l_blocks, l_cert->enc_key, l_addr, l_fee_value, l_hash_out_type); + } + if (l_hash_tx) { json_object* json_obj_out = json_object_new_object(); char *l_val = dap_strdup_printf("TX for %s collection created successfully, hash = %s\n", l_subcmd_str, l_hash_tx); @@ -2690,7 +2704,7 @@ static uint256_t s_callback_calc_reward(dap_chain_t *a_chain, dap_hash_fast_t *a * @return */ static int s_fee_verificator_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t UNUSED_ARG *a_tx_in_hash, - dap_chain_tx_out_cond_t UNUSED_ARG *a_cond, bool UNUSED_ARG a_owner) + dap_chain_tx_out_cond_t UNUSED_ARG *a_cond, bool a_owner) { dap_chain_net_t *l_net = a_ledger->net; assert(l_net); @@ -2720,6 +2734,15 @@ static int s_fee_verificator_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx return -4; } + +static int s_fee_stack_verificator_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t UNUSED_ARG *a_tx_in_hash, + dap_chain_tx_out_cond_t UNUSED_ARG *a_cond, bool a_owner) +{ + return a_owner ? 0 : -1; +} + + + static uint64_t s_callback_count_txs(dap_chain_t *a_chain) { return PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->tx_count;