X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Fwallet.cpp;h=85bf6acebac6d55e7a0111f181023847f84a8201;hp=bfa0e245f8b89af6edf97ba6ca780f9c97ace237;hb=40530c08006088e6f610063f1c49428aa0b272f6;hpb=126e51d5d96f8bc2c900df18af5827c279967dcc diff --git a/src/wallet.cpp b/src/wallet.cpp index bfa0e24..85bf6ac 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -12,6 +12,7 @@ #include "kernel.h" #include "coincontrol.h" #include +#include #include "main.h" @@ -48,7 +49,7 @@ CPubKey CWallet::GenerateNewKey() // Create new metadata int64_t nCreationTime = GetTime(); - mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime); + mapKeyMetadata[CBitcoinAddress(pubkey.GetID())] = CKeyMetadata(nCreationTime); if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) nTimeFirstKey = nCreationTime; @@ -57,6 +58,28 @@ CPubKey CWallet::GenerateNewKey() return key.GetPubKey(); } +CMalleableKeyView CWallet::GenerateNewMalleableKey() +{ + RandAddSeedPerfmon(); + + // Compressed public keys were introduced in version 0.6.0 + SetMinVersion(FEATURE_MALLKEY); + + CMalleableKey mKey; + mKey.MakeNewKeys(); + const CMalleableKeyView &keyView(mKey); + + // Create new metadata + int64_t nCreationTime = GetTime(); + mapKeyMetadata[CBitcoinAddress(keyView.GetMalleablePubKey())] = CKeyMetadata(nCreationTime); + if (!nTimeFirstKey || nCreationTime < nTimeFirstKey) + nTimeFirstKey = nCreationTime; + + if (!AddKey(mKey)) + throw std::runtime_error("CWallet::GenerateNewMalleableKey() : AddKey failed"); + return CMalleableKeyView(mKey); +} + bool CWallet::AddKey(const CKey& key) { CPubKey pubkey = key.GetPubKey(); @@ -65,7 +88,40 @@ bool CWallet::AddKey(const CKey& key) if (!fFileBacked) return true; if (!IsCrypted()) - return CWalletDB(strWalletFile).WriteKey(pubkey, key.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); + return CWalletDB(strWalletFile).WriteKey(pubkey, key.GetPrivKey(), mapKeyMetadata[CBitcoinAddress(pubkey.GetID())]); + return true; +} + +bool CWallet::AddKey(const CMalleableKey& mKey) +{ + CMalleableKeyView keyView = CMalleableKeyView(mKey); + CSecret vchSecretH = mKey.GetSecretH(); + if (!CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH)) + return false; + if (!fFileBacked) + return true; + if (!IsCrypted()) + return CWalletDB(strWalletFile).WriteMalleableKey(keyView, vchSecretH, mapKeyMetadata[CBitcoinAddress(keyView.GetMalleablePubKey())]); + return true; +} + +bool CWallet::AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector &vchCryptedSecretH) +{ + if (!CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH)) + return false; + + if (!fFileBacked) + return true; + + { + LOCK(cs_wallet); + CBitcoinAddress addr(keyView.GetMalleablePubKey()); + if (pwalletdbEncryption) + return pwalletdbEncryption->WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapKeyMetadata[addr]); + else + return CWalletDB(strWalletFile).WriteCryptedMalleableKey(keyView, vchCryptedSecretH, mapKeyMetadata[addr]); + } + return true; } @@ -84,10 +140,11 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vectorWriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); + return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[addr]); else - return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); + return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret, mapKeyMetadata[addr]); } return false; } @@ -97,7 +154,16 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey)) nTimeFirstKey = meta.nCreateTime; - mapKeyMetadata[pubkey.GetID()] = meta; + mapKeyMetadata[CBitcoinAddress(pubkey.GetID())] = meta; + return true; +} + +bool CWallet::LoadKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata) +{ + if (metadata.nCreateTime && (!nTimeFirstKey || metadata.nCreateTime < nTimeFirstKey)) + nTimeFirstKey = metadata.nCreateTime; + + mapKeyMetadata[CBitcoinAddress(keyView.GetMalleablePubKey())] = metadata; return true; } @@ -204,11 +270,13 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, { int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); - pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime))); + double nFirstMultiplier = 1e2 / (GetTimeMillis() - nStartTime); + pMasterKey.second.nDeriveIterations = (uint32_t)(pMasterKey.second.nDeriveIterations *nFirstMultiplier); nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); - pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2; + double nSecondMultiplier = 1e2 / (GetTimeMillis() - nStartTime); + pMasterKey.second.nDeriveIterations = (uint32_t)((pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * nSecondMultiplier) / 2); if (pMasterKey.second.nDeriveIterations < 25000) pMasterKey.second.nDeriveIterations = 25000; @@ -305,11 +373,13 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) CCrypter crypter; int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod); - kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime)); + int64_t nDivider = GetTimeMillis() - nStartTime; + kMasterKey.nDeriveIterations = (uint32_t)(25e5 / (double)(nDivider)); nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod); - kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2; + double nMultiplier = 1e2 / (GetTimeMillis() - nStartTime); + kMasterKey.nDeriveIterations = (uint32_t)((kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * nMultiplier) / 2); if (kMasterKey.nDeriveIterations < 25000) kMasterKey.nDeriveIterations = 25000; @@ -409,10 +479,20 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) CKey key; key.SetSecret((*mi).second.first, (*mi).second.second); pwalletdbDecryption->EraseCryptedKey(key.GetPubKey()); - pwalletdbDecryption->WriteKey(key.GetPubKey(), key.GetPrivKey(), mapKeyMetadata[(*mi).first]); + pwalletdbDecryption->WriteKey(key.GetPubKey(), key.GetPrivKey(), mapKeyMetadata[CBitcoinAddress(mi->first)]); mi++; } + MalleableKeyMap::const_iterator mi2 = mapMalleableKeys.begin(); + while (mi2 != mapMalleableKeys.end()) + { + const CSecret &vchSecretH = mi2->second; + const CMalleableKeyView &keyView = mi2->first; + pwalletdbDecryption->EraseCryptedMalleableKey(keyView); + pwalletdbDecryption->WriteMalleableKey(keyView, vchSecretH, mapKeyMetadata[CBitcoinAddress(keyView.GetMalleablePubKey())]); + mi2++; + } + // Erase master keys MasterKeyMap::const_iterator mk = mapMasterKeys.begin(); while (mk != mapMasterKeys.end()) @@ -437,6 +517,19 @@ bool CWallet::DecryptWallet(const SecureString& strWalletPassphrase) return true; } +bool CWallet::GetPEM(const CKeyID &keyID, const std::string &fileName, const SecureString &strPassKey) const +{ + BIO *pemOut = BIO_new_file(fileName.c_str(), "w"); + if (pemOut == NULL) + return error("GetPEM() : failed to create file %s\n", fileName.c_str()); + CKey key; + if (!GetKey(keyID, key)) + return error("GetPEM() : failed to get key for address=%s\n", CBitcoinAddress(keyID).ToString().c_str()); + bool result = key.WritePEM(pemOut, strPassKey); + BIO_free(pemOut); + return result; +} + int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { int64_t nRet = nOrderPosNext++; @@ -664,14 +757,14 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl uint256 hash = tx.GetHash(); { LOCK(cs_wallet); - bool fExisted = mapWallet.count(hash); + bool fExisted = mapWallet.count(hash) != 0; if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) { CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block if (pblock) - wtx.SetMerkleBranch(pblock); + wtx.SetMerkleBranch(*pblock); return AddToWallet(wtx); } else @@ -790,8 +883,8 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list >& listReceived, - list >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const +void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list >& listReceived, + list >& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const { nGeneratedImmature = nGeneratedMature = nFee = 0; listReceived.clear(); @@ -832,12 +925,12 @@ void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMatur continue; // In either case, we need to get the destination address - CTxDestination address; - if (!ExtractDestination(txout.scriptPubKey, address)) + CBitcoinAddress address; + if (!ExtractAddress(*pwallet, txout.scriptPubKey, address)) { printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str()); - address = CNoDestination(); + address = CBitcoinAddress(); } // If we are debited by the transaction, add the output as a "sent" entry @@ -859,25 +952,25 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nGenerated, int64_t allGeneratedImmature, allGeneratedMature, allFee; allGeneratedImmature = allGeneratedMature = allFee = 0; string strSentAccount; - list > listReceived; - list > listSent; + list > listReceived; + list > listSent; GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount, filter); - if (strAccount == "") + if (strAccount.empty()) nGenerated = allGeneratedMature; if (strAccount == strSentAccount) { - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& s, listSent) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& s, listSent) nSent += s.second; nFee = allFee; } { LOCK(pwallet->cs_wallet); - BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived) + BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived) { if (pwallet->mapAddressBook.count(r.first)) { - map::const_iterator mi = pwallet->mapAddressBook.find(r.first); + map::const_iterator mi = pwallet->mapAddressBook.find(r.first); if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) nReceived += r.second; } @@ -1075,23 +1168,25 @@ void CWalletTx::RelayWalletTransaction() RelayWalletTransaction(txdb); } -void CWallet::ResendWalletTransactions() +void CWallet::ResendWalletTransactions(bool fForceResend) { - // Do this infrequently and randomly to avoid giving away - // that these are our transactions. - static int64_t nNextTime; - if (GetTime() < nNextTime) - return; - bool fFirst = (nNextTime == 0); - nNextTime = GetTime() + GetRand(30 * 60); - if (fFirst) - return; + if (!fForceResend) { + // Do this infrequently and randomly to avoid giving away + // that these are our transactions. + static int64_t nNextTime = GetRand(GetTime() + 30 * 60); + if (GetTime() < nNextTime) + return; + bool fFirst = (nNextTime == 0); + nNextTime = GetTime() + GetRand(30 * 60); + if (fFirst) + return; - // Only do it if there's been a new block since last time - static int64_t nLastTime; - if (nTimeBestReceived < nLastTime) - return; - nLastTime = GetTime(); + // Only do it if there's been a new block since last time + static int64_t nLastTime = 0; + if (nTimeBestReceived < nLastTime) + return; + nLastTime = GetTime(); + } // Rebroadcast any of our txes that aren't in a block yet printf("ResendWalletTransactions()\n"); @@ -1105,7 +1200,7 @@ void CWallet::ResendWalletTransactions() CWalletTx& wtx = item.second; // Don't rebroadcast until it's had plenty of time that // it should have gotten in already by now. - if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) + if (fForceResend || nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); } BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) @@ -1579,7 +1674,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CTxDB txdb("r"); { nFeeRet = nTransactionFee; - while (true) + for ( ; ; ) { wtxNew.vin.clear(); wtxNew.vout.clear(); @@ -1611,8 +1706,8 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CScript scriptChange; // coin control: send change to custom address - if (coinControl && !boost::get(&coinControl->destChange)) - scriptChange.SetDestination(coinControl->destChange); + if (coinControl && coinControl->destChange.IsValid()) + scriptChange.SetAddress(coinControl->destChange); // no coin control: send change to newly generated address else @@ -1684,7 +1779,7 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& void CWallet::GetStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight) { - int64_t nTimeWeight = GetWeight(nTime, (int64_t)GetTime()); + int64_t nTimeWeight = GetWeight(nTime, GetTime()); // If time weight is lower or equal to zero then weight is zero. if (nTimeWeight <= 0) @@ -1693,44 +1788,10 @@ void CWallet::GetStakeWeightFromValue(const int64_t& nTime, const int64_t& nValu return; } - CBigNum bnCoinDayWeight = CBigNum(nValue) * nTimeWeight / COIN / (24 * 60 * 60); + CBigNum bnCoinDayWeight = CBigNum(nValue) * nTimeWeight / COIN / nOneDay; nWeight = bnCoinDayWeight.getuint64(); } - -// NovaCoin: get current stake miner statistics -void CWallet::GetStakeStats(float &nKernelsRate, float &nCoinDaysRate) -{ - static uint64_t nLastKernels = 0, nLastCoinDays = 0; - static float nLastKernelsRate = 0, nLastCoinDaysRate = 0; - static int64_t nLastTime = GetTime(); - - if (nKernelsTried < nLastKernels) - { - nLastKernels = 0; - nLastCoinDays = 0; - - nLastTime = GetTime(); - } - - int64_t nInterval = GetTime() - nLastTime; - //if (nKernelsTried > 1000 && nInterval > 5) - if (nInterval > 10) - { - nKernelsRate = nLastKernelsRate = ( nKernelsTried - nLastKernels ) / (float) nInterval; - nCoinDaysRate = nLastCoinDaysRate = ( nCoinDaysTried - nLastCoinDays ) / (float) nInterval; - - nLastKernels = nKernelsTried; - nLastCoinDays = nCoinDaysTried; - nLastTime = GetTime(); - } - else - { - nKernelsRate = nLastKernelsRate; - nCoinDaysRate = nLastCoinDaysRate; - } -} - bool CWallet::MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const int64_t& nOutputValue, list& listMerged) { int64_t nBalance = GetBalance(); @@ -1925,7 +1986,7 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati if (setCoins.empty()) return false; - bool fMaxTimeWeight = false; + bool fDontSplitCoins = false; if (GetWeight((int64_t)wtx.nTime, (int64_t)nGenerationTime) == nStakeMaxAge) { // Only one output for old kernel inputs @@ -1968,16 +2029,29 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati vwtxPrev.push_back(pcoin->first); } - fMaxTimeWeight = true; + fDontSplitCoins = true; } else { - // Split stake input if maximum weight isn't reached yet - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + int64_t nSplitThreshold = GetArg("-splitthreshold", nCombineThreshold); if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : maximum time weight isn't reached, splitting coinstake\n"); + printf("CreateCoinStake : nSplitThreshold=%" PRId64 "\n", nSplitThreshold); + + if (nCredit > nSplitThreshold) + { + // Split stake input if credit is lower than combine threshold and maximum weight isn't reached yet + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + + if (fDebug && GetBoolArg("-printcoinstake")) + printf("CreateCoinStake : splitting coinstake\n"); + } + else + { + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + fDontSplitCoins = true; + } } // Calculate coin age reward @@ -1988,10 +2062,10 @@ bool CWallet::CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nGenerati nCredit += GetProofOfStakeReward(nCoinAge, nBits, nGenerationTime); int64_t nMinFee = 0; - while (true) + for ( ; ; ) { // Set output amount - if (fMaxTimeWeight) + if (fDontSplitCoins) txNew.vout[1].nValue = nCredit - nMinFee; else { @@ -2065,7 +2139,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) AddToWallet(wtxNew); // Mark old coins as spent - set setCoins; BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) { CWalletTx &coin = mapWallet[txin.prevout.hash]; @@ -2088,6 +2161,12 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) { + // Check amount + if (nValue <= 0) + return _("Invalid amount"); + if (nValue + nTransactionFee > GetBalance()) + return _("Insufficient funds"); + CReserveKey reservekey(this); int64_t nFeeRequired; @@ -2123,26 +2202,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe return ""; } - - -string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) -{ - // Check amount - if (nValue <= 0) - return _("Invalid amount"); - if (nValue + nTransactionFee > GetBalance()) - return _("Insufficient funds"); - - // Parse Bitcoin address - CScript scriptPubKey; - scriptPubKey.SetDestination(address); - - return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee); -} - - - - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) @@ -2193,21 +2252,26 @@ DBErrors CWallet::ZapWalletTx() bool CWallet::SetAddressBookName(const CTxDestination& address, const string& strName) { - std::map::iterator mi = mapAddressBook.find(address); + return SetAddressBookName(CBitcoinAddress(address), strName); +} + +bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName) +{ + std::map::iterator mi = mapAddressBook.find(address); mapAddressBook[address] = strName; - NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); + NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address) != MINE_NO, (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); if (!fFileBacked) return false; - return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); + return CWalletDB(strWalletFile).WriteName(address.ToString(), strName); } -bool CWallet::DelAddressBookName(const CTxDestination& address) +bool CWallet::DelAddressBookName(const CBitcoinAddress& address) { mapAddressBook.erase(address); - NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED); + NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address) != MINE_NO, CT_DELETED); if (!fFileBacked) return false; - return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); + return CWalletDB(strWalletFile).EraseName(address.ToString()); } @@ -2427,9 +2491,9 @@ int64_t CWallet::GetOldestKeyPoolTime() return keypool.nTime; } -std::map CWallet::GetAddressBalances() +std::map CWallet::GetAddressBalances() { - map balances; + map balances; { LOCK(cs_wallet); @@ -2449,10 +2513,10 @@ std::map CWallet::GetAddressBalances() for (unsigned int i = 0; i < pcoin->vout.size(); i++) { - CTxDestination addr; + CBitcoinAddress addr; if (!IsMine(pcoin->vout[i])) continue; - if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr)) + if(!ExtractAddress(*this, pcoin->vout[i].scriptPubKey, addr)) continue; int64_t n = pcoin->IsSpent(i) ? 0 : pcoin->vout[i].nValue; @@ -2467,10 +2531,10 @@ std::map CWallet::GetAddressBalances() return balances; } -set< set > CWallet::GetAddressGroupings() +set< set > CWallet::GetAddressGroupings() { - set< set > groupings; - set grouping; + set< set > groupings; + set grouping; BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) { @@ -2481,8 +2545,8 @@ set< set > CWallet::GetAddressGroupings() // group all input addresses with each other BOOST_FOREACH(CTxIn txin, pcoin->vin) { - CTxDestination address; - if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address)) + CBitcoinAddress address; + if(!ExtractAddress(*this, mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address)) continue; grouping.insert(address); } @@ -2492,8 +2556,8 @@ set< set > CWallet::GetAddressGroupings() if (IsChange(txout)) { CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash]; - CTxDestination txoutAddr; - if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) + CBitcoinAddress txoutAddr; + if(!ExtractAddress(*this, txout.scriptPubKey, txoutAddr)) continue; grouping.insert(txoutAddr); } @@ -2505,8 +2569,8 @@ set< set > CWallet::GetAddressGroupings() for (unsigned int i = 0; i < pcoin->vout.size(); i++) if (IsMine(pcoin->vout[i])) { - CTxDestination address; - if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address)) + CBitcoinAddress address; + if(!ExtractAddress(*this, pcoin->vout[i].scriptPubKey, address)) continue; grouping.insert(address); groupings.insert(grouping); @@ -2514,20 +2578,20 @@ set< set > CWallet::GetAddressGroupings() } } - set< set* > uniqueGroupings; // a set of pointers to groups of addresses - map< CTxDestination, set* > setmap; // map addresses to the unique group containing it - BOOST_FOREACH(set grouping, groupings) + set< set* > uniqueGroupings; // a set of pointers to groups of addresses + map< CBitcoinAddress, set* > setmap; // map addresses to the unique group containing it + BOOST_FOREACH(set grouping, groupings) { // make a set of all the groups hit by this new group - set< set* > hits; - map< CTxDestination, set* >::iterator it; - BOOST_FOREACH(CTxDestination address, grouping) + set< set* > hits; + map< CBitcoinAddress, set* >::iterator it; + BOOST_FOREACH(CBitcoinAddress address, grouping) if ((it = setmap.find(address)) != setmap.end()) hits.insert((*it).second); // merge all hit groups into a new single group and delete old groups - set* merged = new set(grouping); - BOOST_FOREACH(set* hit, hits) + set* merged = new set(grouping); + BOOST_FOREACH(set* hit, hits) { merged->insert(hit->begin(), hit->end()); uniqueGroupings.erase(hit); @@ -2536,12 +2600,12 @@ set< set > CWallet::GetAddressGroupings() uniqueGroupings.insert(merged); // update setmap - BOOST_FOREACH(CTxDestination element, *merged) + BOOST_FOREACH(CBitcoinAddress element, *merged) setmap[element] = merged; } - set< set > ret; - BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) + set< set > ret; + BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) { ret.insert(*uniqueGrouping); delete uniqueGrouping; @@ -2574,7 +2638,7 @@ void CWallet::FixSpentCoins(int& nMismatchFound, int64_t& nBalanceInQuestion, bo { if (IsMine(pcoin->vout[n]) && pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull())) { - printf("FixSpentCoins found lost coin %sppc %s[%d], %s\n", + printf("FixSpentCoins found lost coin %sppc %s[%u], %s\n", FormatMoney(pcoin->vout[n].nValue).c_str(), pcoin->GetHash().ToString().c_str(), n, fCheckOnly? "repair not attempted" : "repairing"); nMismatchFound++; nBalanceInQuestion += pcoin->vout[n].nValue; @@ -2586,7 +2650,7 @@ void CWallet::FixSpentCoins(int& nMismatchFound, int64_t& nBalanceInQuestion, bo } else if (IsMine(pcoin->vout[n]) && !pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull())) { - printf("FixSpentCoins found spent coin %sppc %s[%d], %s\n", + printf("FixSpentCoins found spent coin %sppc %s[%u], %s\n", FormatMoney(pcoin->vout[n].nValue).c_str(), pcoin->GetHash().ToString().c_str(), n, fCheckOnly? "repair not attempted" : "repairing"); nMismatchFound++; nBalanceInQuestion += pcoin->vout[n].nValue; @@ -2700,55 +2764,42 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } -void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { - mapKeyBirth.clear(); +void CWallet::GetAddresses(std::map &mapAddresses) const { + mapAddresses.clear(); // get birth times for keys with metadata - for (std::map::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 mapKeyFirstBlock; - std::set 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::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++) { + mapAddresses[it->first] = it->second.nCreateTime ? it->second.nCreateTime : 0; + } - // find first block that affects those keys, if there are any left - std::vector vAffected; for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { // iterate over all wallet transactions... const CWalletTx &wtx = (*it).second; - std::map::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::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::const_iterator it2 = wtx.vout.begin(); it2 != wtx.vout.end(); it2++) { + const CTxOut &out = (*it2); + // iterate over all their outputs + CBitcoinAddress addressRet; + if (ExtractAddress(*this, out.scriptPubKey, addressRet)) { + if (mapAddresses.find(addressRet) != mapAddresses.end() && (mapAddresses[addressRet] == 0 || mapAddresses[addressRet] > wtx.nTime)) + mapAddresses[addressRet] = wtx.nTime; + } + else { + // multisig output affects more than one key + std::vector vAffected; + ::ExtractAffectedKeys(*this, out.scriptPubKey, vAffected); + + for(std::vector::const_iterator it3 = vAffected.begin(); it3 != vAffected.end(); it3++) { + CBitcoinAddress addrAffected(*it3); + if (mapAddresses.find(addrAffected) != mapAddresses.end() && (mapAddresses[addrAffected] == 0 || mapAddresses[addrAffected] > wtx.nTime)) + mapAddresses[addrAffected] = wtx.nTime; } vAffected.clear(); } } } - - // Extract block timestamps for those keys - for (std::map::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() @@ -2768,3 +2819,4 @@ void CWallet::ClearOrphans() for(list::const_iterator it = orphans.begin(); it != orphans.end(); ++it) EraseFromWallet(*it); } +