diff --git a/nano/core_test/wallets.cpp b/nano/core_test/wallets.cpp index 326975d8..8d2a4b9d 100644 --- a/nano/core_test/wallets.cpp +++ b/nano/core_test/wallets.cpp @@ -1,6 +1,7 @@ #include #include +#include #include using namespace std::chrono_literals; @@ -95,3 +96,23 @@ TEST (wallets, DISABLED_wallet_create_max) auto existing = wallets.items.find (key.pub); ASSERT_TRUE (existing == wallets.items.end ()); } + +TEST (wallets, reload) +{ + nano::system system (24000, 1); + nano::uint256_union one (1); + bool error (false); + ASSERT_FALSE (error); + ASSERT_EQ (1, system.nodes[0]->wallets.items.size ()); + { + nano::inactive_node node (system.nodes[0]->application_path, 24001); + auto wallet (node.node->wallets.create (one)); + ASSERT_NE (wallet, nullptr); + } + system.deadline_set (5s); + while (system.nodes[0]->wallets.open (one) == nullptr) + { + system.poll (); + } + ASSERT_EQ (2, system.nodes[0]->wallets.items.size ()); +} diff --git a/nano/node/node.cpp b/nano/node/node.cpp index 3c7df81f..4e98a8b1 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -2276,6 +2276,9 @@ void nano::node::backup_wallet () void nano::node::search_pending () { + // Reload wallets from disk + wallets.reload (); + // Search pending wallets.search_pending_all (); auto this_l (shared ()); alarm.add (std::chrono::steady_clock::now () + search_pending_interval, [this_l]() { diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 1c8137e4..433d723e 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -1299,6 +1299,7 @@ thread ([this]() { do_wallet_actions (); }) { + std::lock_guard lock (mutex); if (!error_a) { auto transaction (tx_begin_write ()); @@ -1340,6 +1341,7 @@ nano::wallets::~wallets () std::shared_ptr nano::wallets::open (nano::uint256_union const & id_a) { + std::lock_guard lock (mutex); std::shared_ptr result; auto existing (items.find (id_a)); if (existing != items.end ()) @@ -1351,6 +1353,7 @@ std::shared_ptr nano::wallets::open (nano::uint256_union const & i std::shared_ptr nano::wallets::create (nano::uint256_union const & id_a) { + std::lock_guard lock (mutex); assert (items.find (id_a) == items.end ()); std::shared_ptr result; bool error; @@ -1368,6 +1371,7 @@ std::shared_ptr nano::wallets::create (nano::uint256_union const & bool nano::wallets::search_pending (nano::uint256_union const & wallet_a) { + std::lock_guard lock (mutex); auto result (false); auto existing (items.find (wallet_a)); result = existing == items.end (); @@ -1381,6 +1385,7 @@ bool nano::wallets::search_pending (nano::uint256_union const & wallet_a) void nano::wallets::search_pending_all () { + std::lock_guard lock (mutex); for (auto i : items) { i.second->search_pending (); @@ -1398,6 +1403,49 @@ void nano::wallets::destroy (nano::uint256_union const & id_a) wallet->store.destroy (transaction); } +void nano::wallets::reload () +{ + std::lock_guard lock (mutex); + auto transaction (tx_begin_write ()); + std::unordered_set stored_items; + std::string beginning (nano::uint256_union (0).to_string ()); + std::string end ((nano::uint256_union (nano::uint256_t (0) - nano::uint256_t (1))).to_string ()); + nano::store_iterator, nano::mdb_val::no_value> i (std::make_unique, nano::mdb_val::no_value>> (transaction, handle, nano::mdb_val (beginning.size (), const_cast (beginning.c_str ())))); + nano::store_iterator, nano::mdb_val::no_value> n (std::make_unique, nano::mdb_val::no_value>> (transaction, handle, nano::mdb_val (end.size (), const_cast (end.c_str ())))); + for (; i != n; ++i) + { + nano::uint256_union id; + std::string text (i->first.data (), i->first.size ()); + auto error (id.decode_hex (text)); + assert (!error); + // New wallet + if (items.find (id) == items.end ()) + { + auto wallet (std::make_shared (error, transaction, *this, text)); + if (!error) + { + items[id] = wallet; + } + } + // List of wallets on disk + stored_items.insert (id); + } + // Delete non existing wallets from memory + std::vector deleted_items; + for (auto i : items) + { + if (stored_items.find (i.first) == stored_items.end ()) + { + deleted_items.push_back (i.first); + } + } + for (auto & i : deleted_items) + { + assert (items.find (i) == items.end ()); + items.erase (i); + } +} + void nano::wallets::do_wallet_actions () { std::unique_lock lock (mutex); @@ -1436,11 +1484,12 @@ void nano::wallets::queue_wallet_action (nano::uint128_t const & amount_a, std:: void nano::wallets::foreach_representative (nano::transaction const & transaction_a, std::function const & action_a) { + std::lock_guard lock (mutex); auto transaction_l (node.wallets.tx_begin_read ()); for (auto i (items.begin ()), n (items.end ()); i != n; ++i) { auto & wallet (*i->second); - std::lock_guard lock (wallet.store.mutex); + std::lock_guard store_lock (wallet.store.mutex); for (auto j (wallet.store.begin (transaction_l)), m (wallet.store.end ()); j != m; ++j) { nano::account account (j->first); @@ -1469,6 +1518,7 @@ void nano::wallets::foreach_representative (nano::transaction const & transactio bool nano::wallets::exists (nano::transaction const & transaction_a, nano::public_key const & account_a) { + std::lock_guard lock (mutex); auto result (false); for (auto i (items.begin ()), n (items.end ()); !result && i != n; ++i) { diff --git a/nano/node/wallet.hpp b/nano/node/wallet.hpp index 3f312ed2..807e79e5 100644 --- a/nano/node/wallet.hpp +++ b/nano/node/wallet.hpp @@ -171,6 +171,7 @@ public: bool search_pending (nano::uint256_union const &); void search_pending_all (); void destroy (nano::uint256_union const &); + void reload (); void do_wallet_actions (); void queue_wallet_action (nano::uint128_t const &, std::shared_ptr, std::function const &); void foreach_representative (nano::transaction const &, std::function const &);