diff options
Diffstat (limited to 'src')
27 files changed, 495 insertions, 272 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 93e3ef3bc..f91b3d6c1 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3068,9 +3068,21 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context if (tx.version >= 2) { if (tx.rct_signatures.type <= rct::RCTTypeBulletproof2) { - MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1)); - tvc.m_invalid_output = true; - return false; + // two MLSAG txes went in due to a bug with txes that went into the txpool before the fork, grandfather them in + static const char * grandfathered[2] = { "c5151944f0583097ba0c88cd0f43e7fabb3881278aa2f73b3b0a007c5d34e910", "6f2f117cde6fbcf8d4a6ef8974fcac744726574ac38cf25d3322c996b21edd4c" }; + crypto::hash h0, h1; + epee::string_tools::hex_to_pod(grandfathered[0], h0); + epee::string_tools::hex_to_pod(grandfathered[1], h1); + if (cryptonote::get_transaction_hash(tx) == h0 || cryptonote::get_transaction_hash(tx) == h1) + { + MDEBUG("Grandfathering cryptonote::get_transaction_hash(tx) in"); + } + else + { + MERROR_VER("Ringct type " << (unsigned)tx.rct_signatures.type << " is not allowed from v" << (HF_VERSION_CLSAG + 1)); + tvc.m_invalid_output = true; + return false; + } } } } diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index c9d26e0ed..7c578ac51 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -663,7 +663,7 @@ namespace cryptonote * * @param target_blockchain_height the target height */ - uint64_t get_target_blockchain_height() const; + virtual uint64_t get_target_blockchain_height() const override; /** * @brief returns the newest hardfork version known to the blockchain diff --git a/src/cryptonote_core/i_core_events.h b/src/cryptonote_core/i_core_events.h index 03394d785..addb659ab 100644 --- a/src/cryptonote_core/i_core_events.h +++ b/src/cryptonote_core/i_core_events.h @@ -39,6 +39,7 @@ namespace cryptonote virtual ~i_core_events() noexcept {} + virtual uint64_t get_target_blockchain_height() const = 0; virtual void on_transactions_relayed(epee::span<const cryptonote::blobdata> tx_blobs, relay_method tx_relay) = 0; }; } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 85bcf2246..28721ee36 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -1391,7 +1391,10 @@ namespace cryptonote txpool_tx_meta_t meta; if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta)) { - MERROR(" failed to find tx meta"); + static bool warned = false; + if (!warned) + MERROR(" failed to find tx meta: " << sorted_it->second << " (will only print once)"); + warned = true; continue; } LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method()); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 337885509..a8073e091 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -2538,7 +2538,7 @@ skip: local mempool before doing the relay. The code was already updating the DB twice on received transactions - it is difficult to workaround this due to the internal design. */ - return m_p2p->send_txs(std::move(arg.txs), zone, source, m_core, tx_relay) != epee::net_utils::zone::invalid; + return m_p2p->send_txs(std::move(arg.txs), zone, source, tx_relay) != epee::net_utils::zone::invalid; } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 7c482156f..634750cab 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -105,8 +105,8 @@ namespace levin return std::chrono::steady_clock::duration{crypto::rand_range(rep(0), range.count())}; } - //! \return All outgoing connections supporting fragments in `connections`. - std::vector<boost::uuids::uuid> get_out_connections(connections& p2p) + //! \return Outgoing connections supporting fragments in `connections` filtered by remote blockchain height. + std::vector<boost::uuids::uuid> get_out_connections(connections& p2p, uint64_t min_blockchain_height) { std::vector<boost::uuids::uuid> outs; outs.reserve(connection_id_reserve_size); @@ -115,8 +115,8 @@ namespace levin the reserve call so a strand is not used. Investigate if there is lots of waiting in here. */ - p2p.foreach_connection([&outs] (detail::p2p_context& context) { - if (!context.m_is_income) + p2p.foreach_connection([&outs, min_blockchain_height] (detail::p2p_context& context) { + if (!context.m_is_income && context.m_remote_blockchain_height >= min_blockchain_height) outs.emplace_back(context.m_connection_id); return true; }); @@ -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()) @@ -544,7 +545,7 @@ namespace levin } // connection list may be outdated, try again - update_channels::run(zone_, get_out_connections(*zone_->p2p)); + update_channels::run(zone_, get_out_connections(*zone_->p2p, core_->get_target_blockchain_height())); } MERROR("Unable to send transaction(s) via Dandelion++ stem"); @@ -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_); @@ -591,8 +592,9 @@ namespace levin { std::shared_ptr<detail::zone> zone_; const std::size_t channel_; + const i_core_events* core_; - static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index) + static void wait(const std::chrono::steady_clock::time_point start, std::shared_ptr<detail::zone> zone, const std::size_t index, const i_core_events* core) { if (!zone) return; @@ -600,7 +602,7 @@ namespace levin noise_channel& channel = zone->channels.at(index); channel.next_noise.expires_at(start + noise_min_delay + random_duration(noise_delay_range)); channel.next_noise.async_wait( - channel.strand.wrap(send_noise{std::move(zone), index}) + channel.strand.wrap(send_noise{std::move(zone), index, core}) ); } @@ -644,16 +646,18 @@ 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); + 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)}); } } - wait(start, std::move(zone_), channel_); + wait(start, std::move(zone_), channel_, core_); } }; @@ -665,6 +669,7 @@ namespace levin std::chrono::seconds min_epoch_; std::chrono::seconds epoch_range_; std::size_t count_; + const i_core_events* core_; //! \pre Should not be invoked within any strand to prevent blocking. void operator()(const boost::system::error_code error = {}) @@ -677,8 +682,9 @@ namespace levin const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY; const auto start = std::chrono::steady_clock::now(); + auto connections = get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height()); zone_->strand.dispatch( - change_channels{zone_, net::dandelionpp::connection_map{get_out_connections(*(zone_->p2p)), count_}, fluffing} + change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing} ); detail::zone& alias = *zone_; @@ -688,24 +694,25 @@ 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) - : 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; const auto epoch_range = noise_enabled ? noise_epoch_range : dandelionpp_epoch_range; const std::size_t out_count = noise_enabled ? CRYPTONOTE_NOISE_CHANNELS : CRYPTONOTE_DANDELIONPP_STEMS; - start_epoch{zone_, min_epoch, epoch_range, out_count}(); + start_epoch{zone_, min_epoch, epoch_range, out_count, core_}(); for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel) - send_noise::wait(now, zone_, channel); + send_noise::wait(now, zone_, channel, core_); } } @@ -726,7 +733,7 @@ namespace levin return; zone_->strand.dispatch( - update_channels{zone_, get_out_connections(*(zone_->p2p))} + update_channels{zone_, get_out_connections(*(zone_->p2p), core_->get_target_blockchain_height())} ); } @@ -753,7 +760,7 @@ namespace levin zone_->flush_txs.cancel(); } - bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay) + bool notify::send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay) { if (txs.empty()) return true; @@ -785,7 +792,7 @@ namespace levin tx_relay = relay_method::local; // do not put into stempool embargo (hopefully not there already!). } - core.on_transactions_relayed(epee::to_span(txs), tx_relay); + core_->on_transactions_relayed(epee::to_span(txs), tx_relay); // Padding is not useful when using noise mode. Send as stem so receiver // forwards in Dandelion++ mode. @@ -817,11 +824,11 @@ 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( - dandelionpp_notify{zone_, std::addressof(core), std::move(txs), source} + dandelionpp_notify{zone_, core_, std::move(txs), source} ); break; } @@ -832,7 +839,7 @@ namespace levin routine. A "fluff" over i2p/tor is not the same as a "fluff" over ipv4/6. Marking it as "fluff" here will make the tx immediately visible externally from this node, which is not desired. */ - core.on_transactions_relayed(epee::to_span(txs), tx_relay); + core_->on_transactions_relayed(epee::to_span(txs), tx_relay); zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source}); break; } diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h index 957794b12..abbf9d461 100644 --- a/src/cryptonote_protocol/levin_notify.h +++ b/src/cryptonote_protocol/levin_notify.h @@ -69,6 +69,7 @@ namespace levin class notify { std::shared_ptr<detail::zone> zone_; + i_core_events* core_; public: struct status @@ -80,10 +81,11 @@ namespace levin //! Construct an instance that cannot notify. notify() noexcept : zone_(nullptr) + , core_(nullptr) {} //! 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); + 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; @@ -123,7 +125,7 @@ namespace levin particular stem. \return True iff the notification is queued for sending. */ - bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, i_core_events& core, relay_method tx_relay); + bool send_txs(std::vector<blobdata> txs, const boost::uuids::uuid& source, relay_method tx_relay); }; } // levin } // net 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.h b/src/p2p/net_node.h index e81371783..d7c3e6096 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 @@ -334,7 +343,7 @@ namespace nodetool virtual void callback(p2p_connection_context& context); //----------------- i_p2p_endpoint ------------------------------------------------------------- virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections); - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay); + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay); virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context); virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context); virtual bool drop_connection(const epee::net_utils::connection_context_base& context); @@ -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; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 175741146..c50617965 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -386,7 +386,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 + 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,9 +435,9 @@ 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; } @@ -499,7 +499,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 + 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 +598,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 +630,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 +638,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 +730,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 +739,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); @@ -1541,56 +1558,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 +1624,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 +1640,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 +1691,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> @@ -1994,13 +2016,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template<class t_payload_net_handler> - epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, const cryptonote::relay_method tx_relay) + epee::net_utils::zone node_server<t_payload_net_handler>::send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, const cryptonote::relay_method tx_relay) { namespace enet = epee::net_utils; - const auto send = [&txs, &source, &core, tx_relay] (std::pair<const enet::zone, network_zone>& network) + const auto send = [&txs, &source, tx_relay] (std::pair<const enet::zone, network_zone>& network) { - if (network.second.m_notifier.send_txs(std::move(txs), source, core, tx_relay)) + if (network.second.m_notifier.send_txs(std::move(txs), source, tx_relay)) return network.first; return enet::zone::invalid; }; diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h index 393d38e0a..2ace5987f 100644 --- a/src/p2p/net_node_common.h +++ b/src/p2p/net_node_common.h @@ -50,7 +50,7 @@ namespace nodetool struct i_p2p_endpoint { virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> connections)=0; - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay)=0; + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay)=0; virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0; virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0; virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0; @@ -75,7 +75,7 @@ namespace nodetool { return false; } - virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::i_core_events& core, cryptonote::relay_method tx_relay) + virtual epee::net_utils::zone send_txs(std::vector<cryptonote::blobdata> txs, const epee::net_utils::zone origin, const boost::uuids::uuid& source, cryptonote::relay_method tx_relay) { return epee::net_utils::zone::invalid; } 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 a50c70418..e72f60d05 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -521,9 +521,17 @@ namespace cryptonote bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, const connection_context *ctx) { RPC_TRACKER(get_blocks); - bool r; - if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r)) - return r; + + bool use_bootstrap_daemon; + { + boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); + use_bootstrap_daemon = m_should_use_bootstrap_daemon; + } + if (use_bootstrap_daemon) + { + bool r; + return use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r); + } CHECK_PAYMENT(req, res, 1); @@ -1129,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(); } @@ -1661,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/address_book.cpp b/src/wallet/api/address_book.cpp index f69a69ca3..96090d9f5 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -70,6 +70,25 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa return r; } +bool AddressBookImpl::setDescription(std::size_t index, const std::string &description) +{ + clearStatus(); + + const auto ab = m_wallet->m_wallet->get_address_book(); + if (index >= ab.size()){ + return false; + } + + tools::wallet2::address_book_row entry = ab[index]; + entry.m_description = description; + bool r = m_wallet->m_wallet->set_address_book_row(index, entry.m_address, NULL, entry.m_description, entry.m_is_subaddress); + if (r) + refresh(); + else + m_errorCode = General_Error; + return r; +} + void AddressBookImpl::refresh() { LOG_PRINT_L2("Refreshing addressbook"); diff --git a/src/wallet/api/address_book.h b/src/wallet/api/address_book.h index f287969f3..e22f474fb 100644 --- a/src/wallet/api/address_book.h +++ b/src/wallet/api/address_book.h @@ -45,6 +45,7 @@ public: void refresh() override; std::vector<AddressBookRow*> getAll() const override; bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) override; + bool setDescription(std::size_t index, const std::string &description) override; bool deleteRow(std::size_t rowId) override; // Error codes. See AddressBook:ErrorCode enum in wallet2_api.h 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/wallet.cpp b/src/wallet/api/wallet.cpp index 152a7dcd7..9acc8484c 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -910,6 +910,11 @@ std::string WalletImpl::path() const return m_wallet->path(); } +void WalletImpl::stop() +{ + m_wallet->stop(); +} + bool WalletImpl::store(const std::string &path) { clearStatus(); diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index caf1e9ed4..3bf3e759b 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -99,6 +99,7 @@ public: std::string publicSpendKey() const override; std::string publicMultisigSignerKey() const override; std::string path() const override; + void stop() override; bool store(const std::string &path) override; std::string filename() const override; std::string keysFilename() const override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 50df7e5dd..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; }; /** @@ -250,6 +253,7 @@ struct AddressBook virtual std::vector<AddressBookRow*> getAll() const = 0; virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; virtual bool deleteRow(std::size_t rowId) = 0; + virtual bool setDescription(std::size_t index, const std::string &description) = 0; virtual void refresh() = 0; virtual std::string errorString() const = 0; virtual int errorCode() const = 0; @@ -507,6 +511,11 @@ struct Wallet virtual std::string publicMultisigSignerKey() const = 0; /*! + * \brief stop - interrupts wallet refresh() loop once (doesn't stop background refresh thread) + */ + virtual void stop() = 0; + + /*! * \brief store - stores wallet to file. * \param path - main filename to store wallet to. additionally stores address file and keys file. * to store to the same file - just pass empty string; 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 diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index eac99185c..fed7d745c 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -434,7 +434,7 @@ private: std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> m_rings; // relative BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) FIELD(m_tx) VARINT_FIELD(m_amount_in) VARINT_FIELD(m_amount_out) @@ -442,6 +442,8 @@ private: VARINT_FIELD(m_sent_time) FIELD(m_dests) FIELD(m_payment_id) + if (version >= 1) + VARINT_FIELD(m_state) VARINT_FIELD(m_timestamp) VARINT_FIELD(m_subaddr_account) FIELD(m_subaddr_indices) |