wallet2::store() implemented within wallet2::store_to

This commit is contained in:
Ilya Kitaev 2016-03-21 16:17:03 +03:00
parent 7df2baf6b0
commit 2cce32995b
4 changed files with 87 additions and 69 deletions

View File

@ -1424,6 +1424,42 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::store() void wallet2::store()
{ {
store_to("", "");
}
//----------------------------------------------------------------------------------------------------
void wallet2::store_to(const std::string &path, const std::string &password)
{
// if file is the same, we do:
// 1. save wallet to the *.new file
// 2. remove old wallet file
// 3. rename *.new to wallet_name
// handle if we want just store wallet state to current files (ex store() replacement);
bool same_file = true;
if (!path.empty())
{
std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string();
size_t pos = canonical_path.find(path);
same_file = pos != std::string::npos;
}
if (!same_file)
{
// check if we want to store to directory which doesn't exists yet
boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
// if path is not exists, try to create it
if (!parent_path.empty() && !boost::filesystem::exists(parent_path))
{
boost::system::error_code ec;
if (!boost::filesystem::create_directories(parent_path, ec))
{
throw std::logic_error(ec.message());
}
}
}
// preparing wallet data
std::stringstream oss; std::stringstream oss;
boost::archive::binary_oarchive ar(oss); boost::archive::binary_oarchive ar(oss);
ar << *this; ar << *this;
@ -1438,10 +1474,10 @@ void wallet2::store()
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]); crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
cache_file_data.cache_data = cipher; cache_file_data.cache_data = cipher;
// save to new file, rename main to old, rename new to main const std::string new_file = same_file ? m_wallet_file + ".new" : path;
// at all times, there should be a valid file on disk const std::string old_file = m_wallet_file;
const std::string new_file = m_wallet_file + ".new"; const std::string old_keys_file = m_keys_file;
const std::string old_file = m_wallet_file + ".old"; const std::string old_address_file = m_wallet_file + ".address.txt";
// save to new file // save to new file
std::ofstream ostr; std::ofstream ostr;
@ -1451,87 +1487,35 @@ void wallet2::store()
ostr.close(); ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file); THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
// rename // save keys to the new file
boost::filesystem::remove(old_file); // probably does not exist // if we here, main wallet file is saved and we only need to save keys and address files
if (boost::filesystem::exists(m_wallet_file)) { if (!same_file) {
std::error_code e = tools::replace_file(m_wallet_file, old_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
}
std::error_code e = tools::replace_file(new_file, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
boost::filesystem::remove(old_file);
}
void wallet2::store_to(const std::string &path, const std::string &password)
{
// TODO: merge it with wallet2::store() function
// check if we want to store to directory which doesn't exists yet
boost::filesystem::path parent_path = boost::filesystem::path(path).parent_path();
// if path is not exists, try to create it
if (!parent_path.empty() && !boost::filesystem::exists(parent_path)) {
boost::system::error_code ec;
if (!boost::filesystem::create_directories(parent_path, ec)) {
throw std::logic_error(ec.message());
}
}
std::stringstream oss;
boost::archive::binary_oarchive ar(oss);
ar << *this;
wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
cache_file_data.cache_data = oss.str();
crypto::chacha8_key key;
generate_chacha8_key_from_secret_keys(key);
std::string cipher;
cipher.resize(cache_file_data.cache_data.size());
cache_file_data.iv = crypto::rand<crypto::chacha8_iv>();
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
cache_file_data.cache_data = cipher;
const std::string new_file = path;
const std::string old_file = m_wallet_file;
const std::string old_keys_file = m_keys_file;
const std::string old_address_file = m_wallet_file + ".address.txt";
// save to new file
std::ofstream ostr;
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
binary_archive<true> oar(ostr);
bool success = ::serialization::serialize(oar, cache_file_data);
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
// save keys to the new file
// if we here, main wallet file is saved and we only need to save keys and address files
prepare_file_names(path); prepare_file_names(path);
store_keys(m_keys_file, password, false); store_keys(m_keys_file, password, false);
// save address to the new file // save address to the new file
const std::string address_file = m_wallet_file + ".address.txt"; const std::string address_file = m_wallet_file + ".address.txt";
bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet)); bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
// remove old wallet file // remove old wallet file
r = boost::filesystem::remove(old_file); r = boost::filesystem::remove(old_file);
if (!r) { if (!r) {
LOG_ERROR("error removing file: " << old_file); LOG_ERROR("error removing file: " << old_file);
} }
// remove old keys file // remove old keys file
r = boost::filesystem::remove(old_keys_file); r = boost::filesystem::remove(old_keys_file);
if (!r) { if (!r) {
LOG_ERROR("error removing file: " << old_keys_file); LOG_ERROR("error removing file: " << old_keys_file);
} }
// remove old address file // remove old address file
r = boost::filesystem::remove(old_address_file); r = boost::filesystem::remove(old_address_file);
if (!r) { if (!r) {
LOG_ERROR("error removing file: " << old_address_file); LOG_ERROR("error removing file: " << old_address_file);
} }
} else {
// here we have "*.new" file, we need to rename it to be without ".new"
std::error_code e = tools::replace_file(new_file, m_wallet_file);
THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e);
}
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance() const uint64_t wallet2::unlocked_balance() const
@ -2769,12 +2753,12 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) c
std::string wallet2::get_wallet_file() const std::string wallet2::get_wallet_file() const
{ {
return m_wallet_file; return m_wallet_file;
} }
std::string wallet2::get_keys_file() const std::string wallet2::get_keys_file() const
{ {
return m_keys_file; return m_keys_file;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------

View File

@ -276,6 +276,7 @@ public:
virtual bool closeWallet(Wallet *wallet); virtual bool closeWallet(Wallet *wallet);
bool walletExists(const std::string &path); bool walletExists(const std::string &path);
std::string errorString() const; std::string errorString() const;
void setDaemonHost(const std::string &hostname);
private: private:
@ -329,6 +330,11 @@ std::string WalletManagerImpl::errorString() const
return m_errorString; return m_errorString;
} }
void WalletManagerImpl::setDaemonHost(const std::string &hostname)
{
}
///////////////////// WalletManagerFactory implementation ////////////////////// ///////////////////// WalletManagerFactory implementation //////////////////////

View File

@ -112,6 +112,9 @@ struct WalletManager
virtual std::string errorString() const = 0; virtual std::string errorString() const = 0;
virtual void setDaemonHost(const std::string &hostname) = 0;
}; };

View File

@ -165,6 +165,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
ASSERT_TRUE(wmgr->closeWallet(wallet2)); ASSERT_TRUE(wmgr->closeWallet(wallet2));
} }
TEST_F(WalletManagerTest, WalletManagerStoresWallet2) TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
{ {
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@ -181,6 +182,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
ASSERT_TRUE(wmgr->closeWallet(wallet1)); ASSERT_TRUE(wmgr->closeWallet(wallet1));
} }
TEST_F(WalletManagerTest, WalletManagerStoresWallet3) TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
{ {
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG); Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@ -204,6 +206,29 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
} }
TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
{
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->address();
ASSERT_TRUE(wallet1->store(""));
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
ASSERT_TRUE(wallet1->store(""));
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS);
ASSERT_TRUE(wallet1->status() == Bitmonero::Wallet::Status_Ok);
ASSERT_TRUE(wallet1->seed() == seed1);
ASSERT_TRUE(wallet1->address() == address1);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
//epee::debug::get_set_enable_assert(true, false); //epee::debug::get_set_enable_assert(true, false);