From 8ed1f8522b08e8b9811c9c16284a9967d62fb07f Mon Sep 17 00:00:00 2001 From: CryptoManiac Date: Mon, 16 Jun 2014 04:07:48 +0400 Subject: [PATCH] Move importwallet and dumpwallet implementations to walletdb.cpp; Move timestamps encoding and decoding functions to util.cpp. --- src/db.h | 3 +- src/rpcdump.cpp | 205 ++--------------------------------------------------- src/util.cpp | 67 ++++++++++++++++++ src/util.h | 4 + src/walletdb.cpp | 170 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 198 deletions(-) diff --git a/src/db.h b/src/db.h index 9a8af31..750d6b0 100644 --- a/src/db.h +++ b/src/db.h @@ -28,7 +28,8 @@ extern unsigned int nWalletDBUpdated; void ThreadFlushWalletDB(void* parg); bool BackupWallet(const CWallet& wallet, const std::string& strDest); - +bool DumpWallet(CWallet* pwallet, const std::string& strDest); +bool ImportWallet(CWallet* pwallet, const std::string& strLocation); class CDBEnv { diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index b0284f9..1e31e73 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -2,19 +2,11 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include -#include - #include "init.h" // for pwalletMain #include "bitcoinrpc.h" #include "ui_interface.h" #include "base58.h" -#include -#include -#include -#include - #define printf OutputDebugStringF using namespace json_spirit; @@ -22,72 +14,6 @@ using namespace std; void EnsureWalletIsUnlocked(); -namespace bt = boost::posix_time; - -// Extended DecodeDumpTime implementation, see this page for details: -// http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost -const std::locale formats[] = { - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%dT%H:%M:%SZ")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")), - std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d")) -}; - -const size_t formats_n = sizeof(formats)/sizeof(formats[0]); - -std::time_t pt_to_time_t(const bt::ptime& pt) -{ - bt::ptime timet_start(boost::gregorian::date(1970,1,1)); - bt::time_duration diff = pt - timet_start; - return diff.ticks()/bt::time_duration::rep_type::ticks_per_second; -} - -int64 DecodeDumpTime(const std::string& s) -{ - bt::ptime pt; - - for(size_t i=0; i> pt; - if(pt != bt::ptime()) break; - } - - return pt_to_time_t(pt); -} - -std::string static EncodeDumpTime(int64 nTime) { - return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); -} - -std::string static EncodeDumpString(const std::string &str) { - std::stringstream ret; - BOOST_FOREACH(unsigned char c, str) { - if (c <= 32 || c >= 128 || c == '%') { - ret << '%' << HexStr(&c, &c + 1); - } else { - ret << c; - } - } - return ret.str(); -} - -std::string DecodeDumpString(const std::string &str) { - std::stringstream ret; - for (unsigned int pos = 0; pos < str.length(); pos++) { - unsigned char c = str[pos]; - if (c == '%' && pos+2 < str.length()) { - c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | - ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15)); - pos += 2; - } - ret << c; - } - return ret.str(); -} - class CTxDump { public: @@ -150,86 +76,17 @@ Value importwallet(const Array& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "importwallet \n" - "Imports keys from a wallet dump file (see dumpwallet)."); + "Imports keys from a wallet dump file (see dumpwallet)." + + HelpRequiringPassphrase()); EnsureWalletIsUnlocked(); - ifstream file; - file.open(params[0].get_str().c_str()); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - - int64 nTimeBegin = pindexBest->nTime; - - bool fGood = true; - - while (file.good()) { - std::string line; - std::getline(file, line); - if (line.empty() || line[0] == '#') - continue; - - std::vector vstr; - boost::split(vstr, line, boost::is_any_of(" ")); - if (vstr.size() < 2) - continue; - CBitcoinSecret vchSecret; - if (!vchSecret.SetString(vstr[0])) - continue; - - bool fCompressed; - CKey key; - CSecret secret = vchSecret.GetSecret(fCompressed); - key.SetSecret(secret, fCompressed); - CKeyID keyid = key.GetPubKey().GetID(); - - if (pwalletMain->HaveKey(keyid)) { - printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str()); - continue; - } - int64 nTime = DecodeDumpTime(vstr[1]); - std::string strLabel; - bool fLabel = true; - for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { - if (boost::algorithm::starts_with(vstr[nStr], "#")) - break; - if (vstr[nStr] == "change=1") - fLabel = false; - if (vstr[nStr] == "reserve=1") - fLabel = false; - if (boost::algorithm::starts_with(vstr[nStr], "label=")) { - strLabel = DecodeDumpString(vstr[nStr].substr(6)); - fLabel = true; - } - } - printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str()); - if (!pwalletMain->AddKey(key)) { - fGood = false; - continue; - } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; - if (fLabel) - pwalletMain->SetAddressBookName(keyid, strLabel); - nTimeBegin = std::min(nTimeBegin, nTime); - } - file.close(); - - CBlockIndex *pindex = pindexBest; - while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) - pindex = pindex->pprev; - - printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1); - pwalletMain->ScanForWalletTransactions(pindex); - pwalletMain->ReacceptWalletTransactions(); - pwalletMain->MarkDirty(); - - if (!fGood) - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); + if(!ImportWallet(pwalletMain, params[0].get_str().c_str())) + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); return Value::null; } - Value dumpprivkey(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -260,59 +117,13 @@ Value dumpwallet(const Array& params, bool fHelp) if (fHelp || params.size() != 1) throw runtime_error( "dumpwallet \n" - "Dumps all wallet keys in a human-readable format."); + "Dumps all wallet keys in a human-readable format." + + HelpRequiringPassphrase()); EnsureWalletIsUnlocked(); - ofstream file; - file.open(params[0].get_str().c_str()); - if (!file.is_open()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); - - std::map mapKeyBirth; - - std::set setKeyPool; - - pwalletMain->GetKeyBirthTimes(mapKeyBirth); + if(!DumpWallet(pwalletMain, params[0].get_str().c_str() )) + throw JSONRPCError(RPC_WALLET_ERROR, "Error dumping wallet keys to file"); - pwalletMain->GetAllReserveKeys(setKeyPool); - - // sort time/key pairs - std::vector > vKeyBirth; - for (std::map::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { - vKeyBirth.push_back(std::make_pair(it->second, it->first)); - } - mapKeyBirth.clear(); - std::sort(vKeyBirth.begin(), vKeyBirth.end()); - - // produce output - file << strprintf("# Wallet dump created by NovaCoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str()); - file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str()); - file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str()); - file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str()); - file << "\n"; - for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { - const CKeyID &keyid = it->second; - std::string strTime = EncodeDumpTime(it->first); - std::string strAddr = CBitcoinAddress(keyid).ToString(); - bool IsCompressed; - - CKey key; - if (pwalletMain->GetKey(keyid, key)) { - if (pwalletMain->mapAddressBook.count(keyid)) { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s label=%s # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), EncodeDumpString(pwalletMain->mapAddressBook[keyid]).c_str(), strAddr.c_str()); - } else if (setKeyPool.count(keyid)) { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s reserve=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str()); - } else { - CSecret secret = key.GetSecret(IsCompressed); - file << strprintf("%s %s change=1 # addr=%s\n", CBitcoinSecret(secret, IsCompressed).ToString().c_str(), strTime.c_str(), strAddr.c_str()); - } - } - } - file << "\n"; - file << "# End of dump\n"; - file.close(); return Value::null; } diff --git a/src/util.cpp b/src/util.cpp index a527cb2..5422d0b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -24,6 +24,8 @@ namespace boost { #include #include #include + +#include #include #include #include @@ -61,6 +63,7 @@ namespace boost { using namespace std; +namespace bt = boost::posix_time; map mapArgs; map > mapMultiArgs; @@ -80,6 +83,25 @@ bool fLogTimestamps = false; CMedianFilter vTimeOffsets(200,0); bool fReopenDebugLog = false; +// Extended DecodeDumpTime implementation, see this page for details: +// http://stackoverflow.com/questions/3786201/parsing-of-date-time-from-string-boost +const std::locale formats[] = { + std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%dT%H:%M:%SZ")), + std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")), + std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")), + std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")), + std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d")) +}; + +const size_t formats_n = sizeof(formats)/sizeof(formats[0]); + +std::time_t pt_to_time_t(const bt::ptime& pt) +{ + bt::ptime timet_start(boost::gregorian::date(1970,1,1)); + bt::time_duration diff = pt - timet_start; + return diff.ticks()/bt::time_duration::rep_type::ticks_per_second; +} + // Init OpenSSL library multithreading support static CCriticalSection** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) @@ -918,6 +940,51 @@ string DecodeBase32(const string& str) } +int64 DecodeDumpTime(const std::string& s) +{ + bt::ptime pt; + + for(size_t i=0; i> pt; + if(pt != bt::ptime()) break; + } + + return pt_to_time_t(pt); +} + +std::string EncodeDumpTime(int64 nTime) { + return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); +} + +std::string EncodeDumpString(const std::string &str) { + std::stringstream ret; + BOOST_FOREACH(unsigned char c, str) { + if (c <= 32 || c >= 128 || c == '%') { + ret << '%' << HexStr(&c, &c + 1); + } else { + ret << c; + } + } + return ret.str(); +} + +std::string DecodeDumpString(const std::string &str) { + std::stringstream ret; + for (unsigned int pos = 0; pos < str.length(); pos++) { + unsigned char c = str[pos]; + if (c == '%' && pos+2 < str.length()) { + c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) | + ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15)); + pos += 2; + } + ret << c; + } + return ret.str(); +} + bool WildcardMatch(const char* psz, const char* mask) { while (true) diff --git a/src/util.h b/src/util.h index 1d182be..0f08df8 100644 --- a/src/util.h +++ b/src/util.h @@ -204,6 +204,10 @@ std::vector DecodeBase32(const char* p, bool* pfInvalid = NULL); std::string DecodeBase32(const std::string& str); std::string EncodeBase32(const unsigned char* pch, size_t len); std::string EncodeBase32(const std::string& str); +std::string EncodeDumpTime(int64 nTime); +int64 DecodeDumpTime(const std::string& s); +std::string EncodeDumpString(const std::string &str); +std::string DecodeDumpString(const std::string &str); void ParseParameters(int argc, const char*const argv[]); bool WildcardMatch(const char* psz, const char* mask); bool WildcardMatch(const std::string& str, const std::string& mask); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 087ac9b..e23b291 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -5,8 +5,18 @@ #include "walletdb.h" #include "wallet.h" + +#include +#include + #include #include +#include + +#include +#include +#include +#include using namespace std; using namespace boost; @@ -632,6 +642,166 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) return false; } +bool DumpWallet(CWallet* pwallet, const string& strDest) +{ + + if (!pwallet->fFileBacked) + return false; + while (!fShutdown) + { + // Populate maps + std::map mapKeyBirth; + std::set setKeyPool; + pwallet->GetKeyBirthTimes(mapKeyBirth); + pwallet->GetAllReserveKeys(setKeyPool); + + // sort time/key pairs + std::vector > vKeyBirth; + for (std::map::const_iterator it = mapKeyBirth.begin(); it != mapKeyBirth.end(); it++) { + vKeyBirth.push_back(std::make_pair(it->second, it->first)); + } + mapKeyBirth.clear(); + std::sort(vKeyBirth.begin(), vKeyBirth.end()); + + // open outputfile as a stream + ofstream file; + file.open(strDest.c_str()); + if (!file.is_open()) + return false; + + // produce output + file << strprintf("# Wallet dump created by NovaCoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str()); + file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str()); + file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str()); + file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str()); + file << "\n"; + for (std::vector >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) { + const CKeyID &keyid = it->second; + std::string strTime = EncodeDumpTime(it->first); + std::string strAddr = CBitcoinAddress(keyid).ToString(); + bool IsCompressed; + + CKey key; + if (pwallet->GetKey(keyid, key)) { + if (pwallet->mapAddressBook.count(keyid)) { + CSecret secret = key.GetSecret(IsCompressed); + file << strprintf("%s %s label=%s # addr=%s\n", + CBitcoinSecret(secret, IsCompressed).ToString().c_str(), + strTime.c_str(), + EncodeDumpString(pwallet->mapAddressBook[keyid]).c_str(), + strAddr.c_str()); + } else if (setKeyPool.count(keyid)) { + CSecret secret = key.GetSecret(IsCompressed); + file << strprintf("%s %s reserve=1 # addr=%s\n", + CBitcoinSecret(secret, IsCompressed).ToString().c_str(), + strTime.c_str(), + strAddr.c_str()); + } else { + CSecret secret = key.GetSecret(IsCompressed); + file << strprintf("%s %s change=1 # addr=%s\n", + CBitcoinSecret(secret, IsCompressed).ToString().c_str(), + strTime.c_str(), + strAddr.c_str()); + } + } + } + file << "\n"; + file << "# End of dump\n"; + file.close(); + return true; + } + return false; +} + + +bool ImportWallet(CWallet *pwallet, const string& strLocation) +{ + + if (!pwallet->fFileBacked) + return false; + while (!fShutdown) + { + // open inputfile as stream + ifstream file; + file.open(strLocation.c_str()); + if (!file.is_open()) + return false; + + int64 nTimeBegin = pindexBest->nTime; + + bool fGood = true; + + // read through input file checking and importing keys into wallet. + while (file.good()) { + std::string line; + std::getline(file, line); + if (line.empty() || line[0] == '#') + continue; + + std::vector vstr; + boost::split(vstr, line, boost::is_any_of(" ")); + if (vstr.size() < 2) + continue; + CBitcoinSecret vchSecret; + if (!vchSecret.SetString(vstr[0])) + continue; + + bool fCompressed; + CKey key; + CSecret secret = vchSecret.GetSecret(fCompressed); + key.SetSecret(secret, fCompressed); + CKeyID keyid = key.GetPubKey().GetID(); + + if (pwallet->HaveKey(keyid)) { + printf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString().c_str()); + continue; + } + int64 nTime = DecodeDumpTime(vstr[1]); + std::string strLabel; + bool fLabel = true; + for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { + if (boost::algorithm::starts_with(vstr[nStr], "#")) + break; + if (vstr[nStr] == "change=1") + fLabel = false; + if (vstr[nStr] == "reserve=1") + fLabel = false; + if (boost::algorithm::starts_with(vstr[nStr], "label=")) { + strLabel = DecodeDumpString(vstr[nStr].substr(6)); + fLabel = true; + } + } + printf("Importing %s...\n", CBitcoinAddress(keyid).ToString().c_str()); + if (!pwallet->AddKey(key)) { + fGood = false; + continue; + } + pwallet->mapKeyMetadata[keyid].nCreateTime = nTime; + if (fLabel) + pwallet->SetAddressBookName(keyid, strLabel); + nTimeBegin = std::min(nTimeBegin, nTime); + } + file.close(); + + // rescan block chain looking for coins from new keys + CBlockIndex *pindex = pindexBest; + while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200) + pindex = pindex->pprev; + + printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1); + pwallet->ScanForWalletTransactions(pindex); + pwallet->ReacceptWalletTransactions(); + pwallet->MarkDirty(); + + return fGood; + + } + + return false; + +} + + // // Try to (very carefully!) recover wallet.dat if there is a problem. // -- 1.7.1