diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 4887c7ca..2d098e32 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -376,7 +376,7 @@ namespace epee bool run_default_console_handler_no_srv_param(t_server* ptsrv, t_handler handlr, const std::string& prompt, const std::string& usage = "") { async_console_handler console_handler; - return console_handler.run(ptsrv, boost::bind(no_srv_param_adapter, _1, _2, handlr), prompt, usage); + return console_handler.run(ptsrv, boost::bind(no_srv_param_adapter, boost::placeholders::_1, boost::placeholders::_2, handlr), prompt, usage); } template @@ -460,7 +460,7 @@ namespace epee /*template bool start_handling(t_srv& srv, const std::string& usage_string = "") { - start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1)); + start_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, boost::placeholders::_1)); return true; }*/ @@ -489,7 +489,7 @@ namespace epee /*template bool run_handling(t_srv& srv, const std::string& usage_string) { - return run_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, _1), usage_string); + return run_default_console_handler_no_srv_param(&srv, boost::bind(&console_handlers_binder::process_command_str, this, boost::placeholders::_1), usage_string); }*/ }; @@ -510,7 +510,7 @@ namespace epee bool run_handling(t_server* psrv, const std::string& prompt, const std::string& usage_string) { - return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder::process_command_str, this, _1, _2), prompt, usage_string); + return m_console_handler.run(psrv, boost::bind(&srv_console_handlers_binder::process_command_str, this, boost::placeholders::_1, boost::placeholders::_2), prompt, usage_string); } void stop_handling() diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index a4e67f4c..95a5d88e 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -284,12 +284,19 @@ POP_GCC_WARNINGS typedef std::map command_line_params_w; template - void apped_pod_to_strbuff(std::string& buff, const t_pod_data& pod) + void append_pod_to_strbuff(std::string& buff, const t_pod_data& pod) { buff.append(reinterpret_cast(&pod), sizeof(pod)); } - + template + bool get_pod_from_strbuff(const std::string& buff, pod_t& output) + { + if (buff.size() != sizeof(pod_t)) + return false; + output = *reinterpret_cast(buff.data()); + return true; + } template bool parse_commandline(std::map& res, int argc, char** argv) diff --git a/contrib/epee/include/time_helper.h b/contrib/epee/include/time_helper.h index f11dae91..40811420 100644 --- a/contrib/epee/include/time_helper.h +++ b/contrib/epee/include/time_helper.h @@ -87,7 +87,7 @@ DISABLE_VS_WARNINGS(4996) POP_VS_WARNINGS if(pt) - strftime( tmpbuf, 199, "%Y_%m_%d %H_%M_%S", pt ); + strftime( tmpbuf, 199, "%Y-%m-%d %H-%M-%S", pt ); else { std::stringstream strs; diff --git a/src/common/command_line.h b/src/common/command_line.h index f19a04ae..ee7985cc 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -151,7 +151,7 @@ namespace command_line } template - bool handle_error_helper(const boost::program_options::options_description& desc, F parser) + bool handle_error_helper(const boost::program_options::options_description& desc, std::string& err, F parser) { try { @@ -159,6 +159,7 @@ namespace command_line } catch (std::exception& e) { + err = e.what(); std::cerr << "Failed to parse arguments: " << e.what() << std::endl; std::cerr << desc << std::endl; return false; @@ -171,6 +172,13 @@ namespace command_line } } + template + bool handle_error_helper(const boost::program_options::options_description& desc, F parser) + { + std::string stub_err; + return handle_error_helper(desc, stub_err, parser); + } + template bool has_arg(const boost::program_options::variables_map& vm, const arg_descriptor& arg) { diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 97d9480e..def20255 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -70,8 +70,7 @@ namespace currency iv = *((crypto::chacha8_iv*)&pass_hash); crypto::chacha8(scr_data, src_length, key, iv, (char*)dst_data); } - - + //----------------------------------------------------------------- std::string account_base::get_seed_phrase(const std::string& password) const { if (m_keys_seed_binary.empty()) diff --git a/src/currency_core/bc_block_datetime_service.h b/src/currency_core/bc_block_datetime_service.h new file mode 100644 index 00000000..4db3d743 --- /dev/null +++ b/src/currency_core/bc_block_datetime_service.h @@ -0,0 +1,7 @@ +// Copyright (c) 2014-2021 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once + +#define BC_BLOCK_DATETIME_SERVICE_ID "d" +#define BC_BLOCK_DATETIME_INSTRUCTION_DEFAULT "" diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index b2bae2b9..54813472 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -2114,7 +2114,7 @@ bool blockchain_storage::get_tx_rpc_details(const crypto::hash& h, tx_rpc_extend if (tx_ptr && !timestamp) { - timestamp = get_actual_timestamp(m_db_blocks[tx_ptr->m_keeper_block_height]->bl); + timestamp = get_block_datetime(m_db_blocks[tx_ptr->m_keeper_block_height]->bl); } tei.keeper_block = static_cast(tx_ptr->m_keeper_block_height); fill_tx_rpc_details(tei, tx_ptr->tx, &(*tx_ptr), h, timestamp, is_short); @@ -2203,11 +2203,11 @@ bool blockchain_storage::get_main_block_rpc_details(uint64_t i, block_rpc_extend crypto::hash coinbase_id = get_transaction_hash(core_bei_ptr->bl.miner_tx); //load transactions details bei.transactions_details.push_back(tx_rpc_extended_info()); - get_tx_rpc_details(coinbase_id, bei.transactions_details.back(), get_actual_timestamp(core_bei_ptr->bl), true); + get_tx_rpc_details(coinbase_id, bei.transactions_details.back(), get_block_datetime(core_bei_ptr->bl), true); for (auto& h : core_bei_ptr->bl.tx_hashes) { bei.transactions_details.push_back(tx_rpc_extended_info()); - get_tx_rpc_details(h, bei.transactions_details.back(), get_actual_timestamp(core_bei_ptr->bl), true); + get_tx_rpc_details(h, bei.transactions_details.back(), get_block_datetime(core_bei_ptr->bl), true); bei.total_fee += bei.transactions_details.back().fee; bei.total_txs_size += bei.transactions_details.back().blob_size; } @@ -2288,13 +2288,13 @@ bool blockchain_storage::get_alt_block_rpc_details(const block_extended_info& be crypto::hash coinbase_id = get_transaction_hash(bei_core.bl.miner_tx); //load transactions details bei.transactions_details.push_back(tx_rpc_extended_info()); - fill_tx_rpc_details(bei.transactions_details.back(), bei_core.bl.miner_tx, nullptr, coinbase_id, get_actual_timestamp(bei_core.bl)); + fill_tx_rpc_details(bei.transactions_details.back(), bei_core.bl.miner_tx, nullptr, coinbase_id, get_block_datetime(bei_core.bl)); bei.total_fee = 0; for (auto& h : bei_core.bl.tx_hashes) { bei.transactions_details.push_back(tx_rpc_extended_info()); - if (!get_tx_rpc_details(h, bei.transactions_details.back(), get_actual_timestamp(bei_core.bl), true)) + if (!get_tx_rpc_details(h, bei.transactions_details.back(), get_block_datetime(bei_core.bl), true)) { //tx not in blockchain, supposed to be in tx pool m_tx_pool.get_transaction_details(h, bei.transactions_details.back()); @@ -2407,8 +2407,8 @@ uint64_t blockchain_storage::get_seconds_between_last_n_block(size_t n) const if (m_db_blocks.size() <= n) return 0; - uint64_t top_block_ts = get_actual_timestamp(m_db_blocks[m_db_blocks.size() - 1]->bl); - uint64_t n_block_ts = get_actual_timestamp(m_db_blocks[m_db_blocks.size() - 1 - n]->bl); + uint64_t top_block_ts = get_block_datetime(m_db_blocks[m_db_blocks.size() - 1]->bl); + uint64_t n_block_ts = get_block_datetime(m_db_blocks[m_db_blocks.size() - 1 - n]->bl); return top_block_ts > n_block_ts ? top_block_ts - n_block_ts : 0; } @@ -4905,7 +4905,7 @@ void blockchain_storage::get_pos_mining_estimate(uint64_t amount_coins, auto bei = m_db_blocks[h]; if (!is_pos_block(bei->bl)) continue; - uint64_t ts = get_actual_timestamp(bei->bl); + uint64_t ts = get_block_datetime(bei->bl); pos_ts_min = min(pos_ts_min, ts); pos_ts_max = max(pos_ts_max, ts); pos_total_minted_money += get_reward_from_miner_tx(bei->bl.miner_tx); @@ -5060,7 +5060,8 @@ bool blockchain_storage::validate_pos_block(const block& b, } - //check actual time if it there + // the following check is de-facto not applicable since 2021-10, but left intact to avoid consensus issues + // PoS blocks don't use etc_tx_time anymore to store actual timestamp; instead, they use tx_service_attachment in mining tx extra uint64_t actual_ts = get_actual_timestamp(b); if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) || (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) @@ -5379,7 +5380,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt block_fees.reserve(bl.tx_hashes.size()); //process transactions TIME_MEASURE_START_PD(all_txs_insert_time_5); - if (!add_transaction_from_block(bl.miner_tx, get_transaction_hash(bl.miner_tx), id, get_current_blockchain_size(), get_actual_timestamp(bl))) + if (!add_transaction_from_block(bl.miner_tx, get_transaction_hash(bl.miner_tx), id, get_current_blockchain_size(), get_block_datetime(bl))) { LOG_PRINT_L0("Block with id: " << id << " failed to add transaction to blockchain storage"); bvc.m_verification_failed = true; @@ -5454,7 +5455,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt TIME_MEASURE_START_PD(tx_prapare_append); uint64_t current_bc_size = get_current_blockchain_size(); - uint64_t actual_timestamp = get_actual_timestamp(bl); + uint64_t actual_timestamp = get_block_datetime(bl); TIME_MEASURE_FINISH_PD(tx_prapare_append); TIME_MEASURE_START_PD(tx_append_time); if(!add_transaction_from_block(tx, tx_id, id, current_bc_size, actual_timestamp)) @@ -5622,7 +5623,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt stringstream powpos_str_entry, timestamp_str_entry; if (is_pos_bl) { // PoS - int64_t actual_ts = get_actual_timestamp(bei.bl); // signed int is intentionally used here + int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here int64_t ts_diff = actual_ts - m_core_runtime_config.get_core_time(); powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: " << print_money_brief(pos_coinstake_amount) << ", final_difficulty: " << this_coin_diff; timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast(bei.bl.timestamp) - actual_ts << ")"; diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index d78ec011..7019ce41 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -26,6 +26,7 @@ using namespace epee; #include "bc_payments_id_service.h" #include "bc_escrow_service.h" #include "bc_attachments_helpers.h" +#include "bc_block_datetime_service.h" #include "genesis.h" #include "genesis_acc.h" #include "common/mnemonic-encoding.h" @@ -64,11 +65,6 @@ namespace currency pos_entry()); }*/ //--------------------------------------------------------------- - uint64_t get_coinday_weight(uint64_t amount) - { - return amount; - } - //--------------------------------------------------------------- wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff) { //delta=delta*(0.75^n) @@ -594,12 +590,12 @@ namespace currency std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys) { std::string blob; - string_tools::apped_pod_to_strbuff(blob, htlc.pkey_redeem); - string_tools::apped_pod_to_strbuff(blob, htlc.pkey_refund); - string_tools::apped_pod_to_strbuff(blob, acc_keys.spend_secret_key); + string_tools::append_pod_to_strbuff(blob, htlc.pkey_redeem); + string_tools::append_pod_to_strbuff(blob, htlc.pkey_refund); + string_tools::append_pod_to_strbuff(blob, acc_keys.spend_secret_key); crypto::hash origin_hs = crypto::cn_fast_hash(blob.data(), blob.size()); std::string origin_blob; - string_tools::apped_pod_to_strbuff(origin_blob, origin_hs); + string_tools::append_pod_to_strbuff(origin_blob, origin_hs); return origin_blob; } //--------------------------------------------------------------- @@ -819,7 +815,7 @@ namespace currency //take hash from derivation and use it as a salt crypto::hash derivation_hash = crypto::cn_fast_hash(&derivation_local, sizeof(derivation_local)); std::string salted_body = original_body; - string_tools::apped_pod_to_strbuff(salted_body, derivation_hash); + string_tools::append_pod_to_strbuff(salted_body, derivation_hash); crypto::hash proof_hash = crypto::cn_fast_hash(salted_body.data(), salted_body.size()); sa.security.push_back(*(crypto::public_key*)&proof_hash); } @@ -890,8 +886,8 @@ namespace currency //take hash from derivation and use it as a salt crypto::hash derivation_hash = crypto::cn_fast_hash(&derivation_local, sizeof(derivation_local)); std::string salted_body = local_sa.body; - string_tools::apped_pod_to_strbuff(salted_body, derivation_hash); - crypto::hash proof_hash = crypto::cn_fast_hash(salted_body.data(), salted_body.size()); + string_tools::append_pod_to_strbuff(salted_body, derivation_hash); + crypto::hash proof_hash = crypto::cn_fast_hash(salted_body.data(), salted_body.size()); // proof_hash = Hs(local_sa.body || Hs(s * R)), s - spend secret, R - tx pub CHECK_AND_ASSERT_MES(*(crypto::public_key*)&proof_hash == sa.security.front(), void(), "Proof hash missmatch on decrypting with TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF"); } @@ -2062,8 +2058,8 @@ namespace currency crypto::hash hash_together(const pod_operand_a& a, const pod_operand_b& b) { std::string blob; - string_tools::apped_pod_to_strbuff(blob, a); - string_tools::apped_pod_to_strbuff(blob, b); + string_tools::append_pod_to_strbuff(blob, a); + string_tools::append_pod_to_strbuff(blob, b); return crypto::cn_fast_hash(blob.data(), blob.size()); } //------------------------------------------------------------------ @@ -2113,6 +2109,8 @@ namespace currency return median_fee * 10; } //--------------------------------------------------------------- + // NOTE: this function is obsolete and depricated + // PoS block real timestamp is set using a service attachment in mining tx extra since 2021-10 uint64_t get_actual_timestamp(const block& b) { uint64_t tes_ts = b.timestamp; @@ -2124,6 +2122,41 @@ namespace currency } return tes_ts; } + //--------------------------------------------------------------- + // returns timestamp from BC_BLOCK_DATETIME_SERVICE_ID via tx_service_attachment in extra + // fallbacks to old-style actual timestamp via etc_tx_time, then to block timestamp + uint64_t get_block_datetime(const block& b) + { + // first try BC_BLOCK_DATETIME_SERVICE_ID + tx_service_attachment sa = AUTO_VAL_INIT(sa); + if (get_type_in_variant_container(b.miner_tx.extra, sa)) + { + if (sa.service_id == BC_BLOCK_DATETIME_SERVICE_ID && sa.instruction == BC_BLOCK_DATETIME_INSTRUCTION_DEFAULT) + { + uint64_t ts; + if (epee::string_tools::get_pod_from_strbuff(sa.body, ts)) + return ts; + } + } + + // next try etc_tx_time + etc_tx_time t = AUTO_VAL_INIT(t); + if (get_type_in_variant_container(b.miner_tx.extra, t)) + return t.v; + + // otherwise return default: block.ts + return b.timestamp; + } + //--------------------------------------------------------------- + void set_block_datetime(uint64_t datetime, block& b) + { + tx_service_attachment sa = AUTO_VAL_INIT(sa); + sa.service_id = BC_BLOCK_DATETIME_SERVICE_ID; + sa.instruction = BC_BLOCK_DATETIME_INSTRUCTION_DEFAULT; + sa.flags = 0; + epee::string_tools::append_pod_to_strbuff(sa.body, datetime); + b.miner_tx.extra.push_back(sa); + } //------------------------------------------------------------------ bool validate_alias_name(const std::string& al) { @@ -2782,7 +2815,7 @@ namespace currency pei_rpc.timestamp = bei_chain.bl.timestamp; pei_rpc.id = epee::string_tools::pod_to_hex(h); pei_rpc.prev_id = epee::string_tools::pod_to_hex(bei_chain.bl.prev_id); - pei_rpc.actual_timestamp = get_actual_timestamp(bei_chain.bl); + pei_rpc.actual_timestamp = get_block_datetime(bei_chain.bl); pei_rpc.type = is_pos_block(bei_chain.bl) ? 0 : 1; pei_rpc.already_generated_coins = boost::lexical_cast(bei_chain.already_generated_coins); pei_rpc.this_block_fee_median = bei_chain.this_block_tx_fee_median; diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 9a108417..725b39e1 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -329,8 +329,10 @@ namespace currency // prints amount in format "3.14", "0.0" std::string print_money_brief(uint64_t amount); - uint64_t get_actual_timestamp(const block& b); - + uint64_t get_actual_timestamp(const block& b); // obsolete and depricated, use get_block_datetime + uint64_t get_block_datetime(const block& b); + void set_block_datetime(uint64_t datetime, block& b); + bool addendum_to_hexstr(const std::vector& add, std::string& hex_buff); bool hexstr_to_addendum(const std::string& hex_buff, std::vector& add); bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id); @@ -346,7 +348,6 @@ namespace currency //PoS bool is_pos_block(const block& b); bool is_pos_block(const transaction& tx); - uint64_t get_coinday_weight(uint64_t amount); wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff); void print_currency_details(); std::string print_reward_change_first_blocks(size_t n_of_first_blocks); diff --git a/src/currency_core/offers_services_helpers.h b/src/currency_core/offers_services_helpers.h index fc2203fb..1484622c 100644 --- a/src/currency_core/offers_services_helpers.h +++ b/src/currency_core/offers_services_helpers.h @@ -97,8 +97,8 @@ namespace bc_services inline currency::blobdata make_offer_sig_blob(const update_offer& uo) { currency::blobdata bd; - epee::string_tools::apped_pod_to_strbuff(bd, uo.tx_id); - epee::string_tools::apped_pod_to_strbuff(bd, uo.offer_index); + epee::string_tools::append_pod_to_strbuff(bd, uo.tx_id); + epee::string_tools::append_pod_to_strbuff(bd, uo.offer_index); bd += epee::serialization::store_t_to_binary(uo.of); return bd; } @@ -106,8 +106,8 @@ namespace bc_services inline currency::blobdata make_offer_sig_blob(const cancel_offer& co) { currency::blobdata bd; - epee::string_tools::apped_pod_to_strbuff(bd, co.tx_id); - epee::string_tools::apped_pod_to_strbuff(bd, co.offer_index); + epee::string_tools::append_pod_to_strbuff(bd, co.tx_id); + epee::string_tools::append_pod_to_strbuff(bd, co.offer_index); return bd; } diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 65993062..39e42a3c 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -914,7 +914,8 @@ namespace currency LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_CHAIN_ENTRY, with \r\nm_total_height=" << arg.total_height << "\r\nm_start_height=" << arg.start_height << "\r\nm_block_ids.size()=" << arg.m_block_ids.size()); - //m_p2p->drop_connection(context); + m_p2p->drop_connection(context); + m_p2p->add_ip_fail(context.m_remote_ip); } BOOST_FOREACH(auto& bl_details, arg.m_block_ids) diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index dee2a49d..4573b806 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -330,7 +330,7 @@ private: currency::block_extended_info bei = AUTO_VAL_INIT(bei); CHECK_AND_ASSERT_MES(bcs.get_block_extended_info_by_height(tx_chain_entry->m_keeper_block_height, bei), false, "cannot find block by height " << tx_chain_entry->m_keeper_block_height); - LOG_PRINT_L0("Key image found in tx: " << tx_id << " height " << tx_chain_entry->m_keeper_block_height << " (ts: " << epee::misc_utils::get_time_str_v2(currency::get_actual_timestamp(bei.bl)) << ")" << ENDL + LOG_PRINT_L0("Key image found in tx: " << tx_id << " height " << tx_chain_entry->m_keeper_block_height << " (ts: " << epee::misc_utils::get_time_str_v2(currency::get_block_datetime(bei.bl)) << ")" << ENDL << obj_to_json_str(tx_chain_entry->tx)); } else diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index d8ffd569..4313ca65 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -643,6 +643,7 @@ bool MainWindow::show_inital() restore_pos(true); else { + m_config = AUTO_VAL_INIT(m_config); this->show(); QSize sz; sz.setHeight(770); @@ -651,6 +652,7 @@ bool MainWindow::show_inital() store_window_pos(); m_config.is_maximazed = false; m_config.is_showed = true; + m_config.disable_notifications = false; } return true; CATCH_ENTRY2(false); @@ -727,14 +729,26 @@ void qt_log_message_handler(QtMsgType type, const QMessageLogContext &context, c bool MainWindow::init_backend(int argc, char* argv[]) { TRY_ENTRY(); - if (!m_backend.init_command_line(argc, argv)) + std::string command_line_fail_details; + if (!m_backend.init_command_line(argc, argv, command_line_fail_details)) + { + this->show_msg_box(command_line_fail_details); return false; + } if (!init_window()) + { + this->show_msg_box("Failed to main screen launch, check logs for the more detais."); return false; + } if (!m_backend.init(this)) + { + this->show_msg_box("Failed to initialize backend, check debug logs for more details."); return false; + } + + if (m_backend.is_qt_logs_enabled()) { @@ -811,8 +825,25 @@ bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, l CATCH_ENTRY2(false); } - - +bool MainWindow::get_is_disabled_notifications() +{ + return m_config.disable_notifications; +} +bool MainWindow::set_is_disabled_notifications(const bool& param) +{ + m_config.disable_notifications = param; + return m_config.disable_notifications; +} +QString MainWindow::export_wallet_history(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::export_wallet_info, ewi); + PREPARE_RESPONSE(view::api_response, ar); + ar.error_code = m_backend.export_wallet_history(ewi); + return MAKE_RESPONSE(ar); + CATCH_ENTRY2(false); +} bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi) { TRY_ENTRY(); @@ -834,6 +865,10 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer]" << std::endl << json_str); //this->money_transfer(json_str.c_str()); QMetaObject::invokeMethod(this, "money_transfer", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); + if (m_config.disable_notifications) + return true; + + if (!m_tray_icon) return true; if (!tei.ti.is_income) @@ -852,7 +887,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) return true; } - auto amount_str = currency::print_money(tei.ti.amount); + auto amount_str = currency::print_money_brief(tei.ti.amount); std::string title, msg; if (tei.ti.height == 0) // unconfirmed trx { @@ -869,6 +904,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) else if (tei.ti.unlock_time) msg += m_localization[localization_id_locked]; + show_notification(title, msg); return true; diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index ba9216fc..3c67b509 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -64,6 +64,7 @@ public: std::pair m_window_size; bool is_maximazed; bool is_showed; + bool disable_notifications; }; protected slots: @@ -150,6 +151,10 @@ public: QString get_default_fee(); QString get_options(); void bool_toggle_icon(const QString& param); + + bool get_is_disabled_notifications(); + bool set_is_disabled_notifications(const bool& param); + QString export_wallet_history(const QString& param); QString get_log_file(); QString check_available_sources(const QString& param); QString open_url_in_browser(const QString& param); @@ -176,6 +181,7 @@ signals: void do_dispatch(const QString status, const QString params); //general function void on_core_event(const QString method_name); //general function void set_options(const QString str); //general function + void get_wallet_name(); private: //-------------------- i_core_event_handler -------------------- @@ -254,7 +260,7 @@ private: enum localization_string_indices { - // order is surprizingly important here! (see also updateLocalisation in AppController.js) + // order is surprisingly important here! (see also updateLocalisation in AppController.js) localization_id_quit = 0, localization_id_is_received, localization_id_is_confirmed, diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index fd506b56..b028252d 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit fd506b5669624c8deeab901347228c400d9dc89d +Subproject commit b028252d30a32e80c12fa890c306d3c5842e937a diff --git a/src/gui/qt-daemon/main.cpp b/src/gui/qt-daemon/main.cpp index cfa89717..bd1dd934 100644 --- a/src/gui/qt-daemon/main.cpp +++ b/src/gui/qt-daemon/main.cpp @@ -64,9 +64,9 @@ int main(int argc, char *argv[]) MainWindow viewer; if (!viewer.init_backend(argc, argv)) { - static_cast(&viewer)->show_msg_box("Failed to initialize backend, check debug logs for more details."); return 1; } + app.installNativeEventFilter(&viewer); viewer.setWindowTitle(CURRENCY_NAME_BASE); viewer.show_inital(); diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 301b4cda..5c0fb12e 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -81,7 +81,8 @@ namespace nodetool m_last_stat_request_time{}, m_use_only_priority_peers(false), m_peer_livetime{}, - m_debug_requests_enabled(false) + m_debug_requests_enabled(false), + m_ip_auto_blocking_enabled(false) {} static void init_options(boost::program_options::options_description& desc); @@ -215,6 +216,8 @@ namespace nodetool bool urgent_alert_worker(); bool critical_alert_worker(); bool remove_dead_connections(); + bool is_ip_good_for_adding_to_peerlist(uint32_t adress); + bool is_ip_in_blacklist(uint32_t adress); //debug functions @@ -245,6 +248,7 @@ namespace nodetool bool m_hide_my_port; bool m_offline_mode; bool m_debug_requests_enabled; + bool m_ip_auto_blocking_enabled; uint64_t m_startup_time; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 5042548d..477d7e8b 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -26,18 +26,19 @@ namespace nodetool namespace { - const command_line::arg_descriptor arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"}; - const command_line::arg_descriptor arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)}; - const command_line::arg_descriptor arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0}; - const command_line::arg_descriptor arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"}; - const command_line::arg_descriptor > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"}; - const command_line::arg_descriptor > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"}; + const command_line::arg_descriptor arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"}; + const command_line::arg_descriptor arg_p2p_bind_port = {"p2p-bind-port", "Port for p2p network protocol", boost::to_string(P2P_DEFAULT_PORT)}; + const command_line::arg_descriptor arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0}; + const command_line::arg_descriptor arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"}; + const command_line::arg_descriptor > arg_p2p_add_peer = {"add-peer", "Manually add peer to local peerlist"}; + const command_line::arg_descriptor > arg_p2p_add_priority_node = {"add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"}; const command_line::arg_descriptor arg_p2p_use_only_priority_nodes = {"use-only-priority-nodes", "Try to connect only to priority nodes"}; - const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; - const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; - const command_line::arg_descriptor arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true }; - const command_line::arg_descriptor arg_p2p_disable_debug_reqs = { "disable-debug-p2p-requests", "Disable p2p debug requests", false, true }; -} + const command_line::arg_descriptor > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; + const command_line::arg_descriptor arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; + const command_line::arg_descriptor arg_p2p_offline_mode = { "offline-mode", "Don't connect to any node and reject any connections", false, true }; + const command_line::arg_descriptor arg_p2p_disable_debug_reqs = { "disable-debug-p2p-requests", "Disable p2p debug requests", false, true }; + const command_line::arg_descriptor arg_p2p_ip_auto_blocking = { "p2p-ip-auto-blocking", "Enable (1) or disable (0) peers auto-blocking by IP <0|1>. Default: 0", 0, false }; + } //----------------------------------------------------------------------------------- template @@ -53,7 +54,8 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_hide_my_port); command_line::add_arg(desc, arg_p2p_offline_mode); command_line::add_arg(desc, arg_p2p_disable_debug_reqs); - command_line::add_arg(desc, arg_p2p_use_only_priority_nodes); + command_line::add_arg(desc, arg_p2p_use_only_priority_nodes); + command_line::add_arg(desc, arg_p2p_ip_auto_blocking); } //----------------------------------------------------------------------------------- template @@ -65,7 +67,14 @@ namespace nodetool CHECK_AND_ASSERT_MES(r, false, "Failed to parse P2P_MAINTAINERS_PUB_KEY = " << P2P_MAINTAINERS_PUB_KEY); std::string state_file_path = m_config_folder + "/" + P2P_NET_DATA_FILENAME; - tools::unserialize_obj_from_file(*this, state_file_path); + boost::system::error_code ec = AUTO_VAL_INIT(ec); + std::time_t last_update_time = boost::filesystem::last_write_time(state_file_path, ec); + //let's assume that if p2p peer list file stored more then 2 weeks ago, + //then it outdated and we need to fetch peerlist from seed nodes + if (!ec && time(nullptr) - last_update_time < 86400 * 14) + { + tools::unserialize_obj_from_file(*this, state_file_path); + } //always use new id, to be able differ cloned computers m_config.m_peer_id = crypto::rand(); @@ -100,21 +109,39 @@ namespace nodetool if (m_offline_mode) return false; - //@#@ temporary workaround - return true; -#if 0 + if (!m_ip_auto_blocking_enabled) + return true; + + return !is_ip_in_blacklist(addr); + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_ip_good_for_adding_to_peerlist(uint32_t addr) + { + if (m_offline_mode) + return false; + + // even if IP auto blocking is disabled, bad peers should not be added to peerlists and be shared with other nodes + + return !is_ip_in_blacklist(addr); + } + //----------------------------------------------------------------------------------- + template + bool node_server::is_ip_in_blacklist(uint32_t addr) + { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); auto it = m_blocked_ips.find(addr); - if(it == m_blocked_ips.end()) - return true; - if(time(nullptr) - it->second > P2P_IP_BLOCKTIME ) + if (it == m_blocked_ips.end()) + return false; + + if (time(nullptr) - it->second > P2P_IP_BLOCKTIME) { m_blocked_ips.erase(it); - LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << "is unblocked.", LOG_LEVEL_0); - return true; + LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(addr) << " is unblocked due to blocking expiration.", LOG_LEVEL_0); + return false; } - return false; -#endif + + return true; } //----------------------------------------------------------------------------------- template @@ -122,7 +149,8 @@ namespace nodetool { CRITICAL_REGION_LOCAL(m_blocked_ips_lock); m_blocked_ips[addr] = time(nullptr); - LOG_PRINT_CYAN("Ip " << string_tools::get_ip_string_from_int32(addr) << " blocked.", LOG_LEVEL_0); + m_peerlist.remove_peers_by_ip_from_all(addr); + LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(addr) << " blocked and removed from peerlist", LOG_LEVEL_0); return true; } //----------------------------------------------------------------------------------- @@ -138,6 +166,10 @@ namespace nodetool it->second = P2P_IP_FAILS_BEFOR_BLOCK/2; block_ip(address); } + else + { + LOG_PRINT_CYAN("IP " << string_tools::get_ip_string_from_int32(address) << ": fail recorded, total fails count: " << fails, LOG_LEVEL_2); + } return true; } //----------------------------------------------------------------------------------- @@ -162,6 +194,9 @@ namespace nodetool m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip); m_offline_mode = command_line::get_arg(vm, arg_p2p_offline_mode); m_debug_requests_enabled = !command_line::get_arg(vm, arg_p2p_disable_debug_reqs); + m_ip_auto_blocking_enabled = (command_line::get_arg(vm, arg_p2p_ip_auto_blocking) != 0); + + LOG_PRINT_L0("p2p peers auto-blocking is " << (m_ip_auto_blocking_enabled ? "enabled" : "disabled")); if (m_offline_mode) { @@ -679,7 +714,6 @@ namespace nodetool << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port) /*<< ", try " << try_count*/); - //m_peerlist.set_peer_unreachable(pe); return false; } peerid_type pi = AUTO_VAL_INIT(pi); @@ -701,12 +735,15 @@ namespace nodetool return true; } - peerlist_entry pe_local = AUTO_VAL_INIT(pe_local); - pe_local.adr = na; - pe_local.id = pi; - time(&pe_local.last_seen); - m_peerlist.append_with_peer_white(pe_local); - //update last seen and push it to peerlist manager + if (is_ip_good_for_adding_to_peerlist(na.ip)) // additional check to avoid IP shown up in peers in the case of non-blocking incoming connections + { + //update last seen and push it to peerlist manager + peerlist_entry pe_local = AUTO_VAL_INIT(pe_local); + pe_local.adr = na; + pe_local.id = pi; + time(&pe_local.last_seen); + m_peerlist.append_with_peer_white(pe_local); + } LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK with peer " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port), LOG_LEVEL_2); return true; @@ -1373,7 +1410,8 @@ namespace nodetool //associate peer_id with this connection context.peer_id = arg.node_data.peer_id; - if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port) + if(arg.node_data.peer_id != m_config.m_peer_id && arg.node_data.my_port + && is_ip_good_for_adding_to_peerlist(context.m_remote_ip)) { peerid_type peer_id_l = arg.node_data.peer_id; uint32_t port_l = arg.node_data.my_port; diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index 5cdfa0e8..f133683f 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2021 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -11,8 +11,6 @@ #include #include #include -//#include -//#include #include #include #include @@ -55,10 +53,10 @@ namespace nodetool bool append_with_peer_gray(const peerlist_entry& pr); bool set_peer_just_seen(peerid_type peer, uint32_t ip, uint32_t port); bool set_peer_just_seen(peerid_type peer, const net_address& addr); - bool set_peer_unreachable(const peerlist_entry& pr); bool is_ip_allowed(uint32_t ip); void trim_white_peerlist(); void trim_gray_peerlist(); + bool remove_peers_by_ip_from_all(const uint32_t ip); private: @@ -110,17 +108,6 @@ namespace nodetool > > peers_indexed; - typedef boost::multi_index_container< - peerlist_entry, - boost::multi_index::indexed_by< - // access by peerlist_entry::id< - boost::multi_index::ordered_unique, boost::multi_index::member >, - // access by peerlist_entry::net_adress - boost::multi_index::ordered_unique, boost::multi_index::member >, - // sort by peerlist_entry::last_seen< - boost::multi_index::ordered_non_unique, boost::multi_index::member > - > - > peers_indexed_old; public: template @@ -134,9 +121,7 @@ namespace nodetool ar & m_peers_gray; } - private: - bool peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi); - + private: friend class boost::serialization::access; epee::critical_section m_peerlist_lock; std::string m_config_folder; @@ -188,21 +173,6 @@ namespace nodetool return true; } //-------------------------------------------------------------------------------------------------- - inline - bool peerlist_manager::peers_indexed_from_old(const peers_indexed_old& pio, peers_indexed& pi) - { - for(auto x: pio) - { - auto by_addr_it = pi.get().find(x.adr); - if(by_addr_it == pi.get().end()) - { - pi.insert(x); - } - } - - return true; - } - //-------------------------------------------------------------------------------------------------- inline void peerlist_manager::trim_white_peerlist() { CRITICAL_REGION_LOCAL(m_peerlist_lock); @@ -393,6 +363,33 @@ namespace nodetool return true; } //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::remove_peers_by_ip_from_all(const uint32_t ip) + { + TRY_ENTRY(); + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + + for (auto it = m_peers_white.begin(); it != m_peers_white.end();) + { + if (it->adr.ip == ip) + it = m_peers_white.erase(it); + else + ++it; + } + + for (auto it = m_peers_gray.begin(); it != m_peers_gray.end();) + { + if (it->adr.ip == ip) + it = m_peers_gray.erase(it); + else + ++it; + } + + return true; + CATCH_ENTRY_L0("peerlist_manager::remove_peers_by_ip_from_all()", false); + } + //-------------------------------------------------------------------------------------------------- } BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 2c287ed7..c16efcac 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -180,7 +180,7 @@ namespace currency res.pos_block_ts_shift_vs_actual = 0; auto last_pos_block_ptr = m_core.get_blockchain_storage().get_last_block_of_type(true); if (last_pos_block_ptr) - res.pos_block_ts_shift_vs_actual = last_pos_block_ptr->bl.timestamp - get_actual_timestamp(last_pos_block_ptr->bl); + res.pos_block_ts_shift_vs_actual = last_pos_block_ptr->bl.timestamp - get_block_datetime(last_pos_block_ptr->bl); } if (req.flags&COMMAND_RPC_GET_INFO_FLAG_OUTS_STAT) m_core.get_blockchain_storage().get_outs_index_stat(res.outs_stat); @@ -916,17 +916,6 @@ namespace currency error_resp.message = "Block not accepted"; return false; } - //@#@ - //temporary double check timestamp - if (time(NULL) - static_cast(get_actual_timestamp(b)) > 5) - { - LOG_PRINT_RED_L0("Found block (" << get_block_hash(b) << ") timestamp (" << get_actual_timestamp(b) - << ") is suspiciously less (" << time(NULL) - static_cast(get_actual_timestamp(b)) << ") than current time ( " << time(NULL) << ")"); - //mark node to make it easier to find it via scanner - m_core.get_blockchain_storage().get_performnce_data().epic_failure_happend = true; - } - // - res.status = "OK"; return true; @@ -973,17 +962,6 @@ namespace currency error_resp.message = "Block not accepted"; return false; } - //@#@ - //temporary double check timestamp - if (time(NULL) - static_cast(get_actual_timestamp(b)) > 5) - { - LOG_PRINT_RED_L0("Found block (" << get_block_hash(b) << ") timestamp (" << get_actual_timestamp(b) - << ") is suspiciously less (" << time(NULL) - static_cast(get_actual_timestamp(b)) << ") than current time ( " << time(NULL) << ")"); - //mark node to make it easier to find it via scanner - m_core.get_blockchain_storage().get_performnce_data().epic_failure_happend = true; - } - // - res.status = "OK"; return true; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 5ca38d56..cfb48a64 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -228,6 +228,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), "sign_transfer - sign unsigned tx from a watch-only wallet"); m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), "submit_transfer - broadcast signed tx"); + m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this, _1), "Export transaction history in CSV file"); } //---------------------------------------------------------------------------------------------------- simple_wallet::~simple_wallet() @@ -798,12 +799,7 @@ bool simple_wallet::list_recent_transfers(const std::vector& args) std::string wti_to_text_line(const tools::wallet_public::wallet_transfer_info& wti) { stringstream ss; - ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t" - << epee::misc_utils::get_time_str(wti.timestamp) << "\t" - << print_money(wti.amount) << "\t" - << print_money(wti.fee) << "\t" - << wti.remote_addresses << "\t" - << wti.comment << "\t"; + return ss.str(); } //---------------------------------------------------------------------------------------------------- @@ -811,58 +807,37 @@ bool simple_wallet::export_recent_transfers(const std::vector& args { bool export_to_json = true; bool ignore_pos = false; - if (args.size()) - { - if (args[0] == "json") - export_to_json = true; - else if (args[0] == "txt") - export_to_json = false; - } if (args.size() > 1) { if (args[1] == "ignore-pos") ignore_pos = true; } - std::vector unconfirmed; - std::vector recent; - uint64_t total = 0; - uint64_t last_index = 0; - m_wallet->get_recent_transfers_history(recent, 0, 0, total, last_index, false); - m_wallet->get_unconfirmed_transfers(unconfirmed, false); - //workaround for missed fee - stringstream ss; - LOG_PRINT_GREEN("Generating text....", LOG_LEVEL_0); - ss << "Unconfirmed transfers: " << ENDL; - for (auto & wti : unconfirmed) + std::string format = "csv"; + if (args.size() > 0) { - if(ignore_pos && wti.is_mining) - continue; - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); - if(export_to_json) - ss << epee::serialization::store_t_to_json(wti) << ENDL; + if (args[0] == "json" || args[0] == "csv" || args[0] == "text") + { + format = args[0]; + } else - ss << wti_to_text_line(wti) << ENDL; - + { + fail_msg_writer() << "Unknown format: \"" << args[0] << "\", only \"csv\"(default), \"json\" and \"text\" supported"; + } } - ss << "Recent transfers: " << ENDL; - for (auto & wti : recent) + + try { + boost::filesystem::ofstream fstream; + fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + m_wallet->export_transaction_history(fstream, format, !ignore_pos); + fstream.close(); + } + catch (...) { - if (ignore_pos && wti.is_mining) - continue; - if (!wti.fee) - wti.fee = currency::get_tx_fee(wti.tx); - - if (export_to_json) - ss << epee::serialization::store_t_to_json(wti) << ENDL; - else - ss << wti_to_text_line(wti) << ENDL; + success_msg_writer() << "Failed"; + return false; } - LOG_PRINT_GREEN("Storing text to wallet_recent_transfers.txt....", LOG_LEVEL_0); - file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", ss.str()); - LOG_PRINT_GREEN("Done", LOG_LEVEL_0); - return true; } //---------------------------------------------------------------------------------------------------- @@ -1183,7 +1158,7 @@ bool simple_wallet::validate_wrap_status(uint64_t amount) currency::void_struct req = AUTO_VAL_INIT(req); currency::rpc_get_wrap_info_response res = AUTO_VAL_INIT(res); - bool r = epee::net_utils::invoke_http_json_remote_command2("http://wrapped.zano.org/api/get_wrap_info", req, res, http_client, 10000); + bool r = epee::net_utils::invoke_http_json_remote_command2("http://wrapped.zano.org/api2/get_wrap_info", req, res, http_client, 10000); if (!r) { fail_msg_writer() << "Failed to request wrap status from server, check internet connection"; diff --git a/src/version.h.in b/src/version.h.in index 0aadd22e..fec98663 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -5,9 +5,9 @@ #define PROJECT_MAJOR_VERSION "1" #define PROJECT_MINOR_VERSION "3" -#define PROJECT_REVISION "0" +#define PROJECT_REVISION "1" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 132 +#define PROJECT_VERSION_BUILD_NO 134 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index b2f31850..2e7914fb 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -201,7 +201,8 @@ namespace plain_wallet args[1] = const_cast(argss_1.c_str()); args[2] = const_cast(argss_2.c_str()); args[3] = nullptr; - if (!(ptr->gwm.init_command_line(3, args) && ptr->gwm.init(nullptr))) + std::string command_line_fail_details; + if (!(ptr->gwm.init_command_line(3, args, command_line_fail_details) && ptr->gwm.init(nullptr))) { LOG_ERROR("Failed to init wallets_manager"); return GENERAL_INTERNAL_ERRROR_INIT; diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index 1dc31f2c..8c5e52c4 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -284,6 +284,20 @@ public: END_KV_SERIALIZE_MAP() }; + struct export_wallet_info + { + uint64_t wallet_id; + bool include_pos_transactions; + std::string path; + std::string format; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(wallet_id) + KV_SERIALIZE(include_pos_transactions) + KV_SERIALIZE(path) + KV_SERIALIZE(format) + END_KV_SERIALIZE_MAP() + }; struct response_mining_estimate { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f8cc2fb6..5c9028f2 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1281,7 +1281,7 @@ void wallet2::handle_money_received2(const currency::block& b, const currency::t m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); wti.is_income = true; - prepare_wti(wti, get_block_height(b), get_actual_timestamp(b), tx, amount, td); + prepare_wti(wti, get_block_height(b), get_block_datetime(b), tx, amount, td); WLT_LOG_L1("[MONEY RECEIVED]: " << epee::serialization::store_t_to_json(wti)); rise_on_transfer2(wti); } @@ -1311,7 +1311,7 @@ void wallet2::handle_money_spent2(const currency::block& b, wti.remote_addresses = recipients; wti.recipients_aliases = recipients_aliases; - prepare_wti(wti, get_block_height(b), get_actual_timestamp(b), in_tx, amount, td); + prepare_wti(wti, get_block_height(b), get_block_datetime(b), in_tx, amount, td); WLT_LOG_L1("[MONEY SPENT]: " << epee::serialization::store_t_to_json(wti)); rise_on_transfer2(wti); } @@ -3254,6 +3254,87 @@ void wallet2::get_recent_transfers_history(std::vector(ss, " ")); + ss << "]" << ","; + ss << wti.tx_hash << ","; + ss << wti.height << ","; + ss << wti.unlock_time << ","; + ss << wti.tx_blob_size << ","; + ss << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ","; + ss << "["; + std::copy(wti.recipients_aliases.begin(), wti.recipients_aliases.end(), std::ostream_iterator(ss, " ")); + ss << "]" << ","; + ss << (wti.is_income ? "in" : "out") << ","; + ss << (wti.is_service ? "[SERVICE]" : "") << (wti.is_mixing ? "[MIXINS]" : "") << (wti.is_mining ? "[MINING]" : "") << ","; + ss << wti.tx_type << ","; + ss << wti.fee << ENDL; +}; + +void wallet2::wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) +{ + ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t" + << epee::misc_utils::get_time_str(wti.timestamp) << "\t" + << print_money(wti.amount) << "\t" + << print_money(wti.fee) << "\t" + << wti.remote_addresses << "\t" + << wti.comment << ENDL; +}; + +void wallet2::wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index) +{ + ss << epee::serialization::store_t_to_json(wti, 4) << ","; +}; + + +//---------------------------------------------------------------------------------------------------- +void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions) +{ + //typedef int(*t_somefunc)(int, int); + typedef void(*playout_cb_type)(std::ostream&, const wallet_public::wallet_transfer_info&, size_t); + playout_cb_type cb_csv = &wallet2::wti_to_csv_entry; + playout_cb_type cb_json = &wallet2::wti_to_json_line; + playout_cb_type cb_plain_text = &wallet2::wti_to_txt_line; + + playout_cb_type cb = cb_csv; + if (format == "json") + { + ss << "{ \"history\": ["; + cb = cb_json; + } + else if (format == "text") + { + cb = cb_plain_text; + } + else + { + //csv by default + ss << "N, Date, Amount, Comment, Address, ID, Height, Unlock timestamp, Tx size, Alias, In/Out, Flags, Type, Fee" << ENDL; + } + + + enum_container(m_transfer_history.begin(), m_transfer_history.end(), [&](wallet_public::wallet_transfer_info& wti, size_t index) { + if (!include_pos_transactions) + { + if (currency::is_coinbase(wti.tx)) + return true; + } + cb(ss, wti, index); + return true; + }); + + if (format == "json") + { + ss << "{}]}"; + } + } //---------------------------------------------------------------------------------------------------- bool wallet2::get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) @@ -3377,16 +3458,13 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, return true; } //------------------------------------------------------------------ -bool wallet2::build_kernel(const pos_entry& pe, const stake_modifier_type& stake_modifier, stake_kernel& kernel, uint64_t& coindays_weight, uint64_t timestamp) +bool wallet2::build_kernel(const pos_entry& pe, const stake_modifier_type& stake_modifier, const uint64_t timestamp, stake_kernel& kernel) { PROFILE_FUNC("build_kernel"); - coindays_weight = 0; kernel = stake_kernel(); kernel.kimage = pe.keyimage; kernel.stake_modifier = stake_modifier; kernel.block_timestamp = timestamp; - - coindays_weight = get_coinday_weight(pe.amount); return true; } //---------------------------------------------------------------------------------------------------- @@ -3457,7 +3535,7 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address build_minted_block(ctx.sp, ctx.rsp, miner_address); } - WLT_LOG_L0("PoS mining iteration finished, status: " << ctx.rsp.status << ", used " << ctx.sp.pos_entries.size() << " entries with total amount: " << print_money_brief(pos_entries_amount)); + WLT_LOG_L0("PoS mining: " << ctx.rsp.iterations_processed << " iterations finished, status: " << ctx.rsp.status << ", used " << ctx.sp.pos_entries.size() << " entries with total amount: " << print_money_brief(pos_entries_amount)); return true; } @@ -3533,12 +3611,11 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& const currency::txout_to_key& txtokey = boost::get(target); keys_ptrs.push_back(&txtokey.key); - //put actual time for tx block + // set a real timestamp b.timestamp = rsp.block_timestamp; - currency::etc_tx_time tt = AUTO_VAL_INIT(tt); - tt.v = m_core_runtime_config.get_core_time(); - b.miner_tx.extra.push_back(tt); - WLT_LOG_MAGENTA("Applying actual timestamp: " << epee::misc_utils::get_time_str(tt.v), LOG_LEVEL_0); + uint64_t current_timestamp = m_core_runtime_config.get_core_time(); + set_block_datetime(current_timestamp, b); + WLT_LOG_MAGENTA("Applying actual timestamp: " << current_timestamp, LOG_LEVEL_0); //sign block res = prepare_and_sign_pos_block(b, @@ -3564,14 +3641,7 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& } WLT_LOG_GREEN("POS block generated and accepted, congrats!", LOG_LEVEL_0); m_wcallback->on_pos_block_found(b); - //@#@ - //double check timestamp - if (time(NULL) - static_cast(get_actual_timestamp(b)) > 5) - { - WLT_LOG_RED("Found block (" << get_block_hash(b) << ") timestamp (" << get_actual_timestamp(b) - << ") is suspiciously less (" << time(NULL) - static_cast(get_actual_timestamp(b)) << ") than current time ( " << time(NULL) << ")", LOG_LEVEL_0); - } - // + return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index fd79042a..fdf2afad 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -861,6 +861,8 @@ namespace tools uint64_t get_wallet_file_size()const; void set_use_deffered_global_outputs(bool use); construct_tx_param get_default_construct_tx_param_inital(); + + void export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions = true); /* create_htlc_proposal: if htlc_hash == null_hash, then this wallet is originator of the atomic process, and @@ -872,7 +874,6 @@ namespace tools void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin, currency::transaction& result_tx); void redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& origin); bool check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& origin, crypto::hash& redeem_tx_id); - private: void add_transfers_to_expiration_list(const std::vector& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id); @@ -920,7 +921,7 @@ private: void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); std::string get_alias_for_address(const std::string& addr); - static bool build_kernel(const currency::pos_entry& pe, const currency::stake_modifier_type& stake_modifier, currency::stake_kernel& kernel, uint64_t& coindays_weight, uint64_t timestamp); + static bool build_kernel(const currency::pos_entry& pe, const currency::stake_modifier_type& stake_modifier, const uint64_t timestamp, currency::stake_kernel& kernel); bool is_connected_to_net(); bool is_transfer_okay_for_pos(const transfer_details& tr, uint64_t& stake_unlock_time); bool scan_unconfirmed_outdate_tx(); @@ -1006,6 +1007,10 @@ private: void push_alias_info_to_extra_according_to_hf_status(const currency::extra_alias_entry& ai, std::vector& extra); void remove_transfer_from_amount_gindex_map(uint64_t tid); + static void wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + static void wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + static void wti_to_json_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); + currency::account_base m_account; bool m_watch_only; std::string m_log_prefix; // part of pub address, prefix for logging functions @@ -1203,16 +1208,20 @@ namespace tools const currency::core_runtime_config &runtime_config) { cxt.rsp.status = API_RETURN_CODE_NOT_FOUND; - uint64_t timstamp_start = runtime_config.get_core_time(); uint64_t timstamp_last_idle_call = runtime_config.get_core_time(); cxt.rsp.iterations_processed = 0; + uint64_t ts_from = cxt.rsp.starter_timestamp; // median ts of last BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW blocks + ts_from = ts_from - (ts_from % POS_SCAN_STEP) + POS_SCAN_STEP; + uint64_t ts_to = runtime_config.get_core_time() + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT - 5; + ts_to = ts_to - (ts_to % POS_SCAN_STEP); + CHECK_AND_ASSERT_MES(ts_to > ts_from, false, "scan_pos: ts_to <= ts_from: " << ts_to << ", " << ts_from); + uint64_t ts_middle = (ts_to + ts_from) / 2; + ts_middle -= ts_middle % POS_SCAN_STEP; + uint64_t ts_window = std::min(ts_middle - ts_from, ts_to - ts_middle); + for (size_t i = 0; i != cxt.sp.pos_entries.size(); i++) { - //set timestamp starting from timestamp%POS_SCAN_STEP = 0 - uint64_t adjusted_starter_timestamp = timstamp_start - POS_SCAN_STEP; - adjusted_starter_timestamp = POS_SCAN_STEP * 2 - (adjusted_starter_timestamp%POS_SCAN_STEP) + adjusted_starter_timestamp; - bool go_past = true; uint64_t step = 0; @@ -1232,7 +1241,7 @@ namespace tools } }; - while(step <= POS_SCAN_WINDOW) + while(step <= ts_window) { //check every WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL seconds if top block changes, in case - break loop @@ -1248,8 +1257,8 @@ namespace tools } - uint64_t ts = go_past ? adjusted_starter_timestamp - step : adjusted_starter_timestamp + step; - if (ts < cxt.rsp.starter_timestamp) + uint64_t ts = go_past ? ts_middle - step : ts_middle + step; + if (ts < ts_from || ts > ts_to) { next_turn(); continue; @@ -1258,27 +1267,27 @@ namespace tools if (stop) return false; currency::stake_kernel sk = AUTO_VAL_INIT(sk); - uint64_t coindays_weight = 0; - build_kernel(cxt.sp.pos_entries[i], cxt.sm, sk, coindays_weight, ts); + const uint64_t& stake_amount = cxt.sp.pos_entries[i].amount; + build_kernel(cxt.sp.pos_entries[i], cxt.sm, ts, sk); crypto::hash kernel_hash; { PROFILE_FUNC("calc_hash"); kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); } - currency::wide_difficulty_type this_coin_diff = cxt.basic_diff / coindays_weight; + currency::wide_difficulty_type final_diff = cxt.basic_diff / stake_amount; bool check_hash_res; { PROFILE_FUNC("check_hash"); - check_hash_res = currency::check_hash(kernel_hash, this_coin_diff); + check_hash_res = currency::check_hash(kernel_hash, final_diff); ++cxt.rsp.iterations_processed; } if (check_hash_res) { //found kernel - LOG_PRINT_GREEN("Found kernel: amount=" << currency::print_money(cxt.sp.pos_entries[i].amount) << ENDL - << "difficulty_basic=" << cxt.basic_diff << ", diff for this coin: " << this_coin_diff << ENDL - << "index=" << cxt.sp.pos_entries[i].index << ENDL + LOG_PRINT_GREEN("Found kernel: amount: " << currency::print_money(stake_amount) << ENDL + << "difficulty: " << cxt.basic_diff << ", final_diff: " << final_diff << ENDL + << "index: " << cxt.sp.pos_entries[i].index << ENDL << "kernel info: " << ENDL << print_stake_kernel_info(sk) << ENDL << "kernel_hash(proof): " << kernel_hash, diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 9152c66a..ca888e83 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -56,7 +56,11 @@ namespace tools command_line::add_arg(desc, arg_deaf_mode); } //------------------------------------------------------------------------------------------------------------------------------ - wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), m_do_mint(false), m_deaf(false) + wallet_rpc_server::wallet_rpc_server(wallet2& w) + : m_wallet(w) + , m_do_mint(false) + , m_deaf(false) + , m_last_wallet_store_height(0) {} //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address) @@ -91,6 +95,18 @@ namespace tools LOG_PRINT_L2("wallet RPC idle: trying to do PoS iteration..."); m_wallet.try_mint_pos(miner_address); } + + //auto-store wallet in server mode, let's do it every 24-hour + if (m_wallet.get_top_block_height() < m_last_wallet_store_height) + { + LOG_ERROR("Unexpected m_last_wallet_store_height = " << m_last_wallet_store_height << " or " << m_wallet.get_top_block_height()); + } + else if (m_wallet.get_top_block_height() - m_last_wallet_store_height > CURRENCY_BLOCKS_PER_DAY) + { + //store wallet + m_wallet.store(); + m_last_wallet_store_height = m_wallet.get_top_block_height(); + } } catch (error::no_connection_to_daemon&) { @@ -132,6 +148,7 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::init(const boost::program_options::variables_map& vm) { + m_last_wallet_store_height = m_wallet.get_top_block_height(); m_net_server.set_threads_prefix("RPC"); bool r = handle_command_line(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); @@ -296,7 +313,7 @@ namespace tools else { //put it to attachments - ctp.attachments.insert(ctp.extra.end(), req.service_entries.begin(), req.service_entries.end()); + ctp.attachments.insert(ctp.attachments.end(), req.service_entries.begin(), req.service_entries.end()); } bool wrap = false; std::vector& dsts = ctp.dsts; @@ -384,7 +401,7 @@ namespace tools currency::finalized_tx result = AUTO_VAL_INIT(result); std::string unsigned_tx_blob_str; ctp.fee = req.fee; - ctp.fake_outputs_count = 0; + ctp.fake_outputs_count = req.mixin; m_wallet.transfer(ctp, result, true, &unsigned_tx_blob_str); if (m_wallet.is_watch_only()) { diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 3c75296e..b99420d4 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -118,6 +118,7 @@ namespace tools std::string m_bind_ip; bool m_do_mint; bool m_deaf; + uint64_t m_last_wallet_store_height; }; } // namespace tools diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 6155b4b0..2beb7c2f 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -152,7 +152,7 @@ bool wallets_manager::do_exception_safe_call(guarded_code_t guarded_code, error_ } -bool wallets_manager::init_command_line(int argc, char* argv[]) +bool wallets_manager::init_command_line(int argc, char* argv[], std::string& fail_message) { TRY_ENTRY(); po::options_description desc_cmd_only("Command line options"); @@ -197,9 +197,8 @@ bool wallets_manager::init_command_line(int argc, char* argv[]) po::options_description desc_options("Allowed options"); desc_options.add(desc_cmd_only).add(desc_cmd_sett); - - - bool coomand_line_parsed = command_line::handle_error_helper(desc_options, [&]() + std::string err_str; + bool command_line_parsed = command_line::handle_error_helper(desc_options, err_str, [&]() { po::store(po::parse_command_line(argc, argv, desc_options), m_vm); @@ -230,23 +229,29 @@ bool wallets_manager::init_command_line(int argc, char* argv[]) return true; }); - if (!coomand_line_parsed) + if (!command_line_parsed) { std::stringstream ss; ss << "Command line has wrong arguments: " << std::endl; for (int i = 0; i != argc; i++) ss << "[" << i << "] " << argv[i] << std::endl; std::cerr << ss.str() << std::endl << std::flush; + + fail_message = "Error parsing arguments.\n"; + fail_message += err_str + "\n"; + std::stringstream s; + desc_options.print(s); + fail_message += s.str(); return false; } m_qt_logs_enbaled = command_line::get_arg(m_vm, arg_enable_qt_logs); m_qt_dev_tools = command_line::get_arg(m_vm, arg_qt_dev_tools); - return true; CATCH_ENTRY2(false); } + void terminate_handler_func() { LOG_ERROR("\n\nTERMINATE HANDLER\n"); // should print callstack @@ -798,6 +803,24 @@ std::string wallets_manager::get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INF } +std::string wallets_manager::export_wallet_history(const view::export_wallet_info& ewi) +{ + GET_WALLET_OPT_BY_ID(ewi.wallet_id, wo); + try { + + boost::filesystem::ofstream fstream; + fstream.exceptions(std::ifstream::failbit | std::ifstream::badbit); + fstream.open(ewi.path, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc); + wo.w->get()->export_transaction_history(fstream, ewi.format, ewi.include_pos_transactions); + fstream.close(); + } + catch (...) + { + return API_RETURN_CODE_FAIL; + } + return API_RETURN_CODE_OK; +} + uint64_t wallets_manager::get_default_fee() { return TX_DEFAULT_FEE; @@ -1802,7 +1825,10 @@ void wallets_manager::on_transfer2(size_t wallet_id, const tools::wallet_public: GET_WALLET_OPTIONS_BY_ID_VOID_RET(wallet_id, w); tei.is_wallet_in_sync_process = w.long_refresh_in_progress; - m_pview->money_transfer(tei); + if (!(w.w->get()->is_watch_only())) + { + m_pview->money_transfer(tei); + } } void wallets_manager::on_pos_block_found(size_t wallet_id, const currency::block& b) { diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 151680d1..10d6a103 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -89,7 +89,7 @@ public: wallets_manager(); ~wallets_manager(); - bool init_command_line(int argc, char* argv[]); + bool init_command_line(int argc, char* argv[], std::string& fail_message); bool init(view::i_view* pview_handler); bool start(); bool stop(); @@ -139,6 +139,7 @@ public: std::string get_my_offers(const bc_services::core_offers_filter& filter, std::list& offers); std::string get_fav_offers(const std::list& hashes, const bc_services::core_offers_filter& filter, std::list& offers); std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res); + std::string export_wallet_history(const view::export_wallet_info& ewi); uint64_t get_default_fee(); std::string get_mining_estimate(uint64_t amuont_coins, uint64_t time, diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 57f00b22..01aa5f8b 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -563,17 +563,15 @@ bool test_generator::find_kernel(const std::list& accs, { stake_kernel sk = AUTO_VAL_INIT(sk); - uint64_t coindays_weight = 0; build_kernel(scan_pos_entries.pos_entries[i].amount, scan_pos_entries.pos_entries[i].index, scan_pos_entries.pos_entries[i].keyimage, sk, - coindays_weight, blck_chain, indexes, ts); crypto::hash kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); - wide_difficulty_type this_coin_diff = basic_diff / coindays_weight; + wide_difficulty_type this_coin_diff = basic_diff / scan_pos_entries.pos_entries[i].amount; if (!check_hash(kernel_hash, this_coin_diff)) continue; else @@ -672,12 +670,10 @@ bool test_generator::build_kernel(uint64_t amount, uint64_t global_index, const crypto::key_image& ki, stake_kernel& kernel, - uint64_t& coindays_weight, const test_generator::blockchain_vector& blck_chain, const test_generator::outputs_index& indexes, uint64_t timestamp) { - coindays_weight = 0; kernel = stake_kernel(); kernel.kimage = ki; @@ -701,7 +697,6 @@ bool test_generator::build_kernel(uint64_t amount, kernel.block_timestamp = timestamp; - coindays_weight = get_coinday_weight(amount); build_stake_modifier(kernel.stake_modifier, blck_chain); return true; } @@ -2058,6 +2053,25 @@ bool check_ring_signature_at_gen_time(const std::vector& event return true; } +bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c) +{ + std::shared_ptr ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id); + if (!ptce) + return false; + + for (size_t i = 0; i < ptce->tx.vin.size(); ++i) + { + auto& input = ptce->tx.vin[i]; + if (input.type() == typeid(txin_to_key)) + { + auto& intk = boost::get(input); + CHECK_AND_ASSERT_MES(intk.key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << intk.key_offsets.size() - 1 << ", expected is " << mixin); + } + } + + return true; +} + //------------------------------------------------------------------------------ void test_chain_unit_base::register_callback(const std::string& cb_name, verify_callback cb) diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 8ccec794..7cbf4822 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -410,7 +410,6 @@ public: uint64_t global_index, const crypto::key_image& ki, currency::stake_kernel& kernel, - uint64_t& coindays_weight, const blockchain_vector& blck_chain, const outputs_index& indexes, uint64_t timestamp); @@ -680,6 +679,7 @@ bool generate_pos_block_with_given_coinstake(test_generator& generator, const st bool check_ring_signature_at_gen_time(const std::vector& events, const crypto::hash& last_block_id, const currency::txin_to_key& in_t_k, const crypto::hash& hash_for_sig, const std::vector &sig); +bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c); //-------------------------------------------------------------------------- template diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 6cd4425d..b50044b6 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -867,6 +867,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(wallet_rpc_integrated_address); GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer); + GENERATE_AND_PLAY(wallet_rpc_transfer); GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki); GENERATE_AND_PLAY(wallet_sending_to_integrated_address); diff --git a/tests/core_tests/emission_test.cpp b/tests/core_tests/emission_test.cpp index dcb26c84..a033f7a3 100644 --- a/tests/core_tests/emission_test.cpp +++ b/tests/core_tests/emission_test.cpp @@ -112,7 +112,7 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector()); pb.step3_build_stake_kernel(stake_output_amount, stake_output_gidx, stake_output_key_image, difficulty, prev_id, null_hash, timestamp); pb.step4_generate_coinbase_tx(0, already_generated_coins, m_miner_acc.get_public_address()); - pb.m_block.miner_tx.extra.push_back(currency::etc_tx_time({ timestamp })); // actual timestamp + set_block_datetime(timestamp, pb.m_block); pb.step5_sign(stake_tx_pub_key, stake_output_idx, stake_output_pubkey, m_miner_acc); c.handle_incoming_block(t_serializable_object_to_blob(pb.m_block), bvc); diff --git a/tests/core_tests/hard_fork_1.cpp b/tests/core_tests/hard_fork_1.cpp index c4083254..dafe48b8 100644 --- a/tests/core_tests/hard_fork_1.cpp +++ b/tests/core_tests/hard_fork_1.cpp @@ -634,7 +634,7 @@ bool hard_fork_1_pos_and_locked_coins::generate(std::vector& e { MAKE_NEXT_POS_BLOCK(events, b, prev, miner_acc, std::list{miner_acc}); prev = b; - events.push_back(event_core_time(get_actual_timestamp(b) + 100)); + events.push_back(event_core_time(get_block_datetime(b) + 100)); } diff --git a/tests/core_tests/isolate_auditable_and_proof.cpp b/tests/core_tests/isolate_auditable_and_proof.cpp index e3fadbdb..2bf086f5 100644 --- a/tests/core_tests/isolate_auditable_and_proof.cpp +++ b/tests/core_tests/isolate_auditable_and_proof.cpp @@ -23,6 +23,10 @@ isolate_auditable_and_proof::isolate_auditable_and_proof() bool isolate_auditable_and_proof::generate(std::vector& events) const { + // Test outline: this test makes sure: + // 1) that only owner of the secret spend key can decode the attachment (TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE) + // 2) TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF -- add public hash of original info + random_state_test_restorer::reset_random(0); // to make the test deterministic m_genesis_timestamp = 1450000000; test_core_time::adjust(m_genesis_timestamp); @@ -87,7 +91,7 @@ bool isolate_auditable_and_proof::c1(currency::core& c, size_t ev_index, const s tx_service_attachment sa = AUTO_VAL_INIT(sa); sa.service_id = BC_WRAP_SERVICE_ID; sa.instruction = BC_WRAP_SERVICE_INSTRUCTION_ERC20; - sa.flags = TX_SERVICE_ATTACHMENT_ENCRYPT_BODY | TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE| TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF; + sa.flags = TX_SERVICE_ATTACHMENT_ENCRYPT_BODY | TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE | TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF; sa.body = "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B"; extra.push_back(sa); @@ -122,4 +126,3 @@ bool isolate_auditable_and_proof::c1(currency::core& c, size_t ev_index, const s return true; } - diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 12bb2f8a..626dfae2 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -148,6 +148,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind alice_wlt->get_payments(payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size()); CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(3), false, "Invalid payment"); + CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(0, payments.front().m_tx_hash, c), false, ""); // make sure number of decoys is correct // 3. standard address + invalid external payment id => fail @@ -181,9 +182,127 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind alice_wlt->get_payments(payment_id, payments); CHECK_AND_ASSERT_MES(payments.size() == 1, false, "Invalid payments count: " << payments.size()); CHECK_AND_ASSERT_MES(payments.front().m_amount == MK_TEST_COINS(7), false, "Invalid payment"); + CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(0, payments.front().m_tx_hash, c), false, ""); // make sure number of decoys is correct return true; } //------------------------------------------------------------------------------ + +wallet_rpc_transfer::wallet_rpc_transfer() +{ + REGISTER_CALLBACK_METHOD(wallet_rpc_transfer, configure_core); + REGISTER_CALLBACK_METHOD(wallet_rpc_transfer, c1); +} + +bool wallet_rpc_transfer::generate(std::vector& events) const +{ + m_accounts.resize(TOTAL_ACCS_COUNT); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); + account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); + account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + DO_CALLBACK(events, "configure_core"); + set_hard_fork_heights_to_generator(generator); + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 6); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool wallet_rpc_transfer::configure_core(currency::core& c, size_t ev_index, const std::vector& events) +{ + currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config(); + pc.hard_fork_01_starts_after_height = 1; + pc.hard_fork_02_starts_after_height = 1; + pc.hard_fork_03_starts_after_height = 1; + c.get_blockchain_storage().set_core_runtime_config(pc); + return true; +} + +bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false; + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + + miner_wlt->refresh(); + + // wallet RPC server + tools::wallet_rpc_server miner_wlt_rpc(*miner_wlt); + epee::json_rpc::error je; + tools::wallet_rpc_server::connection_context ctx; + + // 1. Check non-zero mixin and default settings + tools::wallet_public::COMMAND_RPC_TRANSFER::request req = AUTO_VAL_INIT(req); + req.fee = TESTS_DEFAULT_FEE; + req.mixin = 2; + tools::wallet_public::transfer_destination tds = AUTO_VAL_INIT(tds); + tds.address = m_accounts[ALICE_ACC_IDX].get_public_address_str(); + tds.amount = MK_TEST_COINS(3); + req.destinations.push_back(tds); + + tools::wallet_public::COMMAND_RPC_TRANSFER::response res = AUTO_VAL_INIT(res); + + r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "RPC call failed, code: " << je.code << ", msg: " << je.message); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, tds.amount), false, ""); + + // check the transfer has been received + tools::wallet2::transfer_details td = AUTO_VAL_INIT(td); + CHECK_AND_ASSERT_MES(alice_wlt->get_transfer_info_by_index(0, td), false, ""); + CHECK_AND_ASSERT_MES(td.amount() == MK_TEST_COINS(3), false, "Invalid payment"); + CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(2, td.tx_hash(), c), false, ""); + + // make sure tx_received is set by default, but tx_payer is not + std::shared_ptr pche = c.get_blockchain_storage().get_tx_chain_entry(td.tx_hash()); + CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container(pche->tx.extra) == 1, false, "tx_receiver: incorrect count of items"); + CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container(pche->tx.extra) == 0, false, "tx_payer: incorrect count of items"); + + + // 2. check tx_receiver and tx_payer non-default + req.mixin = 1; + req.hide_receiver = true; + req.push_payer = true; + tds.amount = MK_TEST_COINS(5); + req.destinations.clear(); + req.destinations.push_back(tds); + + res = AUTO_VAL_INIT(res); + + r = miner_wlt_rpc.on_transfer(req, res, je, ctx); + CHECK_AND_ASSERT_MES(r, false, "RPC call failed, code: " << je.code << ", msg: " << je.message); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); + + CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, MK_TEST_COINS(3 + 5)), false, ""); + + td = AUTO_VAL_INIT(td); + CHECK_AND_ASSERT_MES(alice_wlt->get_transfer_info_by_index(1, td), false, ""); + CHECK_AND_ASSERT_MES(td.amount() == MK_TEST_COINS(5), false, "Invalid payment"); + CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(1, td.tx_hash(), c), false, ""); + + // make sure tx_received is set by default, but tx_payer is not + pche = c.get_blockchain_storage().get_tx_chain_entry(td.tx_hash()); + CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container(pche->tx.extra) == 0, false, "tx_receiver: incorrect count of items"); + CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container(pche->tx.extra) == 1, false, "tx_payer: incorrect count of items"); + + + return true; +} diff --git a/tests/core_tests/wallet_rpc_tests.h b/tests/core_tests/wallet_rpc_tests.h index 9d6674f5..1c0ea50c 100644 --- a/tests/core_tests/wallet_rpc_tests.h +++ b/tests/core_tests/wallet_rpc_tests.h @@ -21,3 +21,11 @@ struct wallet_rpc_integrated_address_transfer : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +struct wallet_rpc_transfer : public wallet_test +{ + wallet_rpc_transfer(); + bool generate(std::vector& events) const; + bool configure_core(currency::core& c, size_t ev_index, const std::vector& events); + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 18b03b9e..ab62563f 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1365,7 +1365,7 @@ bool gen_wallet_transfers_and_chain_switch::generate(std::vector