diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/powerof.h | 26 | ||||
-rw-r--r-- | src/cryptonote_config.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 21 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 6 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.h | 4 | ||||
-rw-r--r-- | src/cryptonote_protocol/levin_notify.cpp | 27 | ||||
-rw-r--r-- | src/cryptonote_protocol/levin_notify.h | 2 | ||||
-rw-r--r-- | src/daemon/command_parser_executor.cpp | 300 | ||||
-rw-r--r-- | src/daemon/command_server.cpp | 4 | ||||
-rw-r--r-- | src/device/device_ledger.cpp | 43 | ||||
-rw-r--r-- | src/device/device_ledger.hpp | 65 | ||||
-rw-r--r-- | src/p2p/net_node.cpp | 1 | ||||
-rw-r--r-- | src/p2p/net_node.h | 24 | ||||
-rw-r--r-- | src/p2p/net_node.inl | 181 | ||||
-rw-r--r-- | src/rpc/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 9 | ||||
-rw-r--r-- | src/wallet/api/transaction_history.cpp | 17 | ||||
-rw-r--r-- | src/wallet/api/transaction_history.h | 1 | ||||
-rw-r--r-- | src/wallet/api/transaction_info.cpp | 11 | ||||
-rw-r--r-- | src/wallet/api/transaction_info.h | 4 | ||||
-rw-r--r-- | src/wallet/api/wallet2_api.h | 3 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 8 |
22 files changed, 495 insertions, 266 deletions
diff --git a/src/common/powerof.h b/src/common/powerof.h new file mode 100644 index 000000000..0f6c6254a --- /dev/null +++ b/src/common/powerof.h @@ -0,0 +1,26 @@ +#pragma once + +#include <stdint.h> + +namespace tools +{ + template<uint64_t a, uint64_t b> + struct PowerOf + { + enum Data : uint64_t + { + // a^b = a * a^(b-1) + Value = a * PowerOf<a, b - 1>::Value, + }; + }; + + template<uint64_t a> + struct PowerOf<a, 0> + { + enum Data : uint64_t + { + // a^0 = 1 + Value = 1, + }; + }; +} diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index a4db99f83..bc17b7e81 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -128,7 +128,7 @@ #define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000 #define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000 -#define P2P_DEFAULT_CONNECTIONS_COUNT 8 +#define P2P_DEFAULT_CONNECTIONS_COUNT 12 #define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes #define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size #define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f91b3d6c1..ad27f1358 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3140,14 +3140,6 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr } } } - else if (rv.type == rct::RCTTypeCLSAG) - { - CHECK_AND_ASSERT_MES(rv.p.CLSAGs.size() == tx.vin.size(), false, "Bad CLSAGs size"); - for (size_t n = 0; n < tx.vin.size(); ++n) - { - rv.p.CLSAGs[n].I = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image); - } - } else { CHECK_AND_ASSERT_MES(false, false, "Unsupported rct tx type: " + boost::lexical_cast<std::string>(rv.type)); @@ -3629,19 +3621,6 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const } //------------------------------------------------------------------ -uint64_t Blockchain::get_fee_quantization_mask() -{ - static uint64_t mask = 0; - if (mask == 0) - { - mask = 1; - for (size_t n = PER_KB_FEE_QUANTIZATION_DECIMALS; n < CRYPTONOTE_DISPLAY_DECIMAL_POINT; ++n) - mask *= 10; - } - return mask; -} - -//------------------------------------------------------------------ uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version) { const uint64_t min_block_weight = get_min_block_weight(version); diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index a9b7ca1da..a8e251c71 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -51,6 +51,7 @@ #include "string_tools.h" #include "rolling_median.h" #include "cryptonote_basic/cryptonote_basic.h" +#include "common/powerof.h" #include "common/util.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "rpc/core_rpc_server_commands_defs.h" @@ -591,7 +592,10 @@ namespace cryptonote * * @return the fee quantized mask */ - static uint64_t get_fee_quantization_mask(); + static uint64_t get_fee_quantization_mask() + { + return tools::PowerOf<10, CRYPTONOTE_DISPLAY_DECIMAL_POINT - PER_KB_FEE_QUANTIZATION_DECIMALS>::Value; + } /** * @brief get dynamic per kB or byte fee for a given block weight diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 7c578ac51..b008d026e 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -224,14 +224,14 @@ namespace cryptonote * * @return true if the block was added to the main chain, otherwise false */ - virtual bool handle_block_found(block& b, block_verification_context &bvc); + virtual bool handle_block_found(block& b, block_verification_context &bvc) override; /** * @copydoc Blockchain::create_block_template * * @note see Blockchain::create_block_template */ - virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash); + virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) override; virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash); /** diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index dbd11e7d0..634750cab 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -233,7 +233,7 @@ namespace levin { struct zone { - explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, bool is_public, bool pad_txs) + explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs) : p2p(std::move(p2p)), noise(std::move(noise_in)), next_epoch(io_service), @@ -243,7 +243,7 @@ namespace levin channels(), flush_time(std::chrono::steady_clock::time_point::max()), connection_count(0), - is_public(is_public), + nzone(zone), pad_txs(pad_txs), fluffing(false) { @@ -260,7 +260,7 @@ namespace levin std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand` std::chrono::steady_clock::time_point flush_time; //!< Next expected Dandelion++ fluff flush std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time - const bool is_public; //!< Zone is public ipv4/ipv6 connections + const epee::net_utils::zone nzone; //!< Zone is public ipv4/ipv6 connections, or i2p or tor const bool pad_txs; //!< Pad txs to the next boundary for privacy bool fluffing; //!< Zone is in Dandelion++ fluff epoch }; @@ -297,7 +297,8 @@ namespace levin if (!channel.connection.is_nil()) channel.queue.push_back(std::move(message_)); else if (destination_ == 0 && zone_->connection_count == 0) - MWARNING("Unable to send transaction(s) over anonymity network - no available outbound connections"); + MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) << + " - no available outbound connections"); } }; @@ -410,7 +411,7 @@ namespace levin zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush, &available] (detail::p2p_context& context) { // When i2p/tor, only fluff to outbound connections - if (source != context.m_connection_id && (zone->is_public || !context.m_is_income)) + if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income)) { available = true; if (context.fluff_txs.empty()) @@ -577,7 +578,7 @@ namespace levin assert(zone_->strand.running_in_this_thread()); - if (zone_->is_public) + if (zone_->nzone == epee::net_utils::zone::public_) MDEBUG("Starting new Dandelion++ epoch: " << (fluffing_ ? "fluff" : "stem")); zone_->map = std::move(map_); @@ -645,10 +646,12 @@ namespace levin { channel.active = nullptr; channel.connection = boost::uuids::nil_uuid(); + auto height = core_->get_target_blockchain_height(); - auto connections = get_out_connections(*zone_->p2p, core_->get_target_blockchain_height()); + auto connections = get_out_connections(*zone_->p2p, height); if (connections.empty()) - MWARNING("Lost all outbound connections to anonymity network - currently unable to send transaction(s)"); + MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) << + " - no suitable outbound connections at height " << height); zone_->strand.post(update_channels{zone_, std::move(connections)}); } @@ -691,15 +694,15 @@ namespace levin }; } // anonymous - notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, const bool is_public, const bool pad_txs, i_core_events& core) - : zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), is_public, pad_txs)) + notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core) + : zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs)) , core_(std::addressof(core)) { if (!zone_->p2p) throw std::logic_error{"cryptonote::levin::notify cannot have nullptr p2p argument"}; const bool noise_enabled = !zone_->noise.empty(); - if (noise_enabled || is_public) + if (noise_enabled || zone == epee::net_utils::zone::public_) { const auto now = std::chrono::steady_clock::now(); const auto min_epoch = noise_enabled ? noise_min_epoch : dandelionpp_min_epoch; @@ -821,7 +824,7 @@ namespace levin case relay_method::stem: case relay_method::forward: case relay_method::local: - if (zone_->is_public) + if (zone_->nzone == epee::net_utils::zone::public_) { // this will change a local/forward tx to stem or fluff ... zone_->strand.dispatch( diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h index 43b61aead..abbf9d461 100644 --- a/src/cryptonote_protocol/levin_notify.h +++ b/src/cryptonote_protocol/levin_notify.h @@ -85,7 +85,7 @@ namespace levin {} //! Construct an instance with available notification `zones`. - explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, bool is_public, bool pad_txs, i_core_events& core); + explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core); notify(const notify&) = delete; notify(notify&&) = default; diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 504b104b0..aac891c4a 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -50,7 +50,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& { if (args.size() > 3) { - std::cout << "use: print_pl [white] [gray] [<limit>] [pruned] [publicrpc]" << std::endl; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; return true; } @@ -79,7 +79,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& } else if (!epee::string_tools::get_xtype_from_string(limit, args[i])) { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } @@ -90,56 +90,79 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& bool t_command_parser_executor::print_peer_list_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_peer_list_stats(); } bool t_command_parser_executor::save_blockchain(const std::vector<std::string>& args) { - if (!args.empty()) return false; - + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.save_blockchain(); } bool t_command_parser_executor::show_hash_rate(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_hash_rate(); } bool t_command_parser_executor::hide_hash_rate(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.hide_hash_rate(); } bool t_command_parser_executor::show_difficulty(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_difficulty(); } bool t_command_parser_executor::show_status(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.show_status(); } bool t_command_parser_executor::print_connections(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_connections(); } bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_net_stats(); } @@ -148,8 +171,8 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str { if(!args.size()) { - std::cout << "need block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } uint64_t start_index = 0; uint64_t end_index = 0; @@ -158,20 +181,20 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str int64_t nblocks; if(!epee::string_tools::get_xtype_from_string(nblocks, args[0])) { - std::cout << "wrong number of blocks" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_info(nblocks, (uint64_t)-nblocks); } if(!epee::string_tools::get_xtype_from_string(start_index, args[0])) { - std::cout << "wrong starter block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong starter block index parameter. For more details, use the help command." << std::endl; + return true; } if(args.size() >1 && !epee::string_tools::get_xtype_from_string(end_index, args[1])) { - std::cout << "wrong end block index parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong end block index parameter. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_info(start_index, end_index); @@ -181,7 +204,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar { if(args.size() > 1) { - std::cout << "use: set_log [<log_level_number_0-4> | <categories>]" << std::endl; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; return true; } @@ -195,7 +218,7 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar { if(4 < l) { - std::cout << "wrong number range, use: set_log <log_level_number_0-4>" << std::endl; + std::cout << "Invalid syntax: Wrong number range, use: set_log <log_level_number_0-4>. For more details, use the help command." << std::endl; return true; } return m_executor.set_log_level(l); @@ -208,7 +231,10 @@ bool t_command_parser_executor::set_log_level(const std::vector<std::string>& ar bool t_command_parser_executor::print_height(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_height(); } @@ -223,14 +249,14 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args include_hex = true; else { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } if (args.empty()) { - std::cout << "expected: print_block (<block_hash> | <block_height>) [+hex]" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } const std::string& arg = args.front(); @@ -248,7 +274,7 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args } } - return false; + return true; } bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args) @@ -267,13 +293,13 @@ bool t_command_parser_executor::print_transaction(const std::vector<std::string> include_json = true; else { - std::cout << "unexpected argument: " << args[i] << std::endl; + std::cout << "Invalid syntax: Unexpected parameter: " << args[i] << ". For more details, use the help command." << std::endl; return true; } } if (args.empty()) { - std::cout << "expected: print_tx <transaction_hash> [+meta] [+hex] [+json]" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -291,7 +317,7 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string { if (args.empty()) { - std::cout << "expected: is_key_image_spent <key_image>" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -309,21 +335,30 @@ bool t_command_parser_executor::is_key_image_spent(const std::vector<std::string bool t_command_parser_executor::print_transaction_pool_long(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_long(); } bool t_command_parser_executor::print_transaction_pool_short(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_short(); } bool t_command_parser_executor::print_transaction_pool_stats(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_transaction_pool_stats(); } @@ -332,7 +367,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg { if(!args.size()) { - std::cout << "Please specify a wallet address to mine for: start_mining <addr> [<threads>|auto]" << std::endl; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; return true; } @@ -353,7 +388,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg { if(!cryptonote::get_account_address_from_str(info, cryptonote::STAGENET, address_str)) { - std::cout << "target account address has wrong format" << std::endl; + std::cout << "Invalid syntax: Target account address has wrong format. For more details, use the help command." << std::endl; return true; } else @@ -389,9 +424,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg bool ignore_battery = false; if(args.size() > 4) { - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } - + if(args.size() == 4) { if(args[3] == "true" || command_line::is_yes(args[3]) || args[3] == "1") @@ -400,10 +436,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg } else if(args[3] != "false" && !command_line::is_no(args[3]) && args[3] != "0") { - return false; + std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl; + return true; } - } - + } + if(args.size() >= 3) { if(args[2] == "true" || command_line::is_yes(args[2]) || args[2] == "1") @@ -412,10 +449,11 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg } else if(args[2] != "false" && !command_line::is_no(args[2]) && args[2] != "0") { - return false; + std::cout << "Invalid syntax: Invalid combination of parameters. For more details, use the help command." << std::endl; + return true; } } - + if(args.size() >= 2) { if (args[1] == "auto" || args[1] == "autodetect") @@ -436,7 +474,10 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg bool t_command_parser_executor::stop_mining(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.stop_mining(); } @@ -448,21 +489,31 @@ bool t_command_parser_executor::mining_status(const std::vector<std::string>& ar bool t_command_parser_executor::stop_daemon(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.stop_daemon(); } bool t_command_parser_executor::print_status(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.print_status(); } bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit(); } @@ -471,8 +522,8 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(limit, limit); @@ -480,7 +531,11 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args) bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit_up(); } @@ -489,8 +544,8 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(0, limit); @@ -498,7 +553,11 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args) { - if(args.size()>1) return false; + if(args.size()>1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } + if(args.size()==0) { return m_executor.get_limit_down(); } @@ -507,8 +566,8 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a limit = std::stoll(args[0]); } catch(const std::exception& ex) { - std::cout << "failed to parse argument" << std::endl; - return false; + std::cout << "Invalid syntax: Failed to parse limit. For more details, use the help command." << std::endl; + return true; } return m_executor.set_limit(limit, 0); @@ -525,12 +584,13 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args) set = true; } } - + catch(const std::exception& ex) { _erro("stoi exception"); - return false; + std::cout << "Invalid syntax: Failed to parse number. For more details, use the help command." << std::endl; + return true; } - + return m_executor.out_peers(set, limit); } @@ -548,7 +608,8 @@ bool t_command_parser_executor::in_peers(const std::vector<std::string>& args) catch(const std::exception& ex) { _erro("stoi exception"); - return false; + std::cout << "Invalid syntax: Failed to parse number." << std::endl; + return true; } return m_executor.in_peers(set, limit); @@ -565,26 +626,37 @@ bool t_command_parser_executor::hard_fork_info(const std::vector<std::string>& a version = std::stoi(args[0]); } catch(const std::exception& ex) { - return false; + std::cout << "Invalid syntax: Failed to parse version number. For more details, use the help command." << std::endl; + return true; + } + if (version <= 0 || version > 255) { + std::cout << "Invalid syntax: Unknown version number. Must be between 0 and 255. For more details, use the help command." << std::endl; + return true; } - if (version <= 0 || version > 255) - return false; } else { - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } return m_executor.hard_fork_info(version); } bool t_command_parser_executor::show_bans(const std::vector<std::string>& args) { - if (!args.empty()) return false; + if (!args.empty()) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } + return m_executor.print_bans(); } bool t_command_parser_executor::ban(const std::vector<std::string>& args) { - if (args.size() != 1 && args.size() != 2) return false; + if (args.size() != 1 && args.size() != 2) { + std::cout << "Invalid syntax: Expects one or two parameters. For more details, use the help command." << std::endl; + return true; + } std::string ip = args[0]; time_t seconds = P2P_IP_BLOCKTIME; if (args.size() > 1) @@ -595,11 +667,13 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args) } catch (const std::exception &e) { - return false; + std::cout << "Invalid syntax: Failed to parse seconds. For more details, use the help command." << std::endl; + return true; } if (seconds == 0) { - return false; + std::cout << "Seconds must be greater than 0." << std::endl; + return true; } } return m_executor.ban(ip, seconds); @@ -607,21 +681,31 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args) bool t_command_parser_executor::unban(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } + std::string ip = args[0]; return m_executor.unban(ip); } bool t_command_parser_executor::banned(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } std::string address = args[0]; return m_executor.banned(address); } bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& args) { - if (args.size() > 1) return false; + if (args.size() > 1) { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } std::string txid; if (args.size() == 1) @@ -629,7 +713,7 @@ bool t_command_parser_executor::flush_txpool(const std::vector<std::string>& arg crypto::hash hash; if (!parse_hash256(args[0], hash)) { - std::cout << "failed to parse tx id" << std::endl; + std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl; return true; } txid = args[0]; @@ -662,7 +746,7 @@ bool t_command_parser_executor::output_histogram(const std::vector<std::string>& } else { - std::cout << "Invalid syntax: more than two non-amount parameters" << std::endl; + std::cout << "Invalid syntax: More than two non-amount parameters. For more details, use the help command." << std::endl; return true; } } @@ -673,20 +757,21 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::str { if(!args.size()) { - std::cout << "need block height parameter" << std::endl; - return false; + std::cout << "Invalid syntax: At least one parameter expected. For more details, use the help command." << std::endl; + return true; } + uint64_t height = 0; uint64_t count = 0; if(!epee::string_tools::get_xtype_from_string(height, args[0])) { - std::cout << "wrong starter block height parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong starter block height parameter. For more details, use the help command." << std::endl; + return true; } if(args.size() >1 && !epee::string_tools::get_xtype_from_string(count, args[1])) { std::cout << "wrong count parameter" << std::endl; - return false; + return true; } return m_executor.print_coinbase_tx_sum(height, count); @@ -696,8 +781,8 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a { if(args.size() > 1) { - std::cout << "usage: alt_chain_info [block_hash|>N|-N]" << std::endl; - return false; + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; } std::string tip; @@ -709,16 +794,16 @@ bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& a { if (!epee::string_tools::get_xtype_from_string(above, args[0].c_str() + 1)) { - std::cout << "invalid above parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Invalid above parameter. For more details, use the help command." << std::endl; + return true; } } else if (args[0].size() > 0 && args[0][0] == '-') { if (!epee::string_tools::get_xtype_from_string(last_blocks, args[0].c_str() + 1)) { - std::cout << "invalid last_blocks parameter" << std::endl; - return false; + std::cout << "Invalid syntax: Invalid last_blocks parameter. For more details, use the help command." << std::endl; + return true; } } else @@ -734,15 +819,15 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector { if(args.size() != 1) { - std::cout << "Exactly one parameter is needed" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } uint64_t nblocks = 0; if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0) { - std::cout << "wrong number of blocks" << std::endl; - return false; + std::cout << "Invalid syntax: Wrong number of blocks. For more details, use the help command." << std::endl; + return true; } return m_executor.print_blockchain_dynamic_stats(nblocks); @@ -750,10 +835,10 @@ bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector bool t_command_parser_executor::update(const std::vector<std::string>& args) { - if(args.size() != 1) + if (args.size() != 1) { - std::cout << "Exactly one parameter is needed: check, download, or update" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } return m_executor.update(args.front()); @@ -761,13 +846,17 @@ bool t_command_parser_executor::update(const std::vector<std::string>& args) bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args) { - if (args.size() != 1) return false; + if (args.size() != 1) + { + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; + } std::string txid; crypto::hash hash; if (!parse_hash256(args[0], hash)) { - std::cout << "failed to parse tx id" << std::endl; + std::cout << "Invalid syntax: Failed to parse tx id. For more details, use the help command." << std::endl; return true; } txid = args[0]; @@ -776,7 +865,10 @@ bool t_command_parser_executor::relay_tx(const std::vector<std::string>& args) bool t_command_parser_executor::sync_info(const std::vector<std::string>& args) { - if (args.size() != 0) return false; + if (args.size() != 0) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.sync_info(); } @@ -785,8 +877,8 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args) { if (args.size() != 1) { - std::cout << "Exactly one parameter is needed" << std::endl; - return false; + std::cout << "Invalid syntax: One parameter expected. For more details, use the help command." << std::endl; + return true; } try @@ -794,21 +886,24 @@ bool t_command_parser_executor::pop_blocks(const std::vector<std::string>& args) uint64_t nblocks = boost::lexical_cast<uint64_t>(args[0]); if (nblocks < 1) { - std::cout << "number of blocks must be greater than 0" << std::endl; - return false; + std::cout << "Invalid syntax: Number of blocks must be greater than 0. For more details, use the help command." << std::endl; + return true; } return m_executor.pop_blocks(nblocks); } catch (const boost::bad_lexical_cast&) { - std::cout << "number of blocks must be a number greater than 0" << std::endl; + std::cout << "Invalid syntax: Number of blocks must be a number greater than 0. For more details, use the help command." << std::endl; } - return false; + return true; } bool t_command_parser_executor::rpc_payments(const std::vector<std::string>& args) { - if (args.size() != 0) return false; + if (args.size() != 0) { + std::cout << "Invalid syntax: No parameters expected. For more details, use the help command." << std::endl; + return true; + } return m_executor.rpc_payments(); } @@ -820,7 +915,11 @@ bool t_command_parser_executor::version(const std::vector<std::string>& args) bool t_command_parser_executor::prune_blockchain(const std::vector<std::string>& args) { - if (args.size() > 1) return false; + if (args.size() > 1) + { + std::cout << "Invalid syntax: Too many parameters. For more details, use the help command." << std::endl; + return true; + } if (args.empty() || args[0] != "confirm") { @@ -846,7 +945,8 @@ bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::stri const size_t args_count = args.size(); if (args_count < 1 || args_count > 3) { - return false; + std::cout << "Invalid syntax: Wrong number of parameters. For more details, use the help command." << std::endl; + return true; } return m_executor.set_bootstrap_daemon( diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index ac4c30726..dd5f76188 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -223,7 +223,8 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "hard_fork_info" , std::bind(&t_command_parser_executor::hard_fork_info, &m_parser, p::_1) - , "Print the hard fork voting information." + , "hard_fork_info <version>" + , "Print the hard fork voting information. If given a version, prints whether is this version enabled." ); m_command_lookup.set_handler( "bans" @@ -314,6 +315,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "prune_blockchain" , std::bind(&t_command_parser_executor::prune_blockchain, &m_parser, p::_1) + , "prune_blockchain [confirm]" , "Prune the blockchain." ); m_command_lookup.set_handler( diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 3e0afeb65..384b776ee 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -83,44 +83,33 @@ namespace hw { // Must be sorted in ascending order by the code #define LEDGER_STATUS(status) {status, #status} constexpr Status status_codes[] = { - LEDGER_STATUS(SW_BYTES_REMAINING_00), - LEDGER_STATUS(SW_WARNING_STATE_UNCHANGED), - LEDGER_STATUS(SW_STATE_TERMINATED), - LEDGER_STATUS(SW_MORE_DATA_AVAILABLE), + LEDGER_STATUS(SW_OK), LEDGER_STATUS(SW_WRONG_LENGTH), - LEDGER_STATUS(SW_LOGICAL_CHANNEL_NOT_SUPPORTED), - LEDGER_STATUS(SW_SECURE_MESSAGING_NOT_SUPPORTED), - LEDGER_STATUS(SW_LAST_COMMAND_EXPECTED), - LEDGER_STATUS(SW_COMMAND_CHAINING_NOT_SUPPORTED), + LEDGER_STATUS(SW_SECURITY_PIN_LOCKED), LEDGER_STATUS(SW_SECURITY_LOAD_KEY), LEDGER_STATUS(SW_SECURITY_COMMITMENT_CONTROL), LEDGER_STATUS(SW_SECURITY_AMOUNT_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_COMMITMENT_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_OUTKEYS_CHAIN_CONTROL), LEDGER_STATUS(SW_SECURITY_MAXOUTPUT_REACHED), - LEDGER_STATUS(SW_SECURITY_TRUSTED_INPUT), - LEDGER_STATUS(SW_CLIENT_NOT_SUPPORTED), - LEDGER_STATUS(SW_SECURITY_STATUS_NOT_SATISFIED), - LEDGER_STATUS(SW_FILE_INVALID), - LEDGER_STATUS(SW_PIN_BLOCKED), - LEDGER_STATUS(SW_DATA_INVALID), - LEDGER_STATUS(SW_CONDITIONS_NOT_SATISFIED), + LEDGER_STATUS(SW_SECURITY_HMAC), + LEDGER_STATUS(SW_SECURITY_RANGE_VALUE), + LEDGER_STATUS(SW_SECURITY_INTERNAL), + LEDGER_STATUS(SW_SECURITY_MAX_SIGNATURE_REACHED), + LEDGER_STATUS(SW_SECURITY_PREFIX_HASH), + LEDGER_STATUS(SW_SECURITY_LOCKED), LEDGER_STATUS(SW_COMMAND_NOT_ALLOWED), - LEDGER_STATUS(SW_APPLET_SELECT_FAILED), + LEDGER_STATUS(SW_SUBCOMMAND_NOT_ALLOWED), + LEDGER_STATUS(SW_DENY), + LEDGER_STATUS(SW_KEY_NOT_SET), LEDGER_STATUS(SW_WRONG_DATA), - LEDGER_STATUS(SW_FUNC_NOT_SUPPORTED), - LEDGER_STATUS(SW_FILE_NOT_FOUND), - LEDGER_STATUS(SW_RECORD_NOT_FOUND), - LEDGER_STATUS(SW_FILE_FULL), - LEDGER_STATUS(SW_INCORRECT_P1P2), - LEDGER_STATUS(SW_REFERENCED_DATA_NOT_FOUND), + LEDGER_STATUS(SW_WRONG_DATA_RANGE), + LEDGER_STATUS(SW_IO_FULL), + LEDGER_STATUS(SW_CLIENT_NOT_SUPPORTED), LEDGER_STATUS(SW_WRONG_P1P2), - LEDGER_STATUS(SW_CORRECT_LENGTH_00), LEDGER_STATUS(SW_INS_NOT_SUPPORTED), - LEDGER_STATUS(SW_CLA_NOT_SUPPORTED), - LEDGER_STATUS(SW_UNKNOWN), - LEDGER_STATUS(SW_OK), - LEDGER_STATUS(SW_ALGORITHM_UNSUPPORTED) + LEDGER_STATUS(SW_PROTOCOL_NOT_SUPPORTED), + LEDGER_STATUS(SW_UNKNOWN) }; const char *Status::to_string(unsigned int code) diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index 5cb834e02..00ff05ec5 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -59,44 +59,33 @@ namespace hw { #ifdef WITH_DEVICE_LEDGER // Origin: https://github.com/LedgerHQ/ledger-app-monero/blob/master/src/monero_types.h - #define SW_BYTES_REMAINING_00 0x6100 - #define SW_WARNING_STATE_UNCHANGED 0x6200 - #define SW_STATE_TERMINATED 0x6285 - #define SW_MORE_DATA_AVAILABLE 0x6310 - #define SW_WRONG_LENGTH 0x6700 - #define SW_LOGICAL_CHANNEL_NOT_SUPPORTED 0x6881 - #define SW_SECURE_MESSAGING_NOT_SUPPORTED 0x6882 - #define SW_LAST_COMMAND_EXPECTED 0x6883 - #define SW_COMMAND_CHAINING_NOT_SUPPORTED 0x6884 - #define SW_SECURITY_LOAD_KEY 0x6900 - #define SW_SECURITY_COMMITMENT_CONTROL 0x6911 - #define SW_SECURITY_AMOUNT_CHAIN_CONTROL 0x6912 - #define SW_SECURITY_COMMITMENT_CHAIN_CONTROL 0x6913 - #define SW_SECURITY_OUTKEYS_CHAIN_CONTROL 0x6914 - #define SW_SECURITY_MAXOUTPUT_REACHED 0x6915 - #define SW_SECURITY_TRUSTED_INPUT 0x6916 - #define SW_CLIENT_NOT_SUPPORTED 0x6930 - #define SW_SECURITY_STATUS_NOT_SATISFIED 0x6982 - #define SW_FILE_INVALID 0x6983 - #define SW_PIN_BLOCKED 0x6983 - #define SW_DATA_INVALID 0x6984 - #define SW_CONDITIONS_NOT_SATISFIED 0x6985 - #define SW_COMMAND_NOT_ALLOWED 0x6986 - #define SW_APPLET_SELECT_FAILED 0x6999 - #define SW_WRONG_DATA 0x6a80 - #define SW_FUNC_NOT_SUPPORTED 0x6a81 - #define SW_FILE_NOT_FOUND 0x6a82 - #define SW_RECORD_NOT_FOUND 0x6a83 - #define SW_FILE_FULL 0x6a84 - #define SW_INCORRECT_P1P2 0x6a86 - #define SW_REFERENCED_DATA_NOT_FOUND 0x6a88 - #define SW_WRONG_P1P2 0x6b00 - #define SW_CORRECT_LENGTH_00 0x6c00 - #define SW_INS_NOT_SUPPORTED 0x6d00 - #define SW_CLA_NOT_SUPPORTED 0x6e00 - #define SW_UNKNOWN 0x6f00 - #define SW_OK 0x9000 - #define SW_ALGORITHM_UNSUPPORTED 0x9484 + #define SW_OK 0x9000 + #define SW_WRONG_LENGTH 0x6700 + #define SW_SECURITY_PIN_LOCKED 0x6910 + #define SW_SECURITY_LOAD_KEY 0x6911 + #define SW_SECURITY_COMMITMENT_CONTROL 0x6912 + #define SW_SECURITY_AMOUNT_CHAIN_CONTROL 0x6913 + #define SW_SECURITY_COMMITMENT_CHAIN_CONTROL 0x6914 + #define SW_SECURITY_OUTKEYS_CHAIN_CONTROL 0x6915 + #define SW_SECURITY_MAXOUTPUT_REACHED 0x6916 + #define SW_SECURITY_HMAC 0x6917 + #define SW_SECURITY_RANGE_VALUE 0x6918 + #define SW_SECURITY_INTERNAL 0x6919 + #define SW_SECURITY_MAX_SIGNATURE_REACHED 0x691A + #define SW_SECURITY_PREFIX_HASH 0x691B + #define SW_SECURITY_LOCKED 0x69EE + #define SW_COMMAND_NOT_ALLOWED 0x6980 + #define SW_SUBCOMMAND_NOT_ALLOWED 0x6981 + #define SW_DENY 0x6982 + #define SW_KEY_NOT_SET 0x6983 + #define SW_WRONG_DATA 0x6984 + #define SW_WRONG_DATA_RANGE 0x6985 + #define SW_IO_FULL 0x6986 + #define SW_CLIENT_NOT_SUPPORTED 0x6A30 + #define SW_WRONG_P1P2 0x6b00 + #define SW_INS_NOT_SUPPORTED 0x6d00 + #define SW_PROTOCOL_NOT_SUPPORTED 0x6e00 + #define SW_UNKNOWN 0x6f00 namespace { bool apdu_verbose =true; diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index 1c5dca0d7..aee1fa593 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -146,6 +146,7 @@ namespace nodetool const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node = {"seed-node", "Connect to a node to retrieve peer addresses, and disconnect"}; const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy = {"tx-proxy", "Send local txes through proxy: <network-type>,<socks-ip:port>[,max_connections][,disable_noise] i.e. \"tor,127.0.0.1:9050,100,disable_noise\""}; const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""}; + const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"}; const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true}; const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false}; diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 97835edd4..87fec9994 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -164,6 +164,7 @@ namespace nodetool network_zone() : m_connect(nullptr), m_net_server(epee::net_utils::e_connection_type_P2P), + m_seed_nodes(), m_bind_ip(), m_bind_ipv6_address(), m_port(), @@ -175,7 +176,9 @@ namespace nodetool m_proxy_address(), m_current_number_of_out_peers(0), m_current_number_of_in_peers(0), - m_can_pingback(false) + m_seed_nodes_lock(), + m_can_pingback(false), + m_seed_nodes_initialized(false) { set_config_defaults(); } @@ -183,6 +186,7 @@ namespace nodetool network_zone(boost::asio::io_service& public_service) : m_connect(nullptr), m_net_server(public_service, epee::net_utils::e_connection_type_P2P), + m_seed_nodes(), m_bind_ip(), m_bind_ipv6_address(), m_port(), @@ -194,13 +198,16 @@ namespace nodetool m_proxy_address(), m_current_number_of_out_peers(0), m_current_number_of_in_peers(0), - m_can_pingback(false) + m_seed_nodes_lock(), + m_can_pingback(false), + m_seed_nodes_initialized(false) { set_config_defaults(); } connect_func* m_connect; net_server m_net_server; + std::vector<epee::net_utils::network_address> m_seed_nodes; std::string m_bind_ip; std::string m_bind_ipv6_address; std::string m_port; @@ -212,7 +219,9 @@ namespace nodetool boost::asio::ip::tcp::endpoint m_proxy_address; std::atomic<unsigned int> m_current_number_of_out_peers; std::atomic<unsigned int> m_current_number_of_in_peers; + boost::shared_mutex m_seed_nodes_lock; bool m_can_pingback; + bool m_seed_nodes_initialized; private: void set_config_defaults() noexcept @@ -383,9 +392,10 @@ namespace nodetool void record_addr_failed(const epee::net_utils::network_address& addr); bool is_addr_recently_failed(const epee::net_utils::network_address& addr); bool is_priority_node(const epee::net_utils::network_address& na); - std::set<std::string> get_seed_nodes(cryptonote::network_type nettype) const; - std::set<std::string> get_seed_nodes(); - bool connect_to_seed(); + std::set<std::string> get_ip_seed_nodes() const; + std::set<std::string> get_dns_seed_nodes(); + std::set<std::string> get_seed_nodes(epee::net_utils::zone); + bool connect_to_seed(epee::net_utils::zone); template <class Container> bool connect_to_peerlist(const Container& peers); @@ -467,9 +477,6 @@ namespace nodetool std::list<epee::net_utils::network_address> m_priority_peers; std::vector<epee::net_utils::network_address> m_exclusive_peers; - std::vector<epee::net_utils::network_address> m_seed_nodes; - bool m_seed_nodes_initialized = false; - boost::shared_mutex m_seed_nodes_lock; std::atomic_flag m_fallback_seed_nodes_added; std::vector<nodetool::peerlist_entry> m_command_line_peers; uint64_t m_peer_livetime; @@ -523,6 +530,7 @@ namespace nodetool extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node; extern const command_line::arg_descriptor<std::vector<std::string> > arg_tx_proxy; extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound; + extern const command_line::arg_descriptor<std::string> arg_ban_list; extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port; extern const command_line::arg_descriptor<bool> arg_no_sync; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index aa16e93d5..055d3507e 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -106,6 +106,7 @@ namespace nodetool command_line::add_arg(desc, arg_p2p_seed_node); command_line::add_arg(desc, arg_tx_proxy); command_line::add_arg(desc, arg_anonymous_inbound); + command_line::add_arg(desc, arg_ban_list); command_line::add_arg(desc, arg_p2p_hide_my_port); command_line::add_arg(desc, arg_no_sync); command_line::add_arg(desc, arg_no_igd); @@ -386,7 +387,7 @@ namespace nodetool m_use_ipv6 = command_line::get_arg(vm, arg_p2p_use_ipv6); 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, pad_txs, m_payload_handler.get_core() + public_zone.m_net_server.get_io_service(), public_zone.m_net_server.get_config_shared(), nullptr, epee::net_utils::zone::public_, pad_txs, m_payload_handler.get_core() }; if (command_line::has_arg(vm, arg_p2p_add_peer)) @@ -435,12 +436,42 @@ namespace nodetool if (command_line::has_arg(vm, arg_p2p_seed_node)) { - boost::unique_lock<boost::shared_mutex> lock(m_seed_nodes_lock); + boost::unique_lock<boost::shared_mutex> lock(public_zone.m_seed_nodes_lock); - if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, m_seed_nodes)) + if (!parse_peers_and_add_to_container(vm, arg_p2p_seed_node, public_zone.m_seed_nodes)) return false; } + if (!command_line::is_arg_defaulted(vm, arg_ban_list)) + { + const std::string ban_list = command_line::get_arg(vm, arg_ban_list); + + const boost::filesystem::path ban_list_path(ban_list); + boost::system::error_code ec; + if (!boost::filesystem::exists(ban_list_path, ec)) + { + throw std::runtime_error("Can't find ban list file " + ban_list + " - " + ec.message()); + } + + std::string banned_ips; + if (!epee::file_io_utils::load_file_to_string(ban_list_path.string(), banned_ips)) + { + throw std::runtime_error("Failed to read ban list file " + ban_list); + } + + std::istringstream iss(banned_ips); + for (std::string line; std::getline(iss, line); ) + { + const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0); + if (!parsed_addr) + { + MERROR("Invalid IP address: " << line << " - " << parsed_addr.error()); + continue; + } + block_host(*parsed_addr, std::numeric_limits<time_t>::max()); + } + } + if(command_line::has_arg(vm, arg_p2p_hide_my_port)) m_hide_my_port = true; @@ -499,7 +530,7 @@ namespace nodetool } zone.m_notifier = cryptonote::levin::notify{ - zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), false, pad_txs, m_payload_handler.get_core() + zone.m_net_server.get_io_service(), zone.m_net_server.get_config_shared(), std::move(this_noise), proxy.zone, pad_txs, m_payload_handler.get_core() }; } @@ -598,21 +629,21 @@ namespace nodetool //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(cryptonote::network_type nettype) const + std::set<std::string> node_server<t_payload_net_handler>::get_ip_seed_nodes() const { std::set<std::string> full_addrs; - if (nettype == cryptonote::TESTNET) + if (m_nettype == cryptonote::TESTNET) { full_addrs.insert("212.83.175.67:28080"); full_addrs.insert("212.83.172.165:28080"); full_addrs.insert("192.110.160.146:28080"); } - else if (nettype == cryptonote::STAGENET) + else if (m_nettype == cryptonote::STAGENET) { full_addrs.insert("162.210.173.150:38080"); full_addrs.insert("192.110.160.146:38080"); } - else if (nettype == cryptonote::FAKECHAIN) + else if (m_nettype == cryptonote::FAKECHAIN) { } else @@ -630,7 +661,7 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes() + std::set<std::string> node_server<t_payload_net_handler>::get_dns_seed_nodes() { if (!m_exclusive_peers.empty() || m_offline) { @@ -638,11 +669,11 @@ namespace nodetool } if (m_nettype == cryptonote::TESTNET) { - return get_seed_nodes(cryptonote::TESTNET); + return get_ip_seed_nodes(); } if (m_nettype == cryptonote::STAGENET) { - return get_seed_nodes(cryptonote::STAGENET); + return get_ip_seed_nodes(); } std::set<std::string> full_addrs; @@ -730,7 +761,7 @@ namespace nodetool else MINFO("Not enough DNS seed nodes found, using fallback defaults too"); - for (const auto &peer: get_seed_nodes(cryptonote::MAINNET)) + for (const auto &peer: get_ip_seed_nodes()) full_addrs.insert(peer); m_fallback_seed_nodes_added.test_and_set(); } @@ -739,6 +770,23 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> + std::set<std::string> node_server<t_payload_net_handler>::get_seed_nodes(epee::net_utils::zone zone) + { + switch (zone) + { + case epee::net_utils::zone::public_: + return get_dns_seed_nodes(); + case epee::net_utils::zone::tor: + return {}; + case epee::net_utils::zone::i2p: + return {}; + default: + break; + } + throw std::logic_error{"Bad zone given to get_seed_nodes"}; + } + //----------------------------------------------------------------------------------- + template<class t_payload_net_handler> typename node_server<t_payload_net_handler>::network_zone& node_server<t_payload_net_handler>::add_zone(const epee::net_utils::zone zone) { const auto zone_ = m_network_zones.lower_bound(zone); @@ -1432,6 +1480,20 @@ namespace nodetool const uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); classB.insert(actual_ip & 0x0000ffff); } +#if BOOST_VERSION > 106600 + else if (cntxt.m_remote_address.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = cntxt.m_remote_address; + const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + classB.insert(actual_ipv4 & ntohl(0xffff0000)); + } + } +#endif return true; }); } @@ -1452,6 +1514,20 @@ namespace nodetool uint32_t actual_ip = na.as<const epee::net_utils::ipv4_network_address>().ip(); skip = classB.find(actual_ip & 0x0000ffff) != classB.end(); } +#if BOOST_VERSION > 106600 + else if (skip_duplicate_class_B && pe.adr.get_type_id() == epee::net_utils::ipv6_network_address::get_type_id()) + { + const epee::net_utils::network_address na = pe.adr; + const boost::asio::ip::address_v6 &actual_ip = na.as<const epee::net_utils::ipv6_network_address>().ip(); + if (actual_ip.is_v4_mapped()) + { + boost::asio::ip::address_v4 v4ip = make_address_v4(boost::asio::ip::v4_mapped, actual_ip); + uint32_t actual_ipv4; + memcpy(&actual_ipv4, v4ip.to_bytes().data(), sizeof(actual_ipv4)); + skip = classB.find(actual_ipv4 & ntohl(0xffff0000)) != classB.end(); + } + } +#endif if (skip) ++skipped; else if (next_needed_pruning_stripe == 0 || pe.pruning_seed == 0) @@ -1464,11 +1540,11 @@ namespace nodetool if (skipped == 0 || !filtered.empty()) break; if (skipped) - MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers"); + MDEBUG("Skipping " << skipped << " possible peers as they share a class B with existing peers"); } if (filtered.empty()) { - MDEBUG("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); + MINFO("No available peer in " << (use_white_list ? "white" : "gray") << " list filtered by " << next_needed_pruning_stripe); return false; } if (use_white_list) @@ -1541,56 +1617,59 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - bool node_server<t_payload_net_handler>::connect_to_seed() + bool node_server<t_payload_net_handler>::connect_to_seed(epee::net_utils::zone zone) { - boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(m_seed_nodes_lock); + network_zone& server = m_network_zones.at(zone); + boost::upgrade_lock<boost::shared_mutex> seed_nodes_upgrade_lock(server.m_seed_nodes_lock); - if (!m_seed_nodes_initialized) + if (!server.m_seed_nodes_initialized) { + const std::uint16_t default_port = cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT; boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock); - m_seed_nodes_initialized = true; - for (const auto& full_addr : get_seed_nodes()) + server.m_seed_nodes_initialized = true; + for (const auto& full_addr : get_seed_nodes(zone)) { + // seeds should have hostname converted to IP already MDEBUG("Seed node: " << full_addr); - append_net_address(m_seed_nodes, full_addr, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); + server.m_seed_nodes.push_back(MONERO_UNWRAP(net::get_network_address(full_addr, default_port))); } - MDEBUG("Number of seed nodes: " << m_seed_nodes.size()); + MDEBUG("Number of seed nodes: " << server.m_seed_nodes.size()); } - if (m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty()) + if (server.m_seed_nodes.empty() || m_offline || !m_exclusive_peers.empty()) return true; size_t try_count = 0; bool is_connected_to_at_least_one_seed_node = false; - size_t current_index = crypto::rand_idx(m_seed_nodes.size()); - const net_server& server = m_network_zones.at(epee::net_utils::zone::public_).m_net_server; + size_t current_index = crypto::rand_idx(server.m_seed_nodes.size()); while(true) { - if(server.is_stop_signal_sent()) + if(server.m_net_server.is_stop_signal_sent()) return false; peerlist_entry pe_seed{}; - pe_seed.adr = m_seed_nodes[current_index]; + pe_seed.adr = server.m_seed_nodes[current_index]; if (is_peer_used(pe_seed)) is_connected_to_at_least_one_seed_node = true; - else if (try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true)) + else if (try_to_connect_and_handshake_with_new_peer(server.m_seed_nodes[current_index], true)) break; - if(++try_count > m_seed_nodes.size()) + if(++try_count > server.m_seed_nodes.size()) { - if (!m_fallback_seed_nodes_added.test_and_set()) + // only IP zone has fallback (to direct IP) seeds + if (zone == epee::net_utils::zone::public_ && !m_fallback_seed_nodes_added.test_and_set()) { MWARNING("Failed to connect to any of seed peers, trying fallback seeds"); - current_index = m_seed_nodes.size() - 1; + current_index = server.m_seed_nodes.size() - 1; { boost::upgrade_to_unique_lock<boost::shared_mutex> seed_nodes_lock(seed_nodes_upgrade_lock); - for (const auto &peer: get_seed_nodes(m_nettype)) + for (const auto &peer: get_ip_seed_nodes()) { MDEBUG("Fallback seed node: " << peer); - append_net_address(m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); + append_net_address(server.m_seed_nodes, peer, cryptonote::get_config(m_nettype).P2P_DEFAULT_PORT); } } - if (current_index == m_seed_nodes.size() - 1) + if (current_index == server.m_seed_nodes.size() - 1) { MWARNING("No fallback seeds, continuing without seeds"); break; @@ -1604,7 +1683,7 @@ namespace nodetool break; } } - if(++current_index >= m_seed_nodes.size()) + if(++current_index >= server.m_seed_nodes.size()) current_index = 0; } return true; @@ -1620,20 +1699,21 @@ namespace nodetool if (!m_exclusive_peers.empty()) return true; - // Only have seeds in the public zone right now. - - size_t start_conn_count = get_public_outgoing_connections_count(); - if(!get_public_white_peers_count() && !connect_to_seed()) + bool one_succeeded = false; + for(auto& zone : m_network_zones) { - return false; - } + size_t start_conn_count = get_outgoing_connections_count(zone.second); + if(!zone.second.m_peerlist.get_white_peers_count() && !connect_to_seed(zone.first)) + { + continue; + } - if (!connect_to_peerlist(m_priority_peers)) return false; + if (zone.first == zone_type::public_ && !connect_to_peerlist(m_priority_peers)) continue; - for(auto& zone : m_network_zones) - { size_t base_expected_white_connections = (zone.second.m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100; + // carefully avoid `continue` in nested loop + size_t conn_count = get_outgoing_connections_count(zone.second); while(conn_count < zone.second.m_config.m_net_config.max_out_connection_count) { @@ -1670,16 +1750,17 @@ namespace nodetool } conn_count = new_conn_count; } - } - if (start_conn_count == get_public_outgoing_connections_count() && start_conn_count < m_network_zones.at(zone_type::public_).m_config.m_net_config.max_out_connection_count) - { - MINFO("Failed to connect to any, trying seeds"); - if (!connect_to_seed()) - return false; + if (start_conn_count == get_outgoing_connections_count(zone.second) && start_conn_count < zone.second.m_config.m_net_config.max_out_connection_count) + { + MINFO("Failed to connect to any, trying seeds"); + if (!connect_to_seed(zone.first)) + continue; + } + one_succeeded = true; } - return true; + return one_succeeded; } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 19298c969..aa4102481 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -66,7 +66,7 @@ set(rpc_pub_headers zmq_pub.h) set(daemon_rpc_server_headers) -set(rpc_daemon_private_headers +set(rpc_private_headers bootstrap_daemon.h core_rpc_server.h rpc_payment.h diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 382b5815f..e72f60d05 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1137,7 +1137,7 @@ namespace cryptonote if (!restricted) { boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); - if (m_bootstrap_daemon.get() != nullptr) + if (m_should_use_bootstrap_daemon) { skip_validation = !check_core_ready(); } @@ -1669,6 +1669,13 @@ namespace cryptonote return false; } + uint64_t next_height; + crypto::rx_seedheights(height, &seed_height, &next_height); + if (next_height != seed_height) + next_seed_hash = m_core.get_block_id_by_height(next_height); + else + next_seed_hash = seed_hash; + if (extra_nonce.empty()) { reserved_offset = 0; diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp index bcb300889..3a8532db8 100644 --- a/src/wallet/api/transaction_history.cpp +++ b/src/wallet/api/transaction_history.cpp @@ -92,6 +92,17 @@ std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const return m_history; } +void TransactionHistoryImpl::setTxNote(const std::string &txid, const std::string ¬e) +{ + cryptonote::blobdata txid_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash)) + return; + const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data()); + + m_wallet->m_wallet->set_tx_note(htxid, note); + refresh(); +} + void TransactionHistoryImpl::refresh() { // multithreaded access: @@ -126,10 +137,12 @@ void TransactionHistoryImpl::refresh() payment_id = payment_id.substr(0,16); TransactionInfoImpl * ti = new TransactionInfoImpl(); ti->m_paymentid = payment_id; + ti->m_coinbase = pd.m_coinbase; ti->m_amount = pd.m_amount; ti->m_direction = TransactionInfo::Direction_In; ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash); ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrAccount = pd.m_subaddr_index.major; ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); @@ -173,6 +186,7 @@ void TransactionHistoryImpl::refresh() ti->m_direction = TransactionInfo::Direction_Out; ti->m_hash = string_tools::pod_to_hex(hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(hash); ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; @@ -183,6 +197,7 @@ void TransactionHistoryImpl::refresh() for (const auto &d: pd.m_dests) { ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); } + m_history.push_back(ti); } @@ -207,6 +222,7 @@ void TransactionHistoryImpl::refresh() ti->m_failed = is_failed; ti->m_pending = true; ti->m_hash = string_tools::pod_to_hex(hash); + ti->m_description = m_wallet->m_wallet->get_tx_note(hash); ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; @@ -230,6 +246,7 @@ void TransactionHistoryImpl::refresh() ti->m_direction = TransactionInfo::Direction_In; ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_blockheight = pd.m_block_height; + ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash); ti->m_pending = true; ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrAccount = pd.m_subaddr_index.major; diff --git a/src/wallet/api/transaction_history.h b/src/wallet/api/transaction_history.h index 8f3805788..60f12d771 100644 --- a/src/wallet/api/transaction_history.h +++ b/src/wallet/api/transaction_history.h @@ -45,6 +45,7 @@ public: virtual TransactionInfo * transaction(const std::string &id) const; virtual std::vector<TransactionInfo*> getAll() const; virtual void refresh(); + virtual void setTxNote(const std::string &txid, const std::string ¬e); private: diff --git a/src/wallet/api/transaction_info.cpp b/src/wallet/api/transaction_info.cpp index 5ae3a6937..33e7856db 100644 --- a/src/wallet/api/transaction_info.cpp +++ b/src/wallet/api/transaction_info.cpp @@ -45,6 +45,7 @@ TransactionInfoImpl::TransactionInfoImpl() : m_direction(Direction_Out) , m_pending(false) , m_failed(false) + , m_coinbase(false) , m_amount(0) , m_fee(0) , m_blockheight(0) @@ -77,6 +78,11 @@ bool TransactionInfoImpl::isFailed() const return m_failed; } +bool TransactionInfoImpl::isCoinbase() const +{ + return m_coinbase; +} + uint64_t TransactionInfoImpl::amount() const { return m_amount; @@ -92,6 +98,11 @@ uint64_t TransactionInfoImpl::blockHeight() const return m_blockheight; } +std::string TransactionInfoImpl::description() const +{ + return m_description; +} + std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const { return m_subaddrIndex; diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 73bb7689d..8bc36a8e9 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -46,10 +46,12 @@ public: //! true if hold virtual bool isPending() const override; virtual bool isFailed() const override; + virtual bool isCoinbase() const override; virtual uint64_t amount() const override; //! always 0 for incoming txes virtual uint64_t fee() const override; virtual uint64_t blockHeight() const override; + virtual std::string description() const override; virtual std::set<uint32_t> subaddrIndex() const override; virtual uint32_t subaddrAccount() const override; virtual std::string label() const override; @@ -65,9 +67,11 @@ private: int m_direction; bool m_pending; bool m_failed; + bool m_coinbase; uint64_t m_amount; uint64_t m_fee; uint64_t m_blockheight; + std::string m_description; std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers uint32_t m_subaddrAccount; std::string m_label; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index e8efc58b8..44928a422 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -182,9 +182,11 @@ struct TransactionInfo virtual int direction() const = 0; virtual bool isPending() const = 0; virtual bool isFailed() const = 0; + virtual bool isCoinbase() const = 0; virtual uint64_t amount() const = 0; virtual uint64_t fee() const = 0; virtual uint64_t blockHeight() const = 0; + virtual std::string description() const = 0; virtual std::set<uint32_t> subaddrIndex() const = 0; virtual uint32_t subaddrAccount() const = 0; virtual std::string label() const = 0; @@ -208,6 +210,7 @@ struct TransactionHistory virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual std::vector<TransactionInfo*> getAll() const = 0; virtual void refresh() = 0; + virtual void setTxNote(const std::string &txid, const std::string ¬e) = 0; }; /** diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a3755ff08..7cbb4a910 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2961,6 +2961,8 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, MTRACE("update_pool_state got pool"); // remove any pending tx that's not in the pool + constexpr const std::chrono::seconds tx_propagation_timeout{CRYPTONOTE_DANDELIONPP_EMBARGO_AVERAGE * 3 / 2}; + const auto now = std::chrono::system_clock::now(); std::unordered_map<crypto::hash, wallet2::unconfirmed_transfer_details>::iterator it = m_unconfirmed_txs.begin(); while (it != m_unconfirmed_txs.end()) { @@ -2988,9 +2990,11 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction, LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as not in pool"); pit->second.m_state = wallet2::unconfirmed_transfer_details::pending_not_in_pool; } - else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed) + else if (pit->second.m_state == wallet2::unconfirmed_transfer_details::pending_not_in_pool && refreshed && + now > std::chrono::system_clock::from_time_t(pit->second.m_sent_time) + tx_propagation_timeout) { - LOG_PRINT_L1("Pending txid " << txid << " not in pool, marking as failed"); + LOG_PRINT_L1("Pending txid " << txid << " not in pool after " << tx_propagation_timeout.count() << + " seconds, marking as failed"); pit->second.m_state = wallet2::unconfirmed_transfer_details::failed; // the inputs aren't spent anymore, since the tx failed |