diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c index 742f44df087d93246d4508c07dfca9c83758feb9..5007e84720ff8993d91eadfc01c47952ca7dc222 100644 --- a/modules/chain/dap_chain_ledger.c +++ b/modules/chain/dap_chain_ledger.c @@ -271,6 +271,7 @@ typedef struct dap_ledger_private { const char *net_native_ticker; uint256_t fee_value; dap_chain_addr_t fee_addr; + dap_list_t *poa_certs; // List of ledger - unspent transactions cache dap_chain_ledger_tx_item_t *threshold_txs; dap_chain_ledger_token_emission_item_t * threshold_emissions; @@ -2427,12 +2428,13 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger) * @param a_net_name char * network name, for example "kelvin-testnet" * @return dap_ledger_t* */ -dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker) +dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs) { dap_ledger_t *l_ledger = dap_chain_ledger_handle_new(); l_ledger->net_name = a_net_name; dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger); l_ledger_pvt->net_native_ticker = a_net_native_ticker; + l_ledger_pvt->poa_certs = a_poa_certs; l_ledger_pvt->flags = a_flags; l_ledger_pvt->check_ds = a_flags & DAP_CHAIN_LEDGER_CHECK_LOCAL_DS; l_ledger_pvt->check_cells_ds = a_flags & DAP_CHAIN_LEDGER_CHECK_CELLS_DS; @@ -3339,6 +3341,19 @@ bool s_tx_match_sign(dap_chain_datum_token_emission_t *a_datum_emission, dap_cha return false; } +static int s_callback_sign_compare(const void *a, const void *b) +{ + return !dap_pkey_match_sign((dap_pkey_t *)a, (dap_sign_t *)b); +} + +bool dap_chain_ledger_tx_poa_signed(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx) +{ + dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL); + dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig); + return dap_list_find_custom(PVT(a_ledger)->poa_certs, l_sign, s_callback_sign_compare); +} + + /** * Checking a new transaction before adding to the cache * @@ -3993,12 +4008,15 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t // 7. Check the network fee if (l_fee_check && compare256(l_fee_sum, l_ledger_pvt->fee_value) == -1) { - char *l_current_fee = dap_chain_balance_to_coins(l_fee_sum); - char *l_expected_fee = dap_chain_balance_to_coins(l_ledger_pvt->fee_value); - log_it(L_ERROR, "Fee value is invalid, expected %s pointed %s", l_expected_fee, l_current_fee); - l_err_num = -55; - DAP_DEL_Z(l_current_fee); - DAP_DEL_Z(l_expected_fee); + // Check for PoA-cert-signed "service" no-tax tx + if (!dap_chain_ledger_tx_poa_signed(a_ledger, a_tx)) { + char *l_current_fee = dap_chain_balance_to_coins(l_fee_sum); + char *l_expected_fee = dap_chain_balance_to_coins(l_ledger_pvt->fee_value); + log_it(L_ERROR, "Fee value is invalid, expected %s pointed %s", l_expected_fee, l_current_fee); + l_err_num = -55; + DAP_DEL_Z(l_current_fee); + DAP_DEL_Z(l_expected_fee); + } } if (a_main_ticker && !l_err_num) diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h index 14297dfd44595f6dabbea39ea0e0f187a0b955bb..f8005b2ecace918bbf51f3073dcca4dd40c1227b 100644 --- a/modules/chain/include/dap_chain_ledger.h +++ b/modules/chain/include/dap_chain_ledger.h @@ -131,7 +131,7 @@ typedef struct dap_chain_net dap_chain_net_t; int dap_chain_ledger_init(); void dap_chain_ledger_deinit(); -dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker); +dap_ledger_t *dap_chain_ledger_create(uint16_t a_flags, char *a_net_name, const char *a_net_native_ticker, dap_list_t *a_poa_certs); void dap_chain_ledger_set_fee(dap_ledger_t *a_ledger, uint256_t a_fee, dap_chain_addr_t a_fee_addr); @@ -236,6 +236,8 @@ void dap_chain_ledger_addr_get_token_ticker_all_depricated(dap_ledger_t *a_ledge void dap_chain_ledger_addr_get_token_ticker_all(dap_ledger_t *a_ledger, dap_chain_addr_t * a_addr, char *** a_tickers, size_t * a_tickers_size); +bool dap_chain_ledger_tx_poa_signed(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx); + // Checking a new transaction before adding to the cache int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, bool a_from_threshold, dap_list_t **a_list_bound_items, dap_list_t **a_list_tx_out, char **a_main_ticker); diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c index c438ca2e17e297014a600981de0665e688c8fea6..a3478c334bd8c53b9ff603de72679dd5e22763a1 100644 --- a/modules/mempool/dap_chain_mempool.c +++ b/modules/mempool/dap_chain_mempool.c @@ -840,9 +840,10 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast dap_list_t *l_list_used_out; const char *l_native_ticker = dap_chain_net_by_id(a_chain->net_id)->pub.native_ticker; bool not_native = dap_strcmp(a_ticker, l_native_ticker); - bool l_net_fee_used = dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_to_fee); - if(l_net_fee_used) - SUM_256_256(l_total_fee,l_net_fee,&l_total_fee); + bool l_net_fee_used = IS_ZERO_256(a_value_fee) ? false : + dap_chain_net_tx_get_fee(a_chain->net_id, &l_net_fee, &l_addr_to_fee); + if (l_net_fee_used) + SUM_256_256(l_total_fee, l_net_fee, &l_total_fee); dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t)); l_tx->header.ts_created = time(NULL); @@ -855,14 +856,14 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast dap_chain_datum_tx_delete(l_tx); return NULL; } - if (not_native) + if (not_native && !IS_ZERO_256(l_total_fee)) { if (dap_chain_addr_fill_from_key(&l_addr_from_fee, a_private_key, a_chain->net_id) != 0 ) { log_it(L_WARNING,"Can't fill address from transfer"); dap_chain_datum_tx_delete(l_tx); return NULL; } - // list of transaction with 'out' items + // list of transaction with 'out' items l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, l_native_ticker, &l_addr_from_fee, l_total_fee, &l_value_transfer); if (!l_list_used_out) { @@ -878,45 +879,50 @@ char *dap_chain_mempool_base_tx_create(dap_chain_t *a_chain, dap_chain_hash_fast } //add out uint256_t l_value_back = l_value_transfer; // how much datoshi add to 'out' items - // Network fee - if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_to_fee, l_net_fee, l_native_ticker)){ - dap_chain_datum_tx_delete(l_tx); - return NULL; + // Network fee + if (l_net_fee_used) { + SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back); + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_to_fee, l_net_fee, l_native_ticker)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } } - SUBTRACT_256_256(l_value_back, l_net_fee, &l_value_back); - if (!IS_ZERO_256(a_value_fee)) + if (!IS_ZERO_256(a_value_fee)) { SUBTRACT_256_256(l_value_back, a_value_fee, &l_value_back); + if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } // coin back - if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_from_fee, l_value_back, l_native_ticker)){ + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, &l_addr_from_fee, l_value_back, l_native_ticker)) { dap_chain_datum_tx_delete(l_tx); return NULL; } - - if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)){ + if (!dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr_to, l_value_need, a_ticker)) { dap_chain_datum_tx_delete(l_tx); return NULL; } } else { //native ticker - if (!IS_ZERO_256(a_value_fee)) + if (!IS_ZERO_256(a_value_fee)) { SUBTRACT_256_256(l_value_need, a_value_fee, &l_value_need); - if(l_net_fee_used){ + if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){ + dap_chain_datum_tx_delete(l_tx); + return NULL; + } + } + if (l_net_fee_used) { SUBTRACT_256_256(l_value_need, l_net_fee, &l_value_need); - if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_to_fee, l_net_fee)){ + if (!dap_chain_datum_tx_add_out_item(&l_tx, &l_addr_to_fee, l_net_fee)) { dap_chain_datum_tx_delete(l_tx); return NULL; } } - if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)){ + if (!dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_need)) { dap_chain_datum_tx_delete(l_tx); return NULL; } } - if (!IS_ZERO_256(a_value_fee)){ - if (!dap_chain_datum_tx_add_fee_item(&l_tx, a_value_fee)){ - dap_chain_datum_tx_delete(l_tx); - return NULL; - } - } //sign item if(dap_chain_datum_tx_add_sign_item(&l_tx, a_private_key) < 0) { log_it(L_WARNING, "No private key for sign"); diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c index 2b7829a57e0ba2838e5f660a42ce71fd4141bc2d..be375efd104acf6995bfddc02d4e9486b629cfa8 100644 --- a/modules/net/dap_chain_net.c +++ b/modules/net/dap_chain_net.c @@ -2300,8 +2300,18 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx) default: l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_CELLS_DS; } + dap_list_t *l_net_keys = NULL; + for (dap_chain_t *l_chain = l_net->pub.chains; l_chain; l_chain = l_chain->next) { + if (!l_chain->callback_get_poa_certs) + continue; + l_net_keys = l_chain->callback_get_poa_certs(l_chain, NULL, NULL); + if (l_net_keys) + break; + } + if (!l_net_keys) + log_it(L_WARNING,"PoA certificates for net %s not found.", l_net->pub.name); // init LEDGER model - l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.name, l_net->pub.native_ticker); + l_net->pub.ledger = dap_chain_ledger_create(l_ledger_flags, l_net->pub.name, l_net->pub.native_ticker, l_net_keys); // Check if seed nodes are present in local db alias char **l_seed_aliases = dap_config_get_array_str(l_cfg, "general", "seed_nodes_aliases", &l_net_pvt->seed_aliases_count); diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c index b7eabde8dc274e538785639794edc1f723b85291..f03f7a412d539fe2e72838c10bdd90a376c78d50 100644 --- a/modules/net/dap_chain_node.c +++ b/modules/net/dap_chain_node.c @@ -257,19 +257,25 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force) if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX && a_chain->callback_get_minimum_fee){ uint256_t l_tx_fee = {}; - if (dap_chain_datum_tx_get_fee_value ((dap_chain_datum_tx_t*)l_datum->data, &l_tx_fee)) { - log_it(L_WARNING, "Can't get fee value from tx"); - continue; - } - uint256_t l_min_fee = a_chain->callback_get_minimum_fee(a_chain); - if (compare256(l_tx_fee, l_min_fee) < 0) { - char *l_tx_fee_str = dap_chain_balance_to_coins(l_tx_fee); - char *l_min_fee_str = dap_chain_balance_to_coins(l_min_fee); - log_it(L_WARNING, "Fee %s is lower than minimum fee %s for tx %s", - l_tx_fee_str, l_min_fee_str, l_objs[i].key); - DAP_DELETE(l_tx_fee_str); - DAP_DELETE(l_min_fee_str); - continue; + dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data; + if (dap_chain_datum_tx_get_fee_value (l_tx, &l_tx_fee) || + IS_ZERO_256(l_tx_fee)) { + if (!dap_chain_ledger_tx_poa_signed(l_net->pub.ledger, l_tx)) { + log_it(L_WARNING, "Can't get fee value from tx"); + continue; + } else + log_it(L_DEBUG, "Process service tx without fee"); + } else { + uint256_t l_min_fee = a_chain->callback_get_minimum_fee(a_chain); + if (compare256(l_tx_fee, l_min_fee) < 0) { + char *l_tx_fee_str = dap_chain_balance_to_coins(l_tx_fee); + char *l_min_fee_str = dap_chain_balance_to_coins(l_min_fee); + log_it(L_WARNING, "Fee %s is lower than minimum fee %s for tx %s", + l_tx_fee_str, l_min_fee_str, l_objs[i].key); + DAP_DELETE(l_tx_fee_str); + DAP_DELETE(l_min_fee_str); + continue; + } } } diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c index 93cd92c2fc65bd5b9dfe2be9553d786b64c571cf..cb47e1ee7d91f14b0ce2dcc39a942a4e30c5e7e6 100644 --- a/modules/net/dap_chain_node_cli_cmd.c +++ b/modules/net/dap_chain_node_cli_cmd.c @@ -5221,9 +5221,9 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) } // Validator's fee - if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &str_tmp)) + if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-fee", &str_tmp)) l_value_fee = dap_chain_balance_scan(str_tmp); - if (IS_ZERO_256(l_value_fee)) { + if (IS_ZERO_256(l_value_fee) && (!l_emission_hash_str || (str_tmp && strcmp(str_tmp, "0")))) { dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-fee' to be valid uint256"); return -5; @@ -5280,38 +5280,24 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) return -9; } - const char *l_native_ticker = l_net->pub.native_ticker; - bool not_native = dap_strcmp(l_token_ticker, l_native_ticker); - - if (not_native) { - if (l_wallet_fee_name){ - l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path); - if (!l_wallet_fee) { - dap_cli_server_cmd_set_reply_text(a_str_reply, "wallet %s does not exist", l_wallet_fee_name); - return -12; - } - l_priv_key = dap_chain_wallet_get_key(l_wallet_fee, 0); - } else { - dap_cli_server_cmd_set_reply_text(a_str_reply, "To create a basic transaction with a " - "non-native ticker, you must specify the '-wallet_fee' " - "parameter. It is required to pay a commission for the " - "transaction."); - return -11; + if (l_wallet_fee_name){ + l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path); + if (!l_wallet_fee) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Wallet %s does not exist", l_wallet_fee_name); + return -12; } - } else { - if (l_cert_str) { - l_cert = dap_cert_find_by_name(l_cert_str); - if (!l_cert) { - dap_cli_server_cmd_set_reply_text(a_str_reply, - "tx_create requires one valid certificate to sign the basic transaction of emission"); - return -5; - } - l_priv_key = l_cert->enc_key; - } else { - dap_cli_server_cmd_set_reply_text(a_str_reply, - "tx_create requires parameter '-cert' for create base tx for emission in native token"); - return -10; + l_priv_key = dap_chain_wallet_get_key(l_wallet_fee, 0); + } else if (l_cert_str) { + l_cert = dap_cert_find_by_name(l_cert_str); + if (!l_cert) { + dap_cli_server_cmd_set_reply_text(a_str_reply, "Certificate %s is invalid", l_cert_str); + return -5; } + l_priv_key = l_cert->enc_key; + } else { + dap_cli_server_cmd_set_reply_text(a_str_reply, + "tx_create requires parameter '-cert' or '-wallet' for create base tx for emission"); + return -10; } } @@ -5337,7 +5323,6 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) dap_string_t *l_string_ret = dap_string_new(NULL); int res = 0; if (l_emission_hash_str) { - bool not_native = dap_strcmp(l_token_ticker, l_net->pub.native_ticker); char *l_tx_hash_str = NULL; if (!l_priv_key) { dap_string_append_printf(l_string_ret, "No private key defined for creating the underlying " @@ -5346,7 +5331,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply) } l_tx_hash_str = dap_chain_mempool_base_tx_create(l_chain, &l_emission_hash, l_emission_chain->id, l_value, l_token_ticker, l_addr_to, l_priv_key, - l_hash_out_type,l_value_fee); + l_hash_out_type, l_value_fee); if (l_tx_hash_str) { dap_string_append_printf(l_string_ret, "\nDatum %s with 256bit TX is placed in datum pool\n", l_tx_hash_str); DAP_DELETE(l_tx_hash_str);