From 78ba2a560985731e965bcf1d79d46714de43c0b2 Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Thu, 25 Jul 2013 12:06:56 -0300 Subject: [PATCH] another big wallet cleanup --- src/bitcoinrpc.h | 1 - src/init.cpp | 2 + src/rpcdump.cpp | 2 - src/rpcwallet.cpp | 3 - src/wallet.cpp | 515 +--------------------------------------------- src/wallet.h | 50 ----- src/walletdb.cpp | 2 - 7 files changed, 5 insertions(+), 570 deletions(-) diff --git a/src/bitcoinrpc.h b/src/bitcoinrpc.h index 0f0856ec..590a82d7 100644 --- a/src/bitcoinrpc.h +++ b/src/bitcoinrpc.h @@ -11,7 +11,6 @@ #include class CBlockIndex; -class CReserveKey; #include "json/json_spirit_reader_template.h" #include "json/json_spirit_writer_template.h" diff --git a/src/init.cpp b/src/init.cpp index e5e66ca1..b57564d4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -840,12 +840,14 @@ bool AppInit2(boost::thread_group& threadGroup) // Create new keyUser and set as default key RandAddSeedPerfmon(); + /* [MF] FIXME: require user on initialization? CPubKey newDefaultKey; if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) { pwalletMain->SetDefaultKey(newDefaultKey); if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), "")) strErrors << _("Cannot write default address") << "\n"; } + */ pwalletMain->SetBestChain(CBlockLocator(pindexBest)); } diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 37e427d9..2f19880a 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -228,9 +228,7 @@ Value dumpwallet(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); std::map mapKeyBirth; - std::set setKeyPool; pwalletMain->GetKeyBirthTimes(mapKeyBirth); - pwalletMain->GetAllReserveKeys(setKeyPool); // sort time/key pairs std::vector > vKeyBirth; diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index b53c0f6e..ca9534ed 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -80,9 +80,6 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("proxy", (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", TestNet())); - obj.push_back(Pair("keypoololdest", (boost::int64_t)pwalletMain->GetOldestKeyPoolTime())); - obj.push_back(Pair("keypoolsize", pwalletMain->GetKeyPoolSize())); - obj.push_back(Pair("paytxfee", ValueFromAmount(nTransactionFee))); if (pwalletMain->IsCrypted()) obj.push_back(Pair("unlocked_until", (boost::int64_t)nWalletUnlockTime)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); diff --git a/src/wallet.cpp b/src/wallet.cpp index 8a843305..864af444 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -49,6 +49,9 @@ CPubKey CWallet::GenerateNewKey(std::string username) if (!AddKeyPubKey(secret, pubkey)) throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed"); + + if (!vchDefaultKey.IsValid()) + vchDefaultKey = pubkey; return pubkey; } @@ -683,253 +686,6 @@ void CWallet::ResendWalletTransactions() // Actions // -bool CWallet::CreateTransaction(const vector >& vecSend, - CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason) -{ - int64 nValue = 0; - BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) - { - if (nValue < 0) - { - strFailReason = _("Transaction amounts must be positive"); - return false; - } - nValue += s.second; - } - if (vecSend.empty() || nValue < 0) - { - strFailReason = _("Transaction amounts must be positive"); - return false; - } - - wtxNew.BindWallet(this); - - { - LOCK2(cs_main, cs_wallet); - { - nFeeRet = nTransactionFee; - /* - loop - { - wtxNew.vin.clear(); - wtxNew.vout.clear(); - wtxNew.fFromMe = true; - - int64 nTotalValue = nValue + nFeeRet; - double dPriority = 0; - // vouts to the payees - BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend) - { - CTxOut txout(s.second, s.first); - if (txout.IsDust(CTransaction::nMinRelayTxFee)) - { - strFailReason = _("Transaction amount too small"); - return false; - } - wtxNew.vout.push_back(txout); - } - - // Choose coins to use - set > setCoins; - int64 nValueIn = 0; - if (!SelectCoins(nTotalValue, setCoins, nValueIn)) - { - strFailReason = _("Insufficient funds"); - return false; - } - BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) - { - int64 nCredit = pcoin.first->vout[pcoin.second].nValue; - //The priority after the next block (depth+1) is used instead of the current, - //reflecting an assumption the user would accept a bit more delay for - //a chance at a free transaction. - dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1); - } - - int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least nMinTxFee - // or until nChange becomes zero - // NOTE: this depends on the exact behaviour of GetMinFee - if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) - { - int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); - nChange -= nMoveToFee; - nFeeRet += nMoveToFee; - } - - if (nChange > 0) - { - // Note: We use a new key here to keep it from being obvious which side is the change. - // The drawback is that by not reusing a previous key, the change may be lost if a - // backup is restored, if the backup doesn't have the new private key for the change. - // If we reused the old key, it would be possible to add code to look for and - // rediscover unknown transactions that were written with keys of ours to recover - // post-backup change. - - // Reserve a new key pair from key pool - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - - // Fill a vout to ourself - // TODO: pass in scriptChange instead of reservekey so - // change transaction isn't always pay-to-bitcoin-address - CScript scriptChange; - scriptChange.SetDestination(vchPubKey.GetID()); - - CTxOut newTxOut(nChange, scriptChange); - - // Never create dust outputs; if we would, just - // add the dust to the fee. - if (newTxOut.IsDust(CTransaction::nMinRelayTxFee)) - { - nFeeRet += nChange; - reservekey.ReturnKey(); - } - else - { - // Insert change txn at random position: - vector::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); - wtxNew.vout.insert(position, newTxOut); - } - } - else - reservekey.ReturnKey(); - - // Fill vin - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) - wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); - - // Sign - int nIn = 0; - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) - if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) - { - strFailReason = _("Signing transaction failed"); - return false; - } - - // Limit size - unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= MAX_STANDARD_TX_SIZE) - { - strFailReason = _("Transaction too large"); - return false; - } - dPriority /= nBytes; - - // Check that enough fee is included - int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); - bool fAllowFree = AllowFree(dPriority); - int64 nMinFee = GetMinFee(wtxNew, fAllowFree, GMF_SEND); - if (nFeeRet < max(nPayFee, nMinFee)) - { - nFeeRet = max(nPayFee, nMinFee); - continue; - } - - // Fill vtxPrev by copying from previous transactions vtxPrev - wtxNew.AddSupportingTransactions(); - wtxNew.fTimeReceivedIsTxTime = true; - - break; - } - */ - } - } - return true; -} - -bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, - CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason) -{ - vector< pair > vecSend; - vecSend.push_back(make_pair(scriptPubKey, nValue)); - return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason); -} - -// Call after CreateTransaction unless you want to abort -bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) -{ - { - LOCK2(cs_main, cs_wallet); - printf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); - { - // This is only to keep the database open to defeat the auto-flush for the - // duration of this scope. This is the only place where this optimization - // maybe makes sense; please don't do it anywhere else. - CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL; - - // Take key pair from key pool so it won't be used again - reservekey.KeepKey(); - - // Add tx to wallet, because if it has change it's also ours, - // otherwise just for transaction history. - AddToWallet(wtxNew); - - // Mark old coins as spent - set setCoins; - /* - BOOST_FOREACH(const CTxIn& txin, wtxNew.vin) - { - CWalletTx &coin = mapWallet[txin.prevout.hash]; - coin.BindWallet(this); - coin.MarkSpent(txin.prevout.n); - coin.WriteToDisk(); - NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED); - } - */ - - if (fFileBacked) - delete pwalletdb; - } - - // Track how many getdata requests our transaction gets - mapRequestCount[wtxNew.GetHash()] = 0; - - // Broadcast - if (!wtxNew.AcceptToMemoryPool(false)) - { - // This must not fail. The transaction has already been signed and recorded. - printf("CommitTransaction() : Error: Transaction not valid"); - return false; - } - wtxNew.RelayWalletTransaction(); - } - return true; -} - - - - -string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) -{ - CReserveKey reservekey(this); - int64 nFeeRequired; - - if (IsLocked()) - { - string strError = _("Error: Wallet locked, unable to create transaction!"); - printf("SendMoney() : %s", strError.c_str()); - return strError; - } - string strError; - if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) - { - printf("SendMoney() : %s\n", strError.c_str()); - return strError; - } - - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired)) - return "ABORTED"; - - if (!CommitTransaction(wtxNew, reservekey)) - return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); - - return ""; -} - - - DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) @@ -955,24 +711,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } -bool CWallet::SetAddressBookName(const CTxDestination& 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); - if (!fFileBacked) - return false; - return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); -} - -bool CWallet::DelAddressBookName(const CTxDestination& address) -{ - mapAddressBook.erase(address); - NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED); - if (!fFileBacked) - return false; - return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); -} bool CWallet::SetDefaultKey(const CPubKey &vchPubKey) @@ -995,253 +733,6 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) } -void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) -{ - nIndex = -1; - keypool.vchPubKey = CPubKey(); - { - LOCK(cs_wallet); - - // Get the oldest key - if(setKeyPool.empty()) - return; - - CWalletDB walletdb(strWalletFile); - - nIndex = *(setKeyPool.begin()); - setKeyPool.erase(setKeyPool.begin()); - if (!walletdb.ReadPool(nIndex, keypool)) - throw runtime_error("ReserveKeyFromKeyPool() : read failed"); - if (!HaveKey(keypool.vchPubKey.GetID())) - throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); - assert(keypool.vchPubKey.IsValid()); - printf("keypool reserve %"PRI64d"\n", nIndex); - } -} - -int64 CWallet::AddReserveKey(const CKeyPool& keypool) -{ - { - LOCK2(cs_main, cs_wallet); - CWalletDB walletdb(strWalletFile); - - int64 nIndex = 1 + *(--setKeyPool.end()); - if (!walletdb.WritePool(nIndex, keypool)) - throw runtime_error("AddReserveKey() : writing added key failed"); - setKeyPool.insert(nIndex); - return nIndex; - } - return -1; -} - -void CWallet::KeepKey(int64 nIndex) -{ - // Remove from key pool - if (fFileBacked) - { - CWalletDB walletdb(strWalletFile); - walletdb.ErasePool(nIndex); - } - printf("keypool keep %"PRI64d"\n", nIndex); -} - -void CWallet::ReturnKey(int64 nIndex) -{ - // Return to key pool - { - LOCK(cs_wallet); - setKeyPool.insert(nIndex); - } - printf("keypool return %"PRI64d"\n", nIndex); -} - -bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse) -{ - /* [MF] pool is going to die. - int64 nIndex = 0; - CKeyPool keypool; - { - LOCK(cs_wallet); - ReserveKeyFromKeyPool(nIndex, keypool); - if (nIndex == -1) - { - if (fAllowReuse && vchDefaultKey.IsValid()) - { - result = vchDefaultKey; - return true; - } - if (IsLocked()) return false; - result = GenerateNewKey(); - return true; - } - KeepKey(nIndex); - result = keypool.vchPubKey; - } - return true; - */ - return false; -} - -int64 CWallet::GetOldestKeyPoolTime() -{ - int64 nIndex = 0; - CKeyPool keypool; - ReserveKeyFromKeyPool(nIndex, keypool); - if (nIndex == -1) - return GetTime(); - ReturnKey(nIndex); - return keypool.nTime; -} - -set< set > CWallet::GetAddressGroupings() -{ - set< set > groupings; - set grouping; - - BOOST_FOREACH(PAIRTYPE(uint256, CWalletTx) walletEntry, mapWallet) - { - CWalletTx *pcoin = &walletEntry.second; -/* - if (pcoin->vin.size() > 0) - { - bool any_mine = false; - // group all input addresses with each other - BOOST_FOREACH(CTxIn txin, pcoin->vin) - { - CTxDestination address; - if(!IsMine(txin)) - continue; - if(!ExtractDestination(mapWallet[txin.prevout.hash].vout[txin.prevout.n].scriptPubKey, address)) - continue; - grouping.insert(address); - any_mine = true; - } - - // group change with input addresses - if (any_mine) - { - BOOST_FOREACH(CTxOut txout, pcoin->vout) - if (IsChange(txout)) - { - CTxDestination txoutAddr; - if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) - continue; - grouping.insert(txoutAddr); - } - } - if (grouping.size() > 0) - { - groupings.insert(grouping); - grouping.clear(); - } - } - - // group lone addrs by themselves - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (IsMine(pcoin->vout[i])) - { - CTxDestination address; - if(!ExtractDestination(pcoin->vout[i].scriptPubKey, address)) - continue; - grouping.insert(address); - groupings.insert(grouping); - grouping.clear(); - } - */ - } - - 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) - { - // 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) - 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) - { - merged->insert(hit->begin(), hit->end()); - uniqueGroupings.erase(hit); - delete hit; - } - uniqueGroupings.insert(merged); - - // update setmap - BOOST_FOREACH(CTxDestination element, *merged) - setmap[element] = merged; - } - - set< set > ret; - BOOST_FOREACH(set* uniqueGrouping, uniqueGroupings) - { - ret.insert(*uniqueGrouping); - delete uniqueGrouping; - } - - return ret; -} - -bool CReserveKey::GetReservedKey(CPubKey& pubkey) -{ - if (nIndex == -1) - { - CKeyPool keypool; - pwallet->ReserveKeyFromKeyPool(nIndex, keypool); - if (nIndex != -1) - vchPubKey = keypool.vchPubKey; - else { - if (pwallet->vchDefaultKey.IsValid()) { - printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); - vchPubKey = pwallet->vchDefaultKey; - } else - return false; - } - } - assert(vchPubKey.IsValid()); - pubkey = vchPubKey; - return true; -} - -void CReserveKey::KeepKey() -{ - if (nIndex != -1) - pwallet->KeepKey(nIndex); - nIndex = -1; - vchPubKey = CPubKey(); -} - -void CReserveKey::ReturnKey() -{ - if (nIndex != -1) - pwallet->ReturnKey(nIndex); - nIndex = -1; - vchPubKey = CPubKey(); -} - -void CWallet::GetAllReserveKeys(set& setAddress) const -{ - setAddress.clear(); - - CWalletDB walletdb(strWalletFile); - - LOCK2(cs_main, cs_wallet); - BOOST_FOREACH(const int64& id, setKeyPool) - { - CKeyPool keypool; - if (!walletdb.ReadPool(id, keypool)) - throw runtime_error("GetAllReserveKeyHashes() : read failed"); - assert(keypool.vchPubKey.IsValid()); - CKeyID keyID = keypool.vchPubKey.GetID(); - if (!HaveKey(keyID)) - throw runtime_error("GetAllReserveKeyHashes() : unknown key in key pool"); - setAddress.insert(keyID); - } -} void CWallet::UpdatedTransaction(const uint256 &hashTx) { diff --git a/src/wallet.h b/src/wallet.h index 11d23061..a48dcd4d 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -20,7 +20,6 @@ #include "util.h" class CWalletTx; -class CReserveKey; class COutput; class CWalletDB; @@ -160,22 +159,6 @@ public: int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(); - bool CreateTransaction(const std::vector >& vecSend, - CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); - bool CreateTransaction(CScript scriptPubKey, int64 nValue, - CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); - bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); - std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); - - int64 AddReserveKey(const CKeyPool& keypool); - void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); - void KeepKey(int64 nIndex); - void ReturnKey(int64 nIndex); - bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true); - int64 GetOldestKeyPoolTime(); - void GetAllReserveKeys(std::set& setAddress) const; - - std::set< std::set > GetAddressGroupings(); bool IsMine(const CTransaction& tx) const { @@ -189,10 +172,6 @@ public: DBErrors LoadWallet(bool& fFirstRunRet); - bool SetAddressBookName(const CTxDestination& address, const std::string& strName); - - bool DelAddressBookName(const CTxDestination& address); - void UpdatedTransaction(const uint256 &hashTx); void PrintWallet(const CBlock& block); @@ -207,11 +186,6 @@ public: } } - int GetKeyPoolSize() - { - return setKeyPool.size(); - } - bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx); bool SetDefaultKey(const CPubKey &vchPubKey); @@ -236,30 +210,6 @@ public: boost::signals2::signal NotifyTransactionChanged; }; -/** A key allocated from the key pool. */ -class CReserveKey -{ -protected: - CWallet* pwallet; - int64 nIndex; - CPubKey vchPubKey; -public: - CReserveKey(CWallet* pwalletIn) - { - nIndex = -1; - pwallet = pwalletIn; - } - - ~CReserveKey() - { - ReturnKey(); - } - - void ReturnKey(); - bool GetReservedKey(CPubKey &pubkey); - void KeepKey(); -}; - typedef std::map mapValue_t; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index f5b6dee6..2d989aa5 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -11,8 +11,6 @@ using namespace std; using namespace boost; -static uint64 nAccountingEntryNumber = 0; - // // CWalletDB //