diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 07084d15b..c85cbfb8a 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -4341,6 +4341,29 @@ void simple_wallet::on_passphrase_request(bool on_device, epee::wipeable_string passphrase = pwd_container->password(); } //---------------------------------------------------------------------------------------------------- +void simple_wallet::on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money) +{ + // Key image sync after the first refresh + if (!m_wallet->get_account().get_device().has_tx_cold_sign()) { + return; + } + + if (!received_money || m_wallet->get_device_last_key_image_sync() != 0) { + return; + } + + // Finished first refresh for HW device and money received -> KI sync + message_writer() << "\n" << tr("The first refresh has finished for the HW-based wallet with received money. hw_key_images_sync is needed. "); + + std::string accepted = input_line(tr("Do you want to do it now? (Y/Yes/N/No): ")); + if (std::cin.eof() || !command_line::is_yes(accepted)) { + message_writer(console_color_red, false) << tr("hw_key_images_sync skipped. Run command manually before a transfer."); + return; + } + + key_images_sync_intern(); +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bool is_init) { if (!try_connect_to_daemon(is_init)) @@ -4358,13 +4381,14 @@ bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bo message_writer() << tr("Starting refresh..."); uint64_t fetched_blocks = 0; + bool received_money = false; bool ok = false; std::ostringstream ss; try { m_in_manual_refresh.store(true, std::memory_order_relaxed); epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_in_manual_refresh.store(false, std::memory_order_relaxed);}); - m_wallet->refresh(m_wallet->is_trusted_daemon(), start_height, fetched_blocks); + m_wallet->refresh(m_wallet->is_trusted_daemon(), start_height, fetched_blocks, received_money); ok = true; // Clear line "Height xxx of xxx" std::cout << "\r \r"; @@ -4372,6 +4396,7 @@ bool simple_wallet::refresh_main(uint64_t start_height, enum ResetType reset, bo if (is_init) print_accounts(); show_balance_unlocked(); + on_refresh_finished(start_height, fetched_blocks, is_init, received_money); } catch (const tools::error::daemon_busy&) { @@ -8134,13 +8159,13 @@ bool simple_wallet::hw_key_images_sync(const std::vector &args) fail_msg_writer() << tr("hw wallet does not support cold KI sync"); return true; } - if (!m_wallet->is_trusted_daemon()) - { - fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon"); - return true; - } LOCK_IDLE_SCOPE(); + key_images_sync_intern(); + return true; +} +//---------------------------------------------------------------------------------------------------- +void simple_wallet::key_images_sync_intern(){ try { message_writer(console_color_white, false) << tr("Please confirm the key image sync on the device"); @@ -8149,19 +8174,23 @@ bool simple_wallet::hw_key_images_sync(const std::vector &args) uint64_t height = m_wallet->cold_key_image_sync(spent, unspent); if (height > 0) { - success_msg_writer() << tr("Signed key images imported to height ") << height << ", " - << print_money(spent) << tr(" spent, ") << print_money(unspent) << tr(" unspent"); - } else { + success_msg_writer() << tr("Key images synchronized to height ") << height; + if (!m_wallet->is_trusted_daemon()) + { + message_writer() << tr("Running untrusted daemon, cannot determine which transaction output is spent. Use a trusted daemon with --trusted-daemon and run rescan_spent"); + } else + { + success_msg_writer() << print_money(spent) << tr(" spent, ") << print_money(unspent) << tr(" unspent"); + } + } + else { fail_msg_writer() << tr("Failed to import key images"); } } catch (const std::exception &e) { fail_msg_writer() << tr("Failed to import key images: ") << e.what(); - return true; } - - return true; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::hw_reconnect(const std::vector &args) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7e2edba7f..665879cac 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -241,6 +241,8 @@ namespace cryptonote bool print_ring_members(const std::vector& ptx_vector, std::ostream& ostr); std::string get_prompt() const; bool print_seed(bool encrypted); + void key_images_sync_intern(); + void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money); struct transfer_view { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 83aae6de3..46bd47353 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -892,7 +892,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended): m_ringdb(), m_last_block_reward(0), m_encrypt_keys_after_refresh(boost::none), - m_unattended(unattended) + m_unattended(unattended), + m_device_last_key_image_sync(0) { } @@ -3009,6 +3010,7 @@ bool wallet2::clear() m_subaddresses.clear(); m_subaddress_labels.clear(); m_multisig_rounds_passed = 0; + m_device_last_key_image_sync = 0; return true; } @@ -9235,9 +9237,7 @@ void wallet2::cold_sign_tx(const std::vector& ptx_vector, signed_tx_ //---------------------------------------------------------------------------------------------------- uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) { auto & hwdev = get_account().get_device(); - if (!hwdev.has_ki_cold_sync()){ - throw std::invalid_argument("Device does not support cold ki sync protocol"); - } + CHECK_AND_ASSERT_THROW_MES(hwdev.has_ki_cold_sync(), "Device does not support cold ki sync protocol"); auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev); CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface"); @@ -9248,7 +9248,11 @@ uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) { dev_cold->ki_sync(&wallet_shim, m_transfers, ski); - return import_key_images(ski, 0, spent, unspent); + // Call COMMAND_RPC_IS_KEY_IMAGE_SPENT only if daemon is trusted. + uint64_t import_res = import_key_images(ski, 0, spent, unspent, is_trusted_daemon()); + m_device_last_key_image_sync = time(NULL); + + return import_res; } //---------------------------------------------------------------------------------------------------- void wallet2::get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index a588e8003..4d121598b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -810,6 +810,7 @@ namespace tools bool is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const; uint64_t get_last_block_reward() const { return m_last_block_reward; } + uint64_t get_device_last_key_image_sync() const { return m_device_last_key_image_sync; } template inline void serialize(t_archive &a, const unsigned int ver) @@ -918,6 +919,9 @@ namespace tools if(ver < 26) return; a & m_tx_device; + if(ver < 27) + return; + a & m_device_last_key_image_sync; } /*! @@ -1388,6 +1392,7 @@ namespace tools size_t m_subaddress_lookahead_major, m_subaddress_lookahead_minor; std::string m_device_name; std::string m_device_derivation_path; + uint64_t m_device_last_key_image_sync; // Aux transaction data from device std::unordered_map m_tx_device; @@ -1424,7 +1429,7 @@ namespace tools std::unique_ptr m_device_callback; }; } -BOOST_CLASS_VERSION(tools::wallet2, 26) +BOOST_CLASS_VERSION(tools::wallet2, 27) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)