}
}
-void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
- mapKeyBirth.clear();
+void CWallet::GetAddresses(std::map<CBitcoinAddress, int64_t> &mapAddresses) const {
+ mapAddresses.clear();
// get birth times for keys with metadata
- for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
- if (it->second.nCreateTime)
- mapKeyBirth[it->first] = it->second.nCreateTime;
-
- // map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
- std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
- std::set<CKeyID> setKeys;
- GetKeys(setKeys);
- BOOST_FOREACH(const CKeyID &keyid, setKeys) {
- if (mapKeyBirth.count(keyid) == 0)
- mapKeyFirstBlock[keyid] = pindexMax;
- }
- setKeys.clear();
-
- // if there are no such keys, we're done
- if (mapKeyFirstBlock.empty())
- return;
+ for (std::map<CMalleableKeyView, CKeyMetadata>::const_iterator it = mapMalleableKeyMetadata.begin(); it != mapMalleableKeyMetadata.end(); it++) {
+ CBitcoinAddress addr(it->first.GetMalleablePubKey());
+ mapAddresses[addr] = it->second.nCreateTime ? it->second.nCreateTime : 0;
+ }
+
+ for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) {
+ CBitcoinAddress addr(it->first);
+ mapAddresses[addr] = it->second.nCreateTime ? it->second.nCreateTime : 0;
+ }
- // find first block that affects those keys, if there are any left
- std::vector<CKeyID> vAffected;
for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
// iterate over all wallet transactions...
const CWalletTx &wtx = (*it).second;
- std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
- if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
- // ... which are already in a block
- int nHeight = blit->second->nHeight;
- BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
- // iterate over all their outputs
- ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
- BOOST_FOREACH(const CKeyID &keyid, vAffected) {
- // ... and all their affected keys
- std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
- rit->second = blit->second;
+ if (wtx.hashBlock == 0)
+ continue; // skip unconfirmed transactions
+
+ for(std::vector<CTxOut>::const_iterator it2 = wtx.vout.begin(); it2 != wtx.vout.end(); it2++) {
+ const CTxOut &out = (*it2);
+ // iterate over all their outputs
+ CBitcoinAddress addressRet;
+ if (const_cast<CWallet*>(this)->ExtractAddress(out.scriptPubKey, addressRet)) {
+ if (mapAddresses.find(addressRet) != mapAddresses.end() && mapAddresses[addressRet] > wtx.nTime)
+ mapAddresses[addressRet] = wtx.nTime;
+ }
+ else {
+ // multisig output affects more than one key
+ std::vector<CKeyID> vAffected;
+ ::ExtractAffectedKeys(*this, out.scriptPubKey, vAffected);
+
+ for(std::vector<CKeyID>::const_iterator it3 = vAffected.begin(); it3 != vAffected.end(); it3++) {
+ CBitcoinAddress addrAffected(*it3);
+
+ if (mapAddresses.find(addrAffected) != mapAddresses.end() && mapAddresses[addrAffected] > wtx.nTime)
+ mapAddresses[addrAffected] = wtx.nTime;
}
vAffected.clear();
}
}
- }
- // Extract block timestamps for those keys
- for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
- mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
+ }
}
void CWallet::ClearOrphans()
bool DumpWallet(CWallet* pwallet, const string& strDest)
{
+ if (!pwallet->fFileBacked)
+ return false;
- if (!pwallet->fFileBacked)
- return false;
- while (!fShutdown)
- {
- // Populate maps
- std::map<CKeyID, int64_t> mapKeyBirth;
- std::set<CKeyID> setKeyPool;
- pwallet->GetKeyBirthTimes(mapKeyBirth);
- pwallet->GetAllReserveKeys(setKeyPool);
-
- // sort time/key pairs
- std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
- for (std::map<CKeyID, int64_t>::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());
+ std::map<CBitcoinAddress, int64_t> mapAddresses;
+ std::set<CKeyID> setKeyPool;
- // 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<std::pair<int64_t, CKeyID> >::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;
+ pwallet->GetAddresses(mapAddresses);
+ pwallet->GetAllReserveKeys(setKeyPool);
- 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;
-}
+ // sort time/key pairs
+ std::vector<std::pair<int64_t, CBitcoinAddress> > vAddresses;
+ for (std::map<CBitcoinAddress, int64_t>::const_iterator it = mapAddresses.begin(); it != mapAddresses.end(); it++) {
+ vAddresses.push_back(std::make_pair(it->second, it->first));
+ }
+ mapAddresses.clear();
+ std::sort(vAddresses.begin(), vAddresses.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<std::pair<int64_t, CBitcoinAddress> >::const_iterator it = vAddresses.begin(); it != vAddresses.end(); it++) {
+ const CBitcoinAddress &addr = it->second;
+ std::string strTime = EncodeDumpTime(it->first);
+ std::string strAddr = addr.ToString();
+ bool IsCompressed;
+
+ if (addr.IsPair()) {
+ // Pubkey pair address
+ CMalleableKeyView keyView;
+ CMalleablePubKey mPubKey(addr.GetData());
+ if (pwallet->GetMalleableView(mPubKey, keyView)) {
+ CMalleableKey mKey;
+ pwallet->GetMalleableKey(keyView, mKey);
+
+ file << strprintf("%s %s # addr=%s view=%s\n",
+ mKey.ToString().c_str(),
+ strTime.c_str(),
+ strAddr.c_str(),
+ keyView.ToString().c_str());
+ }
+ }
+ else {
+ // Pubkey hash address
+ CKeyID keyid;
+ addr.GetKeyID(keyid);
+
+ 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;
+}
bool ImportWallet(CWallet *pwallet, const string& strLocation)
{