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()
{
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;
boost::archive::binary_oarchive ar(oss);
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]);
cache_file_data.cache_data = cipher;
// save to new file, rename main to old, rename new to main
// at all times, there should be a valid file on disk
const std::string new_file = m_wallet_file + ".new";
const std::string old_file = m_wallet_file + ".old";
const std::string new_file = same_file ? m_wallet_file + ".new" : 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;
@ -1451,87 +1487,35 @@ void wallet2::store()
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
// rename
boost::filesystem::remove(old_file); // probably does not exist
if (boost::filesystem::exists(m_wallet_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
// save keys to the new file
// if we here, main wallet file is saved and we only need to save keys and address files
if (!same_file) {
prepare_file_names(path);
store_keys(m_keys_file, password, false);
// save address to the new file
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));
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
// remove old wallet file
r = boost::filesystem::remove(old_file);
if (!r) {
LOG_ERROR("error removing file: " << old_file);
LOG_ERROR("error removing file: " << old_file);
}
// remove old keys file
r = boost::filesystem::remove(old_keys_file);
if (!r) {
LOG_ERROR("error removing file: " << old_keys_file);
LOG_ERROR("error removing file: " << old_keys_file);
}
// remove old address file
r = boost::filesystem::remove(old_address_file);
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
@ -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
{
return m_wallet_file;
return m_wallet_file;
}
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);
bool walletExists(const std::string &path);
std::string errorString() const;
void setDaemonHost(const std::string &hostname);
private:
@ -329,6 +330,11 @@ std::string WalletManagerImpl::errorString() const
return m_errorString;
}
void WalletManagerImpl::setDaemonHost(const std::string &hostname)
{
}
///////////////////// WalletManagerFactory implementation //////////////////////

View file

@ -112,6 +112,9 @@ struct WalletManager
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));
}
TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
{
Bitmonero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG);
@ -181,6 +182,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
{
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)
{
//epee::debug::get_set_enable_assert(true, false);