diff options
26 files changed, 252 insertions, 183 deletions
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl index e455d0204..c52535dcd 100644 --- a/contrib/epee/include/net/abstract_tcp_server2.inl +++ b/contrib/epee/include/net/abstract_tcp_server2.inl @@ -559,7 +559,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) while (!message.empty()) { byte_slice chunk = message.take_slice(chunksize_good); - MDEBUG("chunk_start="<<chunk.data()<<" ptr="<<message_data<<" pos="<<(chunk.data() - message_data)); + MDEBUG("chunk_start="<<(void*)chunk.data()<<" ptr="<<message_data<<" pos="<<(chunk.data() - message_data)); MDEBUG("part of " << message.size() << ": pos="<<(chunk.data() - message_data) << " len="<<chunk.size()); bool ok = do_send_chunk(std::move(chunk)); // <====== *** @@ -984,8 +984,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); acceptor_.open(endpoint.protocol()); - // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). - acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_.set_option(boost::asio::ip::tcp::acceptor::linger(true, 0)); acceptor_.bind(endpoint); acceptor_.listen(); boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint(); @@ -1019,8 +1018,7 @@ PRAGMA_WARNING_DISABLE_VS(4355) boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name); boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); acceptor_ipv6.open(endpoint.protocol()); - // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). - acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::linger(true, 0)); acceptor_ipv6.set_option(boost::asio::ip::v6_only(true)); acceptor_ipv6.bind(endpoint); acceptor_ipv6.listen(); diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h index 41f01e9a0..5774c0ba7 100644 --- a/contrib/epee/include/net/levin_protocol_handler_async.h +++ b/contrib/epee/include/net/levin_protocol_handler_async.h @@ -272,6 +272,11 @@ public: bool add_invoke_response_handler(const callback_t &cb, uint64_t timeout, async_protocol_handler& con, int command) { CRITICAL_REGION_LOCAL(m_invoke_response_handlers_lock); + if (m_protocol_released) + { + MERROR("Adding response handler to a released object"); + return false; + } boost::shared_ptr<invoke_response_handler_base> handler(boost::make_shared<anvoke_handler<callback_t>>(cb, timeout, con, command)); m_invoke_response_handlers.push_back(handler); return handler->is_timer_started(); diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h index 3d7200fae..f5f663464 100644 --- a/src/cryptonote_basic/verification_context.h +++ b/src/cryptonote_basic/verification_context.h @@ -58,5 +58,6 @@ namespace cryptonote bool m_marked_as_orphaned; bool m_already_exists; bool m_partial_block_reward; + bool m_bad_pow; // if bad pow, bad peer outright for DoS protection }; } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index b672ccd6e..e3450491b 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1723,6 +1723,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id { MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff); bvc.m_verifivation_failed = true; + bvc.m_bad_pow = true; return false; } @@ -3431,7 +3432,8 @@ uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const } const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT; - uint64_t fee = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_effective_median_block_weight : median, version); + const uint64_t use_median_value = use_long_term_median_in_fee ? std::min<uint64_t>(median, m_long_term_effective_median_block_weight) : median; + const uint64_t fee = get_dynamic_base_fee(base_reward, use_median_value, version); const bool per_byte = version < HF_VERSION_PER_BYTE_FEE; MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/" << (per_byte ? "byte" : "kB")); return fee; @@ -3749,6 +3751,7 @@ leave: { MERROR_VER("Block with id: " << id << std::endl << "does not have enough proof of work: " << proof_of_work << " at height " << blockchain_height << ", unexpected difficulty: " << current_diffic); bvc.m_verifivation_failed = true; + bvc.m_bad_pow = true; goto leave; } } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 0b7e5c199..3a6a3833d 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -911,7 +911,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- - bool tx_memory_pool::check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const + bool tx_memory_pool::check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool>& spent) const { CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 895014d17..99182cd0d 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -301,7 +301,7 @@ namespace cryptonote * * @return true */ - bool check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool> spent) const; + bool check_for_key_images(const std::vector<crypto::key_image>& key_images, std::vector<bool>& spent) const; /** * @brief get a specific transaction from the pool diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 2666733da..b16b42564 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -139,6 +139,7 @@ namespace cryptonote bool should_download_next_span(cryptonote_connection_context& context, bool standby); bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const; void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); + void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans); bool kick_idle_peers(); bool check_standby_peers(); bool update_sync_search(); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 91bcd86cc..bc5c8d6de 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -477,7 +477,7 @@ namespace cryptonote if(bvc.m_verifivation_failed) { LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection"); - drop_connection(context, true, false); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, false); return 1; } if(bvc.m_added_to_main_chain) @@ -751,7 +751,7 @@ namespace cryptonote if( bvc.m_verifivation_failed ) { LOG_PRINT_CCONTEXT_L0("Block verification failed, dropping connection"); - drop_connection(context, true, false); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, false); return 1; } if( bvc.m_added_to_main_chain ) @@ -1374,7 +1374,7 @@ namespace cryptonote { if (!m_p2p->for_connection(span_connection_id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{ LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); - drop_connection(context, true, true); + drop_connection_with_score(context, bvc.m_bad_pow ? P2P_IP_FAILS_BEFORE_BLOCK : 1, true); return 1; })) LOG_ERROR_CCONTEXT("span connection id not found"); @@ -2428,14 +2428,14 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> - void t_cryptonote_protocol_handler<t_core>::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans) + void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans) { LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) << - "), add_fail " << add_fail << ", flush_all_spans " << flush_all_spans); + "), score " << score << ", flush_all_spans " << flush_all_spans); - if (add_fail) - m_p2p->add_host_fail(context.m_remote_address); + if (score > 0) + m_p2p->add_host_fail(context.m_remote_address, score); m_block_queue.flush_spans(context.m_connection_id, flush_all_spans); @@ -2443,6 +2443,12 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> + void t_cryptonote_protocol_handler<t_core>::drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans) + { + return drop_connection_with_score(context, add_fail ? 1 : 0, flush_all_spans); + } + //------------------------------------------------------------------------------------------------------------------------ + template<class t_core> void t_cryptonote_protocol_handler<t_core>::on_connection_close(cryptonote_connection_context &context) { uint64_t target = 0; diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index c7fc058ca..ae23bb7fd 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -152,7 +152,7 @@ namespace nodetool const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"}; const command_line::arg_descriptor<std::string> arg_igd = {"igd", "UPnP port mapping (disabled, enabled, delayed)", "delayed"}; const command_line::arg_descriptor<bool> arg_p2p_use_ipv6 = {"p2p-use-ipv6", "Enable IPv6 for p2p", false}; - const command_line::arg_descriptor<bool> arg_p2p_require_ipv4 = {"p2p-require-ipv4", "Require successful IPv4 bind for p2p", true}; + const command_line::arg_descriptor<bool> arg_p2p_ignore_ipv4 = {"p2p-ignore-ipv4", "Ignore unsuccessful IPv4 bind for p2p", false}; const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1}; const command_line::arg_descriptor<int64_t> arg_in_peers = {"in-peers", "set max number of in peers", -1}; const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1}; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index d7e2e91f5..0c9c285e8 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -342,7 +342,7 @@ namespace nodetool virtual void request_callback(const epee::net_utils::connection_context_base& context); virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f); virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f); - virtual bool add_host_fail(const epee::net_utils::network_address &address); + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1); //----------------- i_connection_filter -------------------------------------------------------- virtual bool is_remote_host_allowed(const epee::net_utils::network_address &address, time_t *t = NULL); //----------------------------------------------------------------------------------------------- @@ -510,7 +510,7 @@ namespace nodetool extern const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port; extern const command_line::arg_descriptor<std::string, false, true, 2> arg_p2p_bind_port_ipv6; extern const command_line::arg_descriptor<bool> arg_p2p_use_ipv6; - extern const command_line::arg_descriptor<bool> arg_p2p_require_ipv4; + extern const command_line::arg_descriptor<bool> arg_p2p_ignore_ipv4; extern const command_line::arg_descriptor<uint32_t> arg_p2p_external_port; extern const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip; extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index bb77ea658..5fccdca5a 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -97,7 +97,7 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_bind_port, false); command_line::add_arg(desc, arg_p2p_bind_port_ipv6, false); command_line::add_arg(desc, arg_p2p_use_ipv6); - command_line::add_arg(desc, arg_p2p_require_ipv4); + command_line::add_arg(desc, arg_p2p_ignore_ipv4); command_line::add_arg(desc, arg_p2p_external_port); command_line::add_arg(desc, arg_p2p_allow_local_ip); command_line::add_arg(desc, arg_p2p_add_peer); @@ -315,13 +315,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::add_host_fail(const epee::net_utils::network_address &address) + bool node_server<t_payload_net_handler>::add_host_fail(const epee::net_utils::network_address &address, unsigned int score) { if(!address.is_blockable()) return false; CRITICAL_REGION_LOCAL(m_host_fails_score_lock); - uint64_t fails = ++m_host_fails_score[address.host_str()]; + uint64_t fails = m_host_fails_score[address.host_str()] += score; MDEBUG("Host " << address.host_str() << " fail score=" << fails); if(fails > P2P_IP_FAILS_BEFORE_BLOCK) { @@ -382,7 +382,7 @@ namespace nodetool } m_offline = command_line::get_arg(vm, cryptonote::arg_offline); m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6); - m_require_ipv4 = command_line::get_arg(vm, arg_p2p_require_ipv4); + m_require_ipv4 = !command_line::get_arg(vm, arg_p2p_ignore_ipv4); public_zone.m_notifier = cryptonote::levin::notify{ public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, true }; @@ -1864,7 +1864,11 @@ namespace nodetool const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>(); if (ipv4.ip() == 0) ignore = true; + else if (ipv4.port() == be.rpc_port) + ignore = true; } + if (be.pruning_seed && (be.pruning_seed < tools::make_pruning_seed(1, CRYPTONOTE_PRUNING_LOG_STRIPES) || be.pruning_seed > tools::make_pruning_seed(1ul << CRYPTONOTE_PRUNING_LOG_STRIPES, CRYPTONOTE_PRUNING_LOG_STRIPES))) + ignore = true; if (ignore) { MDEBUG("Ignoring " << be.adr.str()); diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index e0046cd86..752873666 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -60,7 +60,7 @@ namespace nodetool virtual bool unblock_host(const epee::net_utils::network_address &address)=0; virtual std::map<std::string, time_t> get_blocked_hosts()=0; virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0; - virtual bool add_host_fail(const epee::net_utils::network_address &address)=0; + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score = 1)=0; virtual void add_used_stripe_peer(const t_connection_context &context)=0; virtual void remove_used_stripe_peer(const t_connection_context &context)=0; virtual void clear_used_stripe_peers()=0; @@ -122,7 +122,7 @@ namespace nodetool { return std::map<epee::net_utils::ipv4_network_subnet, time_t>(); } - virtual bool add_host_fail(const epee::net_utils::network_address &address) + virtual bool add_host_fail(const epee::net_utils::network_address &address, unsigned int score) { return true; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index fef86fd34..6f5f912cd 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -217,13 +217,13 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::add_host_fail(const connection_context *ctx) + bool core_rpc_server::add_host_fail(const connection_context *ctx, unsigned int score) { if(!ctx || !ctx->m_remote_address.is_blockable()) return false; CRITICAL_REGION_LOCAL(m_host_fails_score_lock); - uint64_t fails = ++m_host_fails_score[ctx->m_remote_address.host_str()]; + uint64_t fails = m_host_fails_score[ctx->m_remote_address.host_str()] += score; MDEBUG("Host " << ctx->m_remote_address.host_str() << " fail score=" << fails); if(fails > RPC_IP_FAILS_BEFORE_BLOCK) { diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 379f6ed28..fe03012b7 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -241,7 +241,7 @@ namespace cryptonote private: bool check_core_busy(); bool check_core_ready(); - bool add_host_fail(const connection_context *ctx); + bool add_host_fail(const connection_context *ctx, unsigned int score = 1); //utils uint64_t get_block_reward(const block& blk); diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp index 68b33cb8c..0eaa0ef0e 100644 --- a/src/rpc/rpc_args.cpp +++ b/src/rpc/rpc_args.cpp @@ -92,7 +92,7 @@ namespace cryptonote : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"}) , rpc_bind_ipv6_address({"rpc-bind-ipv6-address", rpc_args::tr("Specify IPv6 address to bind RPC server"), "::1"}) , rpc_use_ipv6({"rpc-use-ipv6", rpc_args::tr("Allow IPv6 for RPC"), false}) - , rpc_require_ipv4({"rpc-require-ipv4", rpc_args::tr("Require successful IPv4 bind for RPC"), true}) + , rpc_ignore_ipv4({"rpc-ignore-ipv4", rpc_args::tr("Ignore unsuccessful IPv4 bind for RPC"), false}) , rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true}) , confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")}) , rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""}) @@ -113,7 +113,7 @@ namespace cryptonote command_line::add_arg(desc, arg.rpc_bind_ip); command_line::add_arg(desc, arg.rpc_bind_ipv6_address); command_line::add_arg(desc, arg.rpc_use_ipv6); - command_line::add_arg(desc, arg.rpc_require_ipv4); + command_line::add_arg(desc, arg.rpc_ignore_ipv4); command_line::add_arg(desc, arg.rpc_login); command_line::add_arg(desc, arg.confirm_external_bind); command_line::add_arg(desc, arg.rpc_access_control_origins); @@ -135,7 +135,7 @@ namespace cryptonote config.bind_ip = command_line::get_arg(vm, arg.rpc_bind_ip); config.bind_ipv6_address = command_line::get_arg(vm, arg.rpc_bind_ipv6_address); config.use_ipv6 = command_line::get_arg(vm, arg.rpc_use_ipv6); - config.require_ipv4 = command_line::get_arg(vm, arg.rpc_require_ipv4); + config.require_ipv4 = !command_line::get_arg(vm, arg.rpc_ignore_ipv4); if (!config.bind_ip.empty()) { // always parse IP here for error consistency diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h index cd154a4d0..bdb9c70d5 100644 --- a/src/rpc/rpc_args.h +++ b/src/rpc/rpc_args.h @@ -54,7 +54,7 @@ namespace cryptonote const command_line::arg_descriptor<std::string> rpc_bind_ip; const command_line::arg_descriptor<std::string> rpc_bind_ipv6_address; const command_line::arg_descriptor<bool> rpc_use_ipv6; - const command_line::arg_descriptor<bool> rpc_require_ipv4; + const command_line::arg_descriptor<bool> rpc_ignore_ipv4; const command_line::arg_descriptor<std::string> rpc_login; const command_line::arg_descriptor<bool> confirm_external_bind; const command_line::arg_descriptor<std::string> rpc_access_control_origins; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f07d142fb..0174104be 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -119,12 +119,10 @@ typedef cryptonote::simple_wallet sw; #define LONG_PAYMENT_ID_SUPPORT_CHECK() \ do { \ - if (!m_long_payment_id_support) { \ - fail_msg_writer() << tr("Warning: Long payment IDs are obsolete."); \ - fail_msg_writer() << tr("Long payment IDs are not encrypted on the blockchain, and will harm your privacy."); \ - fail_msg_writer() << tr("Use --long-payment-id-support-bad-for-privacy if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \ - return true; \ - } \ + fail_msg_writer() << tr("Error: Long payment IDs are obsolete."); \ + fail_msg_writer() << tr("Long payment IDs were not encrypted on the blockchain and would harm your privacy."); \ + fail_msg_writer() << tr("If the party you're sending to still requires a long payment ID, please notify them."); \ + return true; \ } while(0) enum TransferType { @@ -155,7 +153,6 @@ namespace const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false}; const command_line::arg_descriptor<std::string> arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet2::tr("Set subaddress lookahead sizes to <major>:<minor>"), ""}; const command_line::arg_descriptor<bool> arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false}; - const command_line::arg_descriptor<bool> arg_long_payment_id_support = {"long-payment-id-support-bad-for-privacy", sw::tr("Support obsolete long (unencrypted) payment ids (using them harms your privacy)"), false}; const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""}; @@ -2157,8 +2154,8 @@ bool simple_wallet::welcome(const std::vector<std::string> &args) message_writer() << tr("Welcome to Monero, the private cryptocurrency."); message_writer() << ""; message_writer() << tr("Monero, like Bitcoin, is a cryptocurrency. That is, it is digital money."); - message_writer() << tr("Unlike Bitcoin, your Monero transactions and balance stay private, and not visible to the world by default."); - message_writer() << tr("However, you have the option of making those available to select parties, if you choose to."); + message_writer() << tr("Unlike Bitcoin, your Monero transactions and balance stay private and are not visible to the world by default."); + message_writer() << tr("However, you have the option of making those available to select parties if you choose to."); message_writer() << ""; message_writer() << tr("Monero protects your privacy on the blockchain, and while Monero strives to improve all the time,"); message_writer() << tr("no privacy technology can be 100% perfect, Monero included."); @@ -2166,7 +2163,7 @@ bool simple_wallet::welcome(const std::vector<std::string> &args) message_writer() << tr("Flaws in Monero may be discovered in the future, and attacks may be developed to peek under some"); message_writer() << tr("of the layers of privacy Monero provides. Be safe and practice defense in depth."); message_writer() << ""; - message_writer() << tr("Welcome to Monero and financial privacy. For more information, see https://getmonero.org/"); + message_writer() << tr("Welcome to Monero and financial privacy. For more information see https://GetMonero.org"); return true; } @@ -2406,21 +2403,6 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st return true; } -bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/) -{ - LONG_PAYMENT_ID_SUPPORT_CHECK(); - - const auto pwd_container = get_and_verify_password(); - if (pwd_container) - { - parse_bool_and_use(args[1], [&](bool r) { - m_wallet->confirm_missing_payment_id(r); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); - }); - } - return true; -} - bool simple_wallet::set_ask_password(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { const auto pwd_container = get_and_verify_password(); @@ -2677,6 +2659,43 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string> return true; } + +bool simple_wallet::set_ignore_outputs_above(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + uint64_t amount; + if (!cryptonote::parse_amount(amount, args[1])) + { + fail_msg_writer() << tr("Invalid amount"); + return true; + } + if (amount == 0) + amount = MONEY_SUPPLY; + m_wallet->ignore_outputs_above(amount); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + } + return true; +} + +bool simple_wallet::set_ignore_outputs_below(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + uint64_t amount; + if (!cryptonote::parse_amount(amount, args[1])) + { + fail_msg_writer() << tr("Invalid amount"); + return true; + } + m_wallet->ignore_outputs_below(amount); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + } + return true; +} + bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { const auto pwd_container = get_and_verify_password(); @@ -2991,6 +3010,10 @@ simple_wallet::simple_wallet() " Set to the height of a key reusing fork you want to use, 0 to use default.\n " "ignore-fractional-outputs <1|0>\n " " Whether to ignore fractional outputs that result in net loss when spending due to fee.\n " + "ignore-outputs-above <amount>\n " + " Ignore outputs of amount above this threshold when spending. Value 0 is translated to the maximum value (18 million) which disables this filter.\n " + "ignore-outputs-below <amount>\n " + " Ignore outputs of amount below this threshold when spending.\n " "track-uses <1|0>\n " " Whether to keep track of owned outputs uses.\n " "setup-background-mining <1|0>\n " @@ -3351,7 +3374,6 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh(); success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type()); success_msg_writer() << "priority = " << priority<< " (" << priority_string << ")"; - success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id(); success_msg_writer() << "ask-password = " << m_wallet->ask_password() << " (" << ask_password_string << ")"; success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point()); success_msg_writer() << "min-outputs-count = " << m_wallet->get_min_output_count(); @@ -3368,6 +3390,8 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second; success_msg_writer() << "segregation-height = " << m_wallet->segregation_height(); success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs(); + success_msg_writer() << "ignore-outputs-above = " << cryptonote::print_money(m_wallet->ignore_outputs_above()); + success_msg_writer() << "ignore-outputs-below = " << cryptonote::print_money(m_wallet->ignore_outputs_below()); success_msg_writer() << "track-uses = " << m_wallet->track_uses(); success_msg_writer() << "setup-background-mining = " << setup_background_mining_string; success_msg_writer() << "device-name = " << m_wallet->device_name(); @@ -3416,7 +3440,6 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)")); CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", ")); - CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0|1|2 (or never|action|decrypt)")); CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("monero, millinero, micronero, nanonero, piconero")); CHECK_SIMPLE_VARIABLE("min-outputs-count", set_min_output_count, tr("unsigned integer")); @@ -3432,6 +3455,8 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>")); CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer")); CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1")); + CHECK_SIMPLE_VARIABLE("ignore-outputs-above", set_ignore_outputs_above, tr("amount")); + CHECK_SIMPLE_VARIABLE("ignore-outputs-below", set_ignore_outputs_below, tr("amount")); CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("inactivity-lock-timeout", set_inactivity_lock_timeout, tr("unsigned integer (seconds, 0 to disable)")); CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no")); @@ -4231,14 +4256,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (welcome) message_writer(console_color_yellow, true) << tr("If you are new to Monero, type \"welcome\" for a brief overview."); - if (m_long_payment_id_support) - { - message_writer(console_color_red, false) << - tr("WARNING: obsolete long payment IDs are enabled. Sending transactions with those payment IDs are bad for your privacy."); - message_writer(console_color_red, false) << - tr("It is recommended that you do not use them, and ask recipients who ask for one to not endanger your privacy."); - } - m_last_activity_time = time(NULL); return true; } @@ -4272,7 +4289,6 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay); m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead); m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names); - m_long_payment_id_support = command_line::get_arg(vm, arg_long_payment_id_support); m_restoring = !m_generate_from_view_key.empty() || !m_generate_from_spend_key.empty() || !m_generate_from_keys.empty() || @@ -5103,9 +5119,16 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { crypto::hash payment_id = crypto::null_hash; - if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + crypto::hash8 payment_id8 = crypto::null_hash8; + if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + { + if (payment_id8 != crypto::null_hash8) + message_writer() << + tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead"); + } + else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) message_writer(console_color_red, false) << - (m_long_payment_id_support ? tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead.") : tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete. Support will be withdrawn in the future. Use subaddresses instead.")); + tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete and ignored. Use subaddresses instead."); } } if (unlock_time) @@ -6061,20 +6084,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri dsts.push_back(de); } - // prompt is there is no payment id and confirmation is required - if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses) - { - std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true); - if (std::cin.eof()) - return false; - if (!command_line::is_yes(accepted)) - { - fail_msg_writer() << tr("transaction cancelled."); - - return false; - } - } - SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return false;); try @@ -6636,20 +6645,6 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st payment_id_seen = true; } - // prompt is there is no payment id and confirmation is required - if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress) - { - std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true); - if (std::cin.eof()) - return true; - if (!command_line::is_yes(accepted)) - { - fail_msg_writer() << tr("transaction cancelled."); - - return true; - } - } - SCOPED_WALLET_UNLOCK(); try @@ -6908,22 +6903,6 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) payment_id_seen = true; } - // prompt if there is no payment id and confirmation is required - if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress) - { - std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true); - if (std::cin.eof()) - return true; - if (!command_line::is_yes(accepted)) - { - fail_msg_writer() << tr("transaction cancelled."); - - // would like to return false, because no tx made, but everything else returns true - // and I don't know what returning false might adversely affect. *sigh* - return true; - } - } - SCOPED_WALLET_UNLOCK(); try @@ -9744,7 +9723,6 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_create_address_file); command_line::add_arg(desc_params, arg_subaddress_lookahead); command_line::add_arg(desc_params, arg_use_english_language_names); - command_line::add_arg(desc_params, arg_long_payment_id_support); po::positional_options_description positional_options; positional_options.add(arg_command.name, -1); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 22659e99e..47e08ca87 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -144,6 +144,8 @@ namespace cryptonote bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>()); bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>()); bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>()); + bool set_ignore_outputs_above(const std::vector<std::string> &args = std::vector<std::string>()); + bool set_ignore_outputs_below(const std::vector<std::string> &args = std::vector<std::string>()); bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>()); bool set_inactivity_lock_timeout(const std::vector<std::string> &args = std::vector<std::string>()); bool set_setup_background_mining(const std::vector<std::string> &args = std::vector<std::string>()); @@ -430,8 +432,6 @@ namespace cryptonote std::atomic<bool> m_in_manual_refresh; uint32_t m_current_subaddress_account; - bool m_long_payment_id_support; - std::atomic<time_t> m_last_activity_time; std::atomic<bool> m_locked; std::atomic<bool> m_in_command; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4f7b6bbd3..c7374b896 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -137,6 +137,8 @@ using namespace cryptonote; #define DEFAULT_INACTIVITY_LOCK_TIMEOUT 90 // a minute and a half +#define IGNORE_LONG_PAYMENT_ID_FROM_BLOCK_VERSION 12 + static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1"; static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1"; @@ -1113,7 +1115,6 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended): m_first_refresh_done(false), m_refresh_from_block_height(0), m_explicit_refresh_from_block_height(true), - m_confirm_missing_payment_id(true), m_confirm_non_default_ring_size(true), m_ask_password(AskPasswordToDecrypt), m_min_output_count(0), @@ -1127,6 +1128,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended): m_key_reuse_mitigation2(true), m_segregation_height(0), m_ignore_fractional_outputs(true), + m_ignore_outputs_above(MONEY_SUPPLY), + m_ignore_outputs_below(0), m_track_uses(false), m_inactivity_lock_timeout(DEFAULT_INACTIVITY_LOCK_TIMEOUT), m_setup_background_mining(BackgroundMiningMaybe), @@ -1793,7 +1796,7 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has } } //---------------------------------------------------------------------------------------------------- -void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache) +void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache) { PERF_TIMER(process_new_transaction); // In this function, tx (probably) only contains the base information @@ -2285,8 +2288,18 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { - LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); - MWARNING("Found unencrypted payment ID: these are bad for privacy, consider using subaddresses instead"); + bool ignore = block_version >= IGNORE_LONG_PAYMENT_ID_FROM_BLOCK_VERSION; + if (ignore) + { + LOG_PRINT_L2("Found unencrypted payment ID in tx " << txid << " (ignored)"); + MWARNING("Found OBSOLETE AND IGNORED unencrypted payment ID: these are bad for privacy, use subaddresses instead"); + payment_id = crypto::null_hash; + } + else + { + LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); + MWARNING("Found unencrypted payment ID: these are bad for privacy, consider using subaddresses instead"); + } } } @@ -2422,7 +2435,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry { TIME_MEASURE_START(miner_tx_handle_time); if (m_refresh_type != RefreshNoCoinbase) - process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache); + process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.major_version, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache); ++tx_cache_data_offset; TIME_MEASURE_FINISH(miner_tx_handle_time); @@ -2431,7 +2444,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block"); for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx) { - process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache); + process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.major_version, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache); } TIME_MEASURE_FINISH(txs_handle_time); m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx); @@ -2962,7 +2975,7 @@ void wallet2::update_pool_state(bool refreshed) [tx_hash](const std::pair<crypto::hash, bool> &e) { return e.first == tx_hash; }); if (i != txids.end()) { - process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true, tx_entry.double_spend_seen, {}); + process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, 0, time(NULL), false, true, tx_entry.double_spend_seen, {}); m_scanned_pool_txs[0].insert(tx_hash); if (m_scanned_pool_txs[0].size() > 5000) { @@ -3639,9 +3652,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetUint64(m_refresh_from_block_height); json.AddMember("refresh_height", value2, json.GetAllocator()); - value2.SetInt(m_confirm_missing_payment_id ? 1 :0); - json.AddMember("confirm_missing_payment_id", value2, json.GetAllocator()); - value2.SetInt(m_confirm_non_default_ring_size ? 1 :0); json.AddMember("confirm_non_default_ring_size", value2, json.GetAllocator()); @@ -3687,6 +3697,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetInt(m_ignore_fractional_outputs ? 1 : 0); json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator()); + value2.SetUint64(m_ignore_outputs_above); + json.AddMember("ignore_outputs_above", value2, json.GetAllocator()); + + value2.SetUint64(m_ignore_outputs_below); + json.AddMember("ignore_outputs_below", value2, json.GetAllocator()); + value2.SetInt(m_track_uses ? 1 : 0); json.AddMember("track_uses", value2, json.GetAllocator()); @@ -3833,7 +3849,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_auto_refresh = true; m_refresh_type = RefreshType::RefreshDefault; m_refresh_from_block_height = 0; - m_confirm_missing_payment_id = true; m_confirm_non_default_ring_size = true; m_ask_password = AskPasswordToDecrypt; cryptonote::set_default_decimal_point(CRYPTONOTE_DISPLAY_DECIMAL_POINT); @@ -3848,6 +3863,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_key_reuse_mitigation2 = true; m_segregation_height = 0; m_ignore_fractional_outputs = true; + m_ignore_outputs_above = MONEY_SUPPLY; + m_ignore_outputs_below = 0; m_track_uses = false; m_inactivity_lock_timeout = DEFAULT_INACTIVITY_LOCK_TIMEOUT; m_setup_background_mining = BackgroundMiningMaybe; @@ -3968,8 +3985,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_height, uint64_t, Uint64, false, 0); m_refresh_from_block_height = field_refresh_height; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_missing_payment_id, int, Int, false, true); - m_confirm_missing_payment_id = field_confirm_missing_payment_id; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_non_default_ring_size, int, Int, false, true); m_confirm_non_default_ring_size = field_confirm_non_default_ring_size; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, AskPasswordType, Int, false, AskPasswordToDecrypt); @@ -4004,6 +4019,10 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_segregation_height = field_segregation_height; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true); m_ignore_fractional_outputs = field_ignore_fractional_outputs; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_outputs_above, uint64_t, Uint64, false, MONEY_SUPPLY); + m_ignore_outputs_above = field_ignore_outputs_above; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_outputs_below, uint64_t, Uint64, false, 0); + m_ignore_outputs_below = field_ignore_outputs_below; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false); m_track_uses = field_track_uses; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, inactivity_lock_timeout, uint32_t, Uint, false, DEFAULT_INACTIVITY_LOCK_TIMEOUT); @@ -5570,6 +5589,11 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas const std::string address_file = m_wallet_file + ".address.txt"; r = save_to_file(address_file, m_account.get_public_address_str(m_nettype), true); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); + // remove old address file + r = boost::filesystem::remove(old_address_file); + if (!r) { + LOG_ERROR("error removing file: " << old_address_file); + } } // remove old wallet file r = boost::filesystem::remove(old_file); @@ -5581,11 +5605,6 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas if (!r) { LOG_ERROR("error removing file: " << old_keys_file); } - // remove old address file - r = boost::filesystem::remove(old_address_file); - if (!r) { - LOG_ERROR("error removing file: " << old_address_file); - } // remove old message store file if (boost::filesystem::exists(old_mms_file)) { @@ -8599,6 +8618,11 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui const transfer_details& td = m_transfers[i]; if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) { + if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]"); + continue; + } LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount())); picks.push_back(i); return picks; @@ -8614,10 +8638,20 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui const transfer_details& td = m_transfers[i]; if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) { + if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]"); + continue; + } LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount())); for (size_t j = i + 1; j < m_transfers.size(); ++j) { const transfer_details& td2 = m_transfers[j]; + if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below) + { + MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]"); + continue; + } if (!is_spent(td2, false) && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index) { // update our picks if those outputs are less related than any we @@ -9317,11 +9351,16 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp const transfer_details& td = m_transfers[i]; if (m_ignore_fractional_outputs && td.amount() < fractional_threshold) { - MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold)); + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below fractional threshold " << print_money(fractional_threshold)); continue; } if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) { + if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]"); + continue; + } const uint32_t index_minor = td.m_subaddr_index.minor; auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; }; if ((td.is_rct()) || is_valid_decomposed_amount(td.amount())) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1469b4c00..52118c426 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1019,8 +1019,6 @@ private: void set_default_priority(uint32_t p) { m_default_priority = p; } bool auto_refresh() const { return m_auto_refresh; } void auto_refresh(bool r) { m_auto_refresh = r; } - bool confirm_missing_payment_id() const { return m_confirm_missing_payment_id; } - void confirm_missing_payment_id(bool always) { m_confirm_missing_payment_id = always; } AskPasswordType ask_password() const { return m_ask_password; } void ask_password(AskPasswordType ask) { m_ask_password = ask; } void set_min_output_count(uint32_t count) { m_min_output_count = count; } @@ -1047,6 +1045,10 @@ private: void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; } bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; } void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; } + uint64_t ignore_outputs_above() const { return m_ignore_outputs_above; } + void ignore_outputs_above(uint64_t value) { m_ignore_outputs_above = value; } + uint64_t ignore_outputs_below() const { return m_ignore_outputs_below; } + void ignore_outputs_below(uint64_t value) { m_ignore_outputs_below = value; } bool track_uses() const { return m_track_uses; } void track_uses(bool value) { m_track_uses = value; } BackgroundMiningSetupType setup_background_mining() const { return m_setup_background_mining; } @@ -1351,7 +1353,7 @@ private: * \param password Password of wallet file */ bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password); - void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); + void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); bool should_skip_block(const cryptonote::block &b, uint64_t height) const; void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); void detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL); @@ -1496,7 +1498,6 @@ private: // If m_refresh_from_block_height is explicitly set to zero we need this to differentiate it from the case that // m_refresh_from_block_height was defaulted to zero.*/ bool m_explicit_refresh_from_block_height; - bool m_confirm_missing_payment_id; bool m_confirm_non_default_ring_size; AskPasswordType m_ask_password; uint32_t m_min_output_count; @@ -1510,6 +1511,8 @@ private: bool m_key_reuse_mitigation2; uint64_t m_segregation_height; bool m_ignore_fractional_outputs; + uint64_t m_ignore_outputs_above; + uint64_t m_ignore_outputs_below; bool m_track_uses; uint32_t m_inactivity_lock_timeout; BackgroundMiningSetupType m_setup_background_mining; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 0e0221c03..dbd42ab81 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -793,30 +793,9 @@ namespace tools if (!payment_id.empty()) { - - /* Just to clarify */ - const std::string& payment_id_str = payment_id; - - crypto::hash long_payment_id; - crypto::hash8 short_payment_id; - - /* Parse payment ID */ - if (wallet2::parse_long_payment_id(payment_id_str, long_payment_id)) { - cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id); - } - else { - er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; - er.message = "Payment id has invalid format: \"" + payment_id_str + "\", expected 64 character string"; - return false; - } - - /* Append Payment ID data into extra */ - if (!cryptonote::add_extra_nonce_to_tx_extra(extra, extra_nonce)) { - er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; - er.message = "Something went wrong with payment_id. Please check its format: \"" + payment_id_str + "\", expected 64-character string"; - return false; - } - + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead"; + return false; } return true; } @@ -1003,6 +982,13 @@ namespace tools std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); LOG_PRINT_L2("on_transfer_split called create_transactions_2"); + if (ptx_vector.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No transaction created"; + return false; + } + return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er); } @@ -1194,8 +1180,11 @@ namespace tools crypto::hash payment_id; if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { - desc.payment_id = epee::string_tools::pod_to_hex(payment_id8); - has_encrypted_payment_id = true; + if (payment_id8 != crypto::null_hash8) + { + desc.payment_id = epee::string_tools::pod_to_hex(payment_id8); + has_encrypted_payment_id = true; + } } else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { diff --git a/tests/functional_tests/cold_signing.py b/tests/functional_tests/cold_signing.py index f915df77a..698217436 100755 --- a/tests/functional_tests/cold_signing.py +++ b/tests/functional_tests/cold_signing.py @@ -94,7 +94,6 @@ class ColdSigningTest(): print("Creating transaction in hot wallet") dst = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} - payment_id = '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde' self.hot_wallet.refresh() res = self.hot_wallet.export_outputs() @@ -102,7 +101,7 @@ class ColdSigningTest(): res = self.cold_wallet.export_key_images(True) self.hot_wallet.import_key_images(res.signed_key_images, offset = res.offset) - res = self.hot_wallet.transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False) + res = self.hot_wallet.transfer([dst], ring_size = 11, get_tx_key = False) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 0 @@ -124,7 +123,7 @@ class ColdSigningTest(): assert desc.amount_out == desc.amount_in - fee assert desc.ring_size == 11 assert desc.unlock_time == 0 - assert desc.payment_id == payment_id + assert desc.payment_id in ['', '0000000000000000'] assert desc.change_amount == desc.amount_in - 1000000000000 - fee assert desc.change_address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert desc.fee == fee diff --git a/tests/functional_tests/multisig.py b/tests/functional_tests/multisig.py index e0d8b06a4..e4e908aa1 100755 --- a/tests/functional_tests/multisig.py +++ b/tests/functional_tests/multisig.py @@ -272,7 +272,7 @@ class MultisigTest(): assert desc.amount_out == desc.amount_in - fee assert desc.ring_size == 11 assert desc.unlock_time == 0 - assert desc.payment_id == '0000000000000000' + assert not 'payment_id' in desc or desc.payment_id in ['', '0000000000000000'] assert desc.change_amount == desc.amount_in - 1000000000000 - fee assert desc.change_address == self.wallet_address assert desc.fee == fee diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py index b4264f72d..a4f9b9e22 100755 --- a/tests/functional_tests/transfer.py +++ b/tests/functional_tests/transfer.py @@ -114,13 +114,19 @@ class TransferTest(): except: ok = True assert ok + print ('Checking long payment IDs are rejected') + ok = False + try: self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False, get_tx_hex = True) + except: ok = True + assert ok + print ('Checking empty destination is rejected') ok = False try: self.wallet[0].transfer([], ring_size = 11, get_tx_key = False) except: ok = True assert ok - res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False, get_tx_hex = True) + res = self.wallet[0].transfer([dst], ring_size = 11, get_tx_key = False, get_tx_hex = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 0 @@ -156,7 +162,7 @@ class TransferTest(): assert e.type == 'block' e = res.pending[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ['', '0000000000000000'] assert e.type == 'pending' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -189,7 +195,7 @@ class TransferTest(): assert e.type == 'block' e = res.out[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ['', '0000000000000000'] assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -205,7 +211,7 @@ class TransferTest(): assert res.transfers[0] == res.transfer t = res.transfer assert t.txid == txid - assert t.payment_id == payment_id + assert t.payment_id in ['', '0000000000000000'] assert t.height == wallet_height - 1 assert t.timestamp > 0 assert t.amount == 0 # to self, so it's just "pay a fee" really @@ -227,7 +233,7 @@ class TransferTest(): print("Creating transfer to another, manual relay") dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1000000000000} - res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = True, do_not_relay = True, get_tx_hex = True) + res = self.wallet[0].transfer([dst], ring_size = 11, get_tx_key = True, do_not_relay = True, get_tx_hex = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 @@ -269,7 +275,7 @@ class TransferTest(): assert not 'failed' in res or len(res.failed) == 0 e = res.pool[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'pool' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -295,7 +301,7 @@ class TransferTest(): assert not 'failed' in res or len(res.failed) == 0 e = res['in'][0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -318,7 +324,7 @@ class TransferTest(): dst0 = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} dst1 = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1100000000000} dst2 = {'address': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 'amount': 1200000000000} - res = self.wallet[0].transfer([dst0, dst1, dst2], ring_size = 11, payment_id = payment_id, get_tx_key = True) + res = self.wallet[0].transfer([dst0, dst1, dst2], ring_size = 11, get_tx_key = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 @@ -357,7 +363,7 @@ class TransferTest(): assert len(e) == 1 e = e[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -385,7 +391,7 @@ class TransferTest(): assert len(e) == 1 e = e[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -412,7 +418,7 @@ class TransferTest(): assert len(e) == 1 e = e[0] assert e.txid == txid - assert e.payment_id == payment_id + assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 @@ -521,7 +527,7 @@ class TransferTest(): res = self.wallet[1].get_bulk_payments() assert len(res.payments) >= 3 # two txes to standard address were sent, plus one to integrated address res = self.wallet[1].get_bulk_payments(payment_ids = ['1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde']) - assert len(res.payments) >= 2 # two txes were sent with that payment id + assert not 'payments' in res or len(res.payments) == 0 # long payment IDs are now ignored on receipt res = self.wallet[1].get_bulk_payments(payment_ids = ['ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff']) assert 'payments' not in res or len(res.payments) == 0 # none with that payment id res = self.wallet[1].get_bulk_payments(payment_ids = ['1111111122222222' + '0'*48]) @@ -531,7 +537,7 @@ class TransferTest(): res = self.wallet[2].get_bulk_payments() assert len(res.payments) >= 1 # one tx was sent res = self.wallet[2].get_bulk_payments(payment_ids = ['1'*64, '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde', '2'*64]) - assert len(res.payments) >= 1 # one tx was sent + assert not 'payments' in res or len(res.payments) == 0 # long payment IDs are now ignored res = self.wallet[1].get_bulk_payments(["1111111122222222"]) assert len(res.payments) >= 1 # we have one of these diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index cac1fa943..96825f54f 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -30,7 +30,6 @@ set(unit_tests_sources account.cpp apply_permutation.cpp address_from_url.cpp - ban.cpp base58.cpp blockchain_db.cpp block_queue.cpp @@ -68,6 +67,7 @@ set(unit_tests_sources multiexp.cpp multisig.cpp net.cpp + node_server.cpp notify.cpp output_distribution.cpp parse_amount.cpp diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/node_server.cpp index 86d546387..2c89323c7 100644 --- a/tests/unit_tests/ban.cpp +++ b/tests/unit_tests/node_server.cpp @@ -260,5 +260,42 @@ TEST(ban, ignores_port) ASSERT_FALSE(is_blocked(server,MAKE_IPV4_ADDRESS_PORT(1,2,3,4,6))); } +TEST(node_server, bind_same_p2p_port) +{ + const auto new_node = []() -> std::unique_ptr<Server> { + test_core pr_core; + cryptonote::t_cryptonote_protocol_handler<test_core> cprotocol(pr_core, NULL); + std::unique_ptr<Server> server(new Server(cprotocol)); + cprotocol.set_p2p_endpoint(server.get()); + + return server; + }; + + const auto init = [](const std::unique_ptr<Server>& server, const char* port) -> bool { + boost::program_options::options_description desc_options("Command line options"); + cryptonote::core::init_options(desc_options); + Server::init_options(desc_options); + + const char *argv[2] = {nullptr, nullptr}; + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(1, argv, desc_options), vm); + + vm.find(nodetool::arg_p2p_bind_port.name)->second = boost::program_options::variable_value(std::string(port), false); + + boost::program_options::notify(vm); + + return server->init(vm); + }; + + constexpr char port[] = "48080"; + constexpr char port_another[] = "58080"; + + const auto node = new_node(); + EXPECT_TRUE(init(node, port)); + + EXPECT_FALSE(init(new_node(), port)); + EXPECT_TRUE(init(new_node(), port_another)); +} + namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; } namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; } |