diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -147,6 +147,7 @@ wallet/test/wallet_test_fixture.h \ wallet/test/accounting_tests.cpp \ wallet/test/wallet_tests.cpp \ + wallet/test/walletdb_tests.cpp \ wallet/test/crypto_tests.cpp endif diff --git a/src/wallet/test/walletdb_tests.cpp b/src/wallet/test/walletdb_tests.cpp new file mode 100644 --- /dev/null +++ b/src/wallet/test/walletdb_tests.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2017 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "test/test_bitcoin.h" + +#include "wallet/wallet.h" +#include "wallet/walletdb.h" + +#include + +static std::unique_ptr +TmpDB(const boost::filesystem::path &pathTemp) { + boost::filesystem::path path = + pathTemp / + strprintf("testwallet%i", static_cast(GetRand(1000000))); + return std::unique_ptr(new CWalletDB(path.string(), "cr+")); +} + +static std::unique_ptr LoadWallet(CWalletDB *db) { + std::unique_ptr wallet(new CWallet); + DBErrors res = db->LoadWallet(wallet.get()); + BOOST_CHECK(res == DB_LOAD_OK); + return std::move(wallet); +} + +BOOST_FIXTURE_TEST_SUITE(walletdb_tests, TestingSetup); + +BOOST_AUTO_TEST_CASE(write_erase_name) { + + auto walletdb = TmpDB(pathTemp); + CTxDestination dst1 = CKeyID(uint160S("c0ffee")); + CTxDestination dst2 = CKeyID(uint160S("f00d")); + + BOOST_CHECK(walletdb->WriteName(dst1, "name1")); + BOOST_CHECK(walletdb->WriteName(dst2, "name2")); + { + auto w = LoadWallet(walletdb.get()); + BOOST_CHECK_EQUAL(1, w->mapAddressBook.count(dst1)); + BOOST_CHECK_EQUAL("name1", w->mapAddressBook[dst1].name); + BOOST_CHECK_EQUAL("name2", w->mapAddressBook[dst2].name); + } + + walletdb->EraseName(dst1); + + { + auto w = LoadWallet(walletdb.get()); + BOOST_CHECK_EQUAL(0, w->mapAddressBook.count(dst1)); + BOOST_CHECK_EQUAL(1, w->mapAddressBook.count(dst2)); + } +} + +BOOST_AUTO_TEST_CASE(write_erase_purpose) { + + auto walletdb = TmpDB(pathTemp); + CTxDestination dst1 = CKeyID(uint160S("c0ffee")); + CTxDestination dst2 = CKeyID(uint160S("f00d")); + + BOOST_CHECK(walletdb->WritePurpose(dst1, "purpose1")); + BOOST_CHECK(walletdb->WritePurpose(dst2, "purpose2")); + { + auto w = LoadWallet(walletdb.get()); + BOOST_CHECK_EQUAL(1, w->mapAddressBook.count(dst1)); + BOOST_CHECK_EQUAL("purpose1", w->mapAddressBook[dst1].purpose); + BOOST_CHECK_EQUAL("purpose2", w->mapAddressBook[dst2].purpose); + } + + walletdb->ErasePurpose(dst1); + + { + auto w = LoadWallet(walletdb.get()); + BOOST_CHECK_EQUAL(0, w->mapAddressBook.count(dst1)); + BOOST_CHECK_EQUAL(1, w->mapAddressBook.count(dst2)); + } +} + +BOOST_AUTO_TEST_CASE(write_erase_destdata) { + + auto walletdb = TmpDB(pathTemp); + CTxDestination dst1 = CKeyID(uint160S("c0ffee")); + CTxDestination dst2 = CKeyID(uint160S("f00d")); + + BOOST_CHECK(walletdb->WriteDestData(dst1, "key1", "value1")); + BOOST_CHECK(walletdb->WriteDestData(dst1, "key2", "value2")); + BOOST_CHECK(walletdb->WriteDestData(dst2, "key1", "value3")); + BOOST_CHECK(walletdb->WriteDestData(dst2, "key2", "value4")); + { + auto w = LoadWallet(walletdb.get()); + std::string val; + BOOST_CHECK(w->GetDestData(dst1, "key1", &val)); + BOOST_CHECK_EQUAL("value1", val); + BOOST_CHECK(w->GetDestData(dst1, "key2", &val)); + BOOST_CHECK_EQUAL("value2", val); + BOOST_CHECK(w->GetDestData(dst2, "key1", &val)); + BOOST_CHECK_EQUAL("value3", val); + BOOST_CHECK(w->GetDestData(dst2, "key2", &val)); + BOOST_CHECK_EQUAL("value4", val); + } + + walletdb->EraseDestData(dst1, "key2"); + + { + auto w = LoadWallet(walletdb.get()); + std::string dummy; + BOOST_CHECK(w->GetDestData(dst1, "key1", &dummy)); + BOOST_CHECK(!w->GetDestData(dst1, "key2", &dummy)); + BOOST_CHECK(w->GetDestData(dst2, "key1", &dummy)); + BOOST_CHECK(w->GetDestData(dst2, "key2", &dummy)); + } +} + +BOOST_AUTO_TEST_CASE(no_dest_fails) { + auto walletdb = TmpDB(pathTemp); + CTxDestination dst = CNoDestination{}; + BOOST_CHECK(!walletdb->WriteName(dst, "name")); + BOOST_CHECK(!walletdb->WritePurpose(dst, "purpose")); + BOOST_CHECK(!walletdb->WriteDestData(dst, "key", "value")); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3235,13 +3235,11 @@ } if (!strPurpose.empty() && - !CWalletDB(strWalletFile) - .WritePurpose(EncodeDestination(address), strPurpose)) { + !CWalletDB(strWalletFile).WritePurpose(address, strPurpose)) { return false; } - return CWalletDB(strWalletFile) - .WriteName(EncodeDestination(address), strName); + return CWalletDB(strWalletFile).WriteName(address, strName); } bool CWallet::DelAddressBook(const CTxDestination &address) { @@ -3251,10 +3249,9 @@ if (fFileBacked) { // Delete destdata tuples associated with address. - std::string strAddress = EncodeDestination(address); for (const std::pair &item : mapAddressBook[address].destdata) { - CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); + CWalletDB(strWalletFile).EraseDestData(address, item.first); } } mapAddressBook.erase(address); @@ -3268,8 +3265,8 @@ return false; } - CWalletDB(strWalletFile).ErasePurpose(EncodeDestination(address)); - return CWalletDB(strWalletFile).EraseName(EncodeDestination(address)); + CWalletDB(strWalletFile).ErasePurpose(address); + return CWalletDB(strWalletFile).EraseName(address); } bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) { @@ -3869,8 +3866,7 @@ return true; } - return CWalletDB(strWalletFile) - .WriteDestData(EncodeDestination(dest), key, value); + return CWalletDB(strWalletFile).WriteDestData(dest, key, value); } bool CWallet::EraseDestData(const CTxDestination &dest, @@ -3883,7 +3879,7 @@ return true; } - return CWalletDB(strWalletFile).EraseDestData(EncodeDestination(dest), key); + return CWalletDB(strWalletFile).EraseDestData(dest, key); } bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +10,7 @@ #include "amount.h" #include "key.h" #include "primitives/transaction.h" +#include "script/standard.h" // for CTxDestination #include "wallet/db.h" #include @@ -112,12 +114,12 @@ bool fFlushOnClose = true) : CDB(strFilename, pszMode, fFlushOnClose) {} - bool WriteName(const std::string &strAddress, const std::string &strName); - bool EraseName(const std::string &strAddress); + bool WriteName(const CTxDestination &address, const std::string &strName); + bool EraseName(const CTxDestination &address); - bool WritePurpose(const std::string &strAddress, + bool WritePurpose(const CTxDestination &address, const std::string &purpose); - bool ErasePurpose(const std::string &strAddress); + bool ErasePurpose(const CTxDestination &address); bool WriteTx(const CWalletTx &wtx); bool EraseTx(uint256 hash); @@ -157,10 +159,10 @@ bool WriteAccount(const std::string &strAccount, const CAccount &account); /// Write destination data key,value tuple to database. - bool WriteDestData(const std::string &address, const std::string &key, + bool WriteDestData(const CTxDestination &address, const std::string &key, const std::string &value); /// Erase destination data tuple from wallet database. - bool EraseDestData(const std::string &address, const std::string &key); + bool EraseDestData(const CTxDestination &address, const std::string &key); Amount GetAccountCreditDebit(const std::string &strAccount); void ListAccountCreditDebit(const std::string &strAccount, diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,10 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers +// Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "wallet/walletdb.h" +#include "base58.h" #include "consensus/validation.h" #include "dstencode.h" #include "protocol.h" @@ -29,30 +31,47 @@ // CWalletDB // -bool CWalletDB::WriteName(const std::string &strAddress, +bool CWalletDB::WriteName(const CTxDestination &address, const std::string &strName) { + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("name"), strAddress), strName); + return Write(std::make_pair(std::string("name"), + EncodeLegacyAddr(address, Params())), + strName); } -bool CWalletDB::EraseName(const std::string &strAddress) { +bool CWalletDB::EraseName(const CTxDestination &address) { // This should only be used for sending addresses, never for receiving // addresses, receiving addresses must always have an address book entry if // they're not change return. + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("name"), strAddress)); + return Erase(std::make_pair(std::string("name"), + EncodeLegacyAddr(address, Params()))); } -bool CWalletDB::WritePurpose(const std::string &strAddress, +bool CWalletDB::WritePurpose(const CTxDestination &address, const std::string &strPurpose) { + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Write(std::make_pair(std::string("purpose"), strAddress), + return Write(std::make_pair(std::string("purpose"), + EncodeLegacyAddr(address, Params())), strPurpose); } -bool CWalletDB::ErasePurpose(const std::string &strPurpose) { +bool CWalletDB::ErasePurpose(const CTxDestination &address) { + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Erase(std::make_pair(std::string("purpose"), strPurpose)); + return Erase(std::make_pair(std::string("purpose"), + EncodeLegacyAddr(address, Params()))); } bool CWalletDB::WriteTx(const CWalletTx &wtx) { @@ -853,20 +872,28 @@ return CWalletDB::Recover(dbenv, filename, false); } -bool CWalletDB::WriteDestData(const std::string &address, +bool CWalletDB::WriteDestData(const CTxDestination &address, const std::string &key, const std::string &value) { + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Write( - std::make_pair(std::string("destdata"), std::make_pair(address, key)), - value); + return Write(std::make_pair( + std::string("destdata"), + std::make_pair(EncodeLegacyAddr(address, Params()), key)), + value); } -bool CWalletDB::EraseDestData(const std::string &address, +bool CWalletDB::EraseDestData(const CTxDestination &address, const std::string &key) { + if (!IsValidDestination(address)) { + return false; + } nWalletDBUpdateCounter++; - return Erase( - std::make_pair(std::string("destdata"), std::make_pair(address, key))); + return Erase(std::make_pair( + std::string("destdata"), + std::make_pair(EncodeLegacyAddr(address, Params()), key))); } bool CWalletDB::WriteHDChain(const CHDChain &chain) {